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'
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
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 "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

View File

@ -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; \

View File

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

View File

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

View File

@ -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
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* 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: