add pkpy::any

This commit is contained in:
blueloveTH 2024-05-08 14:45:42 +08:00
parent 530fc49d60
commit 4a1cf10e74
11 changed files with 121 additions and 46 deletions

View File

@ -6,7 +6,7 @@ with open("include/pocketpy/opcodes.h", "rt", encoding='utf-8') as f:
OPCODES_TEXT = '\n' + f.read() + '\n' OPCODES_TEXT = '\n' + f.read() + '\n'
pipeline = [ 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"], ["obj.h", "dict.h", "codeobject.h", "frame.h", "profiler.h"],
["gc.h", "vm.h", "ceval.h", "lexer.h", "expr.h", "compiler.h", "repl.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"], ["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
View 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

View File

@ -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
View 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

View File

@ -2,6 +2,7 @@
#include "obj.h" #include "obj.h"
#include "error.h" #include "error.h"
#include "any.h"
namespace pkpy{ namespace pkpy{
@ -120,27 +121,6 @@ struct FuncDecl {
void _gc_mark() const; 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 { struct NativeFunc {
NativeFuncC f; NativeFuncC f;
@ -152,12 +132,11 @@ struct NativeFunc {
UserData _userdata; UserData _userdata;
void set_userdata(UserData data) { void set_userdata(UserData&& data) {
if(!_userdata.empty && !data.empty){ if(_userdata){
// override is not supported throw std::runtime_error("NativeFunc userdata already set");
throw std::runtime_error("userdata already set");
} }
_userdata = data; _userdata = std::move(data);
} }
NativeFunc(NativeFuncC f, int argc): f(f), argc(argc) {} NativeFunc(NativeFuncC f, int argc): f(f), argc(argc) {}
@ -205,9 +184,14 @@ struct Py_<NativeFunc> final: PyObject {
}; };
template<typename T> template<typename T>
T lambda_get_userdata(PyObject** p){ T& lambda_get_userdata(PyObject** p){
if(p[-1] != PY_NULL) return PK_OBJ_GET(NativeFunc, p[-1])._userdata.get<T>(); static_assert(std::is_same_v<T, std::decay_t<T>>);
else return PK_OBJ_GET(NativeFunc, p[-2])._userdata.get<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 } // namespace pkpy

View File

@ -128,11 +128,12 @@ struct Type {
struct PyObject; struct PyObject;
#define PK_BITS(p) (reinterpret_cast<i64>(p)) #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> template<typename T>
struct is_pod { inline constexpr bool is_pod_v = std::is_trivially_copyable_v<T> && std::is_standard_layout_v<T>;
static constexpr bool value = 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) \ #define PK_ALWAYS_PASS_BY_POINTER(T) \
T(const T&) = delete; \ T(const T&) = delete; \

View File

@ -19,7 +19,7 @@ constexpr T default_invalid_value(){
template<typename V> template<typename V>
struct SmallNameDict{ struct SmallNameDict{
using K = StrName; using K = StrName;
static_assert(is_pod<V>::value); static_assert(is_pod_v<V>);
bool _is_small; bool _is_small;
uint16_t _size; uint16_t _size;
@ -103,7 +103,7 @@ struct LargeNameDict {
using Item = NameDictItem<T>; using Item = NameDictItem<T>;
static constexpr uint16_t kInitialCapacity = 32; static constexpr uint16_t kInitialCapacity = 32;
static_assert(is_pod<T>::value); static_assert(is_pod_v<T>);
bool _is_small; bool _is_small;
float _load_factor; float _load_factor;

View File

@ -11,7 +11,7 @@ struct pod_vector{
static constexpr int N = 64 / SizeT; static constexpr int N = 64 / SizeT;
// static_assert(64 % SizeT == 0); // static_assert(64 % SizeT == 0);
static_assert(is_pod<T>::value); static_assert(is_pod_v<T>);
static_assert(N >= 4); static_assert(N >= 4);
int _size; int _size;

View File

@ -308,7 +308,7 @@ public:
#if PK_REGION("General Bindings") #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(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){ 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); PyObject* bind_property(PyObject*, const char*, NativeFuncC fget, NativeFuncC fset=nullptr);
template<typename T, typename F, bool ReadOnly=false> template<typename T, typename F, bool ReadOnly=false>

19
src/any.cpp Normal file
View 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

View File

@ -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* VM::bind_func(PyObject* obj, StrName name, int argc, NativeFuncC fn, UserData userdata, BindType bt) {
PyObject* nf = VAR(NativeFunc(fn, argc)); 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){ switch(bt){
case BindType::DEFAULT: break; case BindType::DEFAULT: break;
case BindType::STATICMETHOD: nf = VAR(StaticMethod(nf)); 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){ 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){ 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]; FuncDecl_ decl = co->func_decls[0];
decl->docstring = docstring; decl->docstring = docstring;
PyObject* f_obj = VAR(NativeFunc(fn, decl)); 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){ switch(bt){
case BindType::STATICMETHOD: case BindType::STATICMETHOD: