mirror of
https://github.com/pocketpy/pocketpy
synced 2025-10-19 19:10:17 +00:00
add pkpy::any
This commit is contained in:
parent
530fc49d60
commit
4a1cf10e74
@ -6,7 +6,7 @@ with open("include/pocketpy/opcodes.h", "rt", encoding='utf-8') as f:
|
||||
OPCODES_TEXT = '\n' + f.read() + '\n'
|
||||
|
||||
pipeline = [
|
||||
["config.h", "export.h", "_generated.h", "common.h", "memory.h", "vector.h", "str.h", "tuplelist.h", "namedict.h", "error.h"],
|
||||
["config.h", "export.h", "_generated.h", "common.h", "memory.h", "any.h", "vector.h", "str.h", "tuplelist.h", "namedict.h", "error.h"],
|
||||
["obj.h", "dict.h", "codeobject.h", "frame.h", "profiler.h"],
|
||||
["gc.h", "vm.h", "ceval.h", "lexer.h", "expr.h", "compiler.h", "repl.h"],
|
||||
["cffi.h", "bindings.h", "iter.h", "base64.h", "csv.h", "collections.h", "array2d.h", "dataclasses.h", "random.h", "linalg.h", "easing.h", "io.h", "modules.h"],
|
||||
|
5
build_g.sh
Normal file
5
build_g.sh
Normal file
@ -0,0 +1,5 @@
|
||||
SRC=$(find src/ -name "*.cpp")
|
||||
|
||||
FLAGS="-std=c++17 -O1 -stdlib=libc++ -Iinclude -frtti -Wfatal-errors -g"
|
||||
|
||||
clang++ $FLAGS -o main -O1 src2/main.cpp $SRC
|
@ -1,5 +0,0 @@
|
||||
SRC=$(find src/ -name "*.cpp")
|
||||
|
||||
FLAGS="-std=c++17 -O1 -stdlib=libc++ -Iinclude -frtti -W -Wno-unused-parameter -Wno-sign-compare"
|
||||
|
||||
clang++ $FLAGS -o main -O1 src2/main.cpp $SRC
|
71
include/pocketpy/any.h
Normal file
71
include/pocketpy/any.h
Normal file
@ -0,0 +1,71 @@
|
||||
#pragma once
|
||||
|
||||
#include "common.h"
|
||||
|
||||
namespace pkpy {
|
||||
|
||||
struct any{
|
||||
struct vtable{
|
||||
const std::type_index type;
|
||||
void (*deleter)(void*);
|
||||
|
||||
template<typename T>
|
||||
inline static vtable* get(){
|
||||
static_assert(std::is_same_v<T, std::decay_t<T>>);
|
||||
if constexpr (is_sso_v<T>){
|
||||
static vtable vt{ typeid(T), [](void*){} };
|
||||
return &vt;
|
||||
}else{
|
||||
static vtable vt{ typeid(T), [](void* ptr){ delete static_cast<T*>(ptr); } };
|
||||
return &vt;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
void* data;
|
||||
vtable* _vt;
|
||||
|
||||
any() : data(nullptr), _vt(nullptr) {}
|
||||
|
||||
explicit operator bool() const { return data != nullptr; }
|
||||
|
||||
template<typename T>
|
||||
any(T&& value){
|
||||
using U = std::decay_t<T>;
|
||||
static_assert(!std::is_same_v<U, any>, "any(const any&) is deleted");
|
||||
if constexpr (is_sso_v<U>){
|
||||
memcpy(&data, &value, sizeof(U));
|
||||
}else{
|
||||
data = new U(std::forward<T>(value));
|
||||
}
|
||||
_vt = vtable::get<U>();
|
||||
}
|
||||
|
||||
any(any&& other) noexcept;
|
||||
any& operator=(any&& other) noexcept;
|
||||
|
||||
const std::type_index type_id() const{
|
||||
return _vt ? _vt->type : typeid(void);
|
||||
}
|
||||
|
||||
any(const any& other) = delete;
|
||||
any& operator=(const any& other) = delete;
|
||||
|
||||
~any() { if(data) _vt->deleter(data); }
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
bool any_cast(const any& a, T** out){
|
||||
static_assert(std::is_same_v<T, std::decay_t<T>>);
|
||||
if(a.type_id() != typeid(T)) return false;
|
||||
if constexpr (is_sso_v<T>){
|
||||
*out = (T*)(&a.data);
|
||||
}else{
|
||||
*out = static_cast<T*>(a.data);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
using UserData = any;
|
||||
|
||||
} // namespace pkpy
|
@ -2,6 +2,7 @@
|
||||
|
||||
#include "obj.h"
|
||||
#include "error.h"
|
||||
#include "any.h"
|
||||
|
||||
namespace pkpy{
|
||||
|
||||
@ -120,27 +121,6 @@ struct FuncDecl {
|
||||
void _gc_mark() const;
|
||||
};
|
||||
|
||||
struct UserData{
|
||||
char data[12];
|
||||
bool empty;
|
||||
|
||||
UserData(): empty(true) {}
|
||||
template<typename T>
|
||||
UserData(T t): empty(false){
|
||||
static_assert(std::is_trivially_copyable_v<T>);
|
||||
static_assert(sizeof(T) <= sizeof(data));
|
||||
memcpy(data, &t, sizeof(T));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T get() const{
|
||||
static_assert(std::is_trivially_copyable_v<T>);
|
||||
static_assert(sizeof(T) <= sizeof(data));
|
||||
PK_DEBUG_ASSERT(!empty);
|
||||
return reinterpret_cast<const T&>(data);
|
||||
}
|
||||
};
|
||||
|
||||
struct NativeFunc {
|
||||
NativeFuncC f;
|
||||
|
||||
@ -152,12 +132,11 @@ struct NativeFunc {
|
||||
|
||||
UserData _userdata;
|
||||
|
||||
void set_userdata(UserData data) {
|
||||
if(!_userdata.empty && !data.empty){
|
||||
// override is not supported
|
||||
throw std::runtime_error("userdata already set");
|
||||
void set_userdata(UserData&& data) {
|
||||
if(_userdata){
|
||||
throw std::runtime_error("NativeFunc userdata already set");
|
||||
}
|
||||
_userdata = data;
|
||||
_userdata = std::move(data);
|
||||
}
|
||||
|
||||
NativeFunc(NativeFuncC f, int argc): f(f), argc(argc) {}
|
||||
@ -205,9 +184,14 @@ struct Py_<NativeFunc> final: PyObject {
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
T lambda_get_userdata(PyObject** p){
|
||||
if(p[-1] != PY_NULL) return PK_OBJ_GET(NativeFunc, p[-1])._userdata.get<T>();
|
||||
else return PK_OBJ_GET(NativeFunc, p[-2])._userdata.get<T>();
|
||||
T& lambda_get_userdata(PyObject** p){
|
||||
static_assert(std::is_same_v<T, std::decay_t<T>>);
|
||||
UserData* ud;
|
||||
if(p[-1] != PY_NULL) ud = &PK_OBJ_GET(NativeFunc, p[-1])._userdata;
|
||||
else ud = &PK_OBJ_GET(NativeFunc, p[-2])._userdata;
|
||||
T* out;
|
||||
if(!any_cast(*ud, &out)) throw std::runtime_error("lambda_get_userdata: any_cast failed");
|
||||
return *out;
|
||||
}
|
||||
|
||||
} // namespace pkpy
|
@ -128,11 +128,12 @@ struct Type {
|
||||
struct PyObject;
|
||||
#define PK_BITS(p) (reinterpret_cast<i64>(p))
|
||||
|
||||
// is_pod<> for c++17 and c++20
|
||||
// is_pod_v<> for c++17 and c++20
|
||||
template<typename T>
|
||||
struct is_pod {
|
||||
static constexpr bool value = std::is_trivially_copyable_v<T> && std::is_standard_layout_v<T>;
|
||||
};
|
||||
inline constexpr bool is_pod_v = std::is_trivially_copyable_v<T> && std::is_standard_layout_v<T>;
|
||||
|
||||
template<typename T>
|
||||
inline constexpr bool is_sso_v = is_pod_v<T> && sizeof(T) <= sizeof(void*);
|
||||
|
||||
#define PK_ALWAYS_PASS_BY_POINTER(T) \
|
||||
T(const T&) = delete; \
|
||||
|
@ -19,7 +19,7 @@ constexpr T default_invalid_value(){
|
||||
template<typename V>
|
||||
struct SmallNameDict{
|
||||
using K = StrName;
|
||||
static_assert(is_pod<V>::value);
|
||||
static_assert(is_pod_v<V>);
|
||||
|
||||
bool _is_small;
|
||||
uint16_t _size;
|
||||
@ -103,7 +103,7 @@ struct LargeNameDict {
|
||||
|
||||
using Item = NameDictItem<T>;
|
||||
static constexpr uint16_t kInitialCapacity = 32;
|
||||
static_assert(is_pod<T>::value);
|
||||
static_assert(is_pod_v<T>);
|
||||
|
||||
bool _is_small;
|
||||
float _load_factor;
|
||||
|
@ -11,7 +11,7 @@ struct pod_vector{
|
||||
static constexpr int N = 64 / SizeT;
|
||||
|
||||
// static_assert(64 % SizeT == 0);
|
||||
static_assert(is_pod<T>::value);
|
||||
static_assert(is_pod_v<T>);
|
||||
static_assert(N >= 4);
|
||||
|
||||
int _size;
|
||||
|
@ -308,7 +308,7 @@ public:
|
||||
#if PK_REGION("General Bindings")
|
||||
PyObject* bind_func(PyObject* obj, StrName name, int argc, NativeFuncC fn, UserData userdata={}, BindType bt=BindType::DEFAULT);
|
||||
PyObject* bind_func(Type type, StrName name, int argc, NativeFuncC fn, UserData userdata={}, BindType bt=BindType::DEFAULT){
|
||||
return bind_func(_t(type), name, argc, fn, userdata, bt);
|
||||
return bind_func(_t(type), name, argc, fn, std::move(userdata), bt);
|
||||
}
|
||||
PyObject* bind_property(PyObject*, const char*, NativeFuncC fget, NativeFuncC fset=nullptr);
|
||||
template<typename T, typename F, bool ReadOnly=false>
|
||||
|
19
src/any.cpp
Normal file
19
src/any.cpp
Normal file
@ -0,0 +1,19 @@
|
||||
#include "pocketpy/any.h"
|
||||
|
||||
namespace pkpy{
|
||||
|
||||
any::any(any&& other) noexcept: data(other.data), _vt(other._vt){
|
||||
other.data = nullptr;
|
||||
other._vt = nullptr;
|
||||
}
|
||||
|
||||
any& any::operator=(any&& other) noexcept{
|
||||
if(data) _vt->deleter(data);
|
||||
data = other.data;
|
||||
_vt = other._vt;
|
||||
other.data = nullptr;
|
||||
other._vt = nullptr;
|
||||
return *this;
|
||||
}
|
||||
|
||||
} // namespace pkpy
|
@ -1229,7 +1229,7 @@ void VM::setattr(PyObject* obj, StrName name, PyObject* value){
|
||||
|
||||
PyObject* VM::bind_func(PyObject* obj, StrName name, int argc, NativeFuncC fn, UserData userdata, BindType bt) {
|
||||
PyObject* nf = VAR(NativeFunc(fn, argc));
|
||||
PK_OBJ_GET(NativeFunc, nf).set_userdata(userdata);
|
||||
PK_OBJ_GET(NativeFunc, nf).set_userdata(std::move(userdata));
|
||||
switch(bt){
|
||||
case BindType::DEFAULT: break;
|
||||
case BindType::STATICMETHOD: nf = VAR(StaticMethod(nf)); break;
|
||||
@ -1240,7 +1240,7 @@ PyObject* VM::bind_func(PyObject* obj, StrName name, int argc, NativeFuncC fn, U
|
||||
}
|
||||
|
||||
PyObject* VM::bind(PyObject* obj, const char* sig, NativeFuncC fn, UserData userdata, BindType bt){
|
||||
return bind(obj, sig, nullptr, fn, userdata, bt);
|
||||
return bind(obj, sig, nullptr, fn, std::move(userdata), bt);
|
||||
}
|
||||
|
||||
PyObject* VM::bind(PyObject* obj, const char* sig, const char* docstring, NativeFuncC fn, UserData userdata, BindType bt){
|
||||
@ -1257,7 +1257,7 @@ PyObject* VM::bind(PyObject* obj, const char* sig, const char* docstring, Native
|
||||
FuncDecl_ decl = co->func_decls[0];
|
||||
decl->docstring = docstring;
|
||||
PyObject* f_obj = VAR(NativeFunc(fn, decl));
|
||||
PK_OBJ_GET(NativeFunc, f_obj).set_userdata(userdata);
|
||||
PK_OBJ_GET(NativeFunc, f_obj).set_userdata(std::move(userdata));
|
||||
|
||||
switch(bt){
|
||||
case BindType::STATICMETHOD:
|
||||
|
Loading…
x
Reference in New Issue
Block a user