mirror of
https://github.com/pocketpy/pocketpy
synced 2025-11-01 17:30:18 +00:00
lazy cpp_function and capsule.
This commit is contained in:
parent
e1d52653bf
commit
bf8b91b9f8
@ -515,20 +515,18 @@ struct template_parser<Callable,
|
||||
} // namespace impl
|
||||
|
||||
class cpp_function : public function {
|
||||
inline static py_Type m_type = 0;
|
||||
|
||||
PKBIND_TYPE_IMPL(function, cpp_function, tp_function);
|
||||
|
||||
static void register_() {
|
||||
m_type = py_newtype("function_record", tp_object, nullptr, [](void* data) {
|
||||
inline static lazy<py_Type> tp_function_record = +[](py_Type& type) {
|
||||
type = py_newtype("function_record", tp_object, nullptr, [](void* data) {
|
||||
static_cast<impl::function_record*>(data)->~function_record();
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
static bool is_function_record(handle h) {
|
||||
if(isinstance<function>(h)) {
|
||||
auto slot = py_getslot(h.ptr(), 0);
|
||||
if(slot) { return py_typeof(slot) == m_type; }
|
||||
if(slot) { return py_typeof(slot) == tp_function_record; }
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@ -539,47 +537,42 @@ class cpp_function : public function {
|
||||
// bind the function
|
||||
std::string sig = name;
|
||||
sig += is_method ? "(self, *args, **kwargs)" : "(*args, **kwargs)";
|
||||
auto call = [](int argc, py_Ref stack) {
|
||||
handle func = py_inspect_currentfunction();
|
||||
auto data = py_touserdata(py_getslot(func.ptr(), 0));
|
||||
auto& record = *static_cast<impl::function_record*>(data);
|
||||
try {
|
||||
record(argc, stack);
|
||||
return true;
|
||||
} catch(std::domain_error& e) {
|
||||
py_exception(tp_ValueError, e.what());
|
||||
} catch(std::invalid_argument& e) {
|
||||
py_exception(tp_ValueError, e.what());
|
||||
} catch(std::length_error& e) {
|
||||
py_exception(tp_ValueError, e.what());
|
||||
} catch(std::out_of_range& e) {
|
||||
py_exception(tp_IndexError, e.what());
|
||||
} catch(std::range_error& e) {
|
||||
py_exception(tp_ValueError, e.what());
|
||||
} catch(stop_iteration&) { StopIteration(); } catch(index_error& e) {
|
||||
py_exception(tp_IndexError, e.what());
|
||||
} catch(key_error& e) { py_exception(tp_KeyError, e.what()); } catch(value_error& e) {
|
||||
py_exception(tp_ValueError, e.what());
|
||||
} catch(type_error& e) {
|
||||
py_exception(tp_TypeError, e.what());
|
||||
} catch(import_error& e) {
|
||||
py_exception(tp_ImportError, e.what());
|
||||
} catch(attribute_error& e) {
|
||||
py_exception(tp_AttributeError, e.what());
|
||||
} catch(std::exception& e) { py_exception(tp_RuntimeError, e.what()); }
|
||||
return false;
|
||||
};
|
||||
py_newfunction(m_ptr, sig.c_str(), call, nullptr, 1);
|
||||
|
||||
assert(m_type != 0 && "function record type not registered");
|
||||
py_newfunction(m_ptr, sig.c_str(), call, nullptr, 1);
|
||||
auto slot = py_getslot(m_ptr, 0);
|
||||
void* data = py_newobject(slot, m_type, 0, sizeof(impl::function_record));
|
||||
void* data = py_newobject(slot, tp_function_record, 0, sizeof(impl::function_record));
|
||||
new (data) impl::function_record(std::forward<Fn>(fn), extras...);
|
||||
}
|
||||
|
||||
template <typename Fn, typename... Extras>
|
||||
cpp_function(Fn&& fn, const Extras&... extras) :
|
||||
cpp_function("lambda", std::forward<Fn>(fn), extras...) {}
|
||||
private:
|
||||
static bool call(int argc, py_Ref stack) {
|
||||
handle func = py_inspect_currentfunction();
|
||||
auto data = py_touserdata(py_getslot(func.ptr(), 0));
|
||||
auto& record = *static_cast<impl::function_record*>(data);
|
||||
try {
|
||||
record(argc, stack);
|
||||
return true;
|
||||
} catch(std::domain_error& e) {
|
||||
py_exception(tp_ValueError, e.what());
|
||||
} catch(std::invalid_argument& e) {
|
||||
py_exception(tp_ValueError, e.what());
|
||||
} catch(std::length_error& e) {
|
||||
py_exception(tp_ValueError, e.what());
|
||||
} catch(std::out_of_range& e) {
|
||||
py_exception(tp_IndexError, e.what());
|
||||
} catch(std::range_error& e) {
|
||||
py_exception(tp_ValueError, e.what());
|
||||
} catch(stop_iteration&) { StopIteration(); } catch(index_error& e) {
|
||||
py_exception(tp_IndexError, e.what());
|
||||
} catch(key_error& e) { py_exception(tp_KeyError, e.what()); } catch(value_error& e) {
|
||||
py_exception(tp_ValueError, e.what());
|
||||
} catch(type_error& e) { py_exception(tp_TypeError, e.what()); } catch(import_error& e) {
|
||||
py_exception(tp_ImportError, e.what());
|
||||
} catch(attribute_error& e) {
|
||||
py_exception(tp_AttributeError, e.what());
|
||||
} catch(std::exception& e) { py_exception(tp_RuntimeError, e.what()); }
|
||||
return false;
|
||||
};
|
||||
};
|
||||
|
||||
class property : public object {
|
||||
|
||||
@ -6,6 +6,7 @@
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <cassert>
|
||||
#include <optional>
|
||||
#include <typeindex>
|
||||
#include <stdexcept>
|
||||
#include <unordered_map>
|
||||
@ -17,27 +18,6 @@ namespace pkbind {
|
||||
|
||||
class handle;
|
||||
|
||||
/// hold the object temporarily
|
||||
template <int N>
|
||||
struct reg_t {
|
||||
py_Ref value;
|
||||
|
||||
void operator= (py_Ref ref) & { py_setreg(N, ref); }
|
||||
|
||||
operator py_Ref () & {
|
||||
assert(value && "register is not initialized");
|
||||
return value;
|
||||
}
|
||||
|
||||
void operator= (handle value) &;
|
||||
|
||||
operator handle () &;
|
||||
|
||||
// pkpy provide user 8 registers.
|
||||
// 8th register is used for object pool, so N is limited to [0, 7).
|
||||
static_assert(N >= 0 && N <= 6, "N must be in [0, 7)");
|
||||
};
|
||||
|
||||
struct retv_t {
|
||||
py_Ref value;
|
||||
|
||||
@ -140,8 +120,28 @@ struct action {
|
||||
static void register_start(function func) { starts.push_back(func); }
|
||||
};
|
||||
|
||||
template <int N>
|
||||
inline reg_t<N> reg;
|
||||
template <typename T>
|
||||
class lazy {
|
||||
public:
|
||||
lazy(void (*init)(T&)) : init(init) {}
|
||||
|
||||
operator T& () {
|
||||
if(!initialized) {
|
||||
if(init) { init(value); }
|
||||
initialized = true;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
T& operator* () { return static_cast<T&>(*this); }
|
||||
|
||||
void reset() { initialized = false; }
|
||||
|
||||
private:
|
||||
T value;
|
||||
bool initialized = false;
|
||||
void (*init)(T&) = nullptr;
|
||||
};
|
||||
|
||||
inline retv_t retv;
|
||||
|
||||
|
||||
@ -281,17 +281,6 @@ T borrow(handle h) {
|
||||
return T(h, object::realloc_t{});
|
||||
}
|
||||
|
||||
template <int N>
|
||||
void reg_t<N>::operator= (handle h) & {
|
||||
py_setreg(N, h.ptr());
|
||||
}
|
||||
|
||||
template <int N>
|
||||
reg_t<N>::operator handle () & {
|
||||
assert(value && "register is not initialized");
|
||||
return value;
|
||||
}
|
||||
|
||||
inline void retv_t::operator= (handle h) & { py_assign(value, h.ptr()); }
|
||||
|
||||
inline retv_t::operator handle () & {
|
||||
|
||||
@ -330,24 +330,22 @@ class kwargs : public dict {
|
||||
|
||||
// TODO:
|
||||
class capsule : public object {
|
||||
PKBIND_TYPE_IMPL(object, capsule, *tp_capsule);
|
||||
|
||||
struct capsule_impl {
|
||||
void* data;
|
||||
void (*destructor)(void*);
|
||||
};
|
||||
|
||||
inline static py_Type m_type = 0;
|
||||
|
||||
PKBIND_TYPE_IMPL(object, capsule, m_type);
|
||||
|
||||
static void register_() {
|
||||
m_type = py_newtype("capsule", tp_object, nullptr, [](void* data) {
|
||||
inline static lazy<py_Type> tp_capsule = +[](py_Type& type) {
|
||||
type = py_newtype("capsule", tp_object, nullptr, [](void* data) {
|
||||
auto impl = static_cast<capsule_impl*>(data);
|
||||
if(impl->data && impl->destructor) { impl->destructor(impl->data); }
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
capsule(void* data, void (*destructor)(void*) = nullptr) : object(alloc_t{}) {
|
||||
void* impl = py_newobject(m_ptr, m_type, 0, sizeof(capsule_impl));
|
||||
void* impl = py_newobject(m_ptr, tp_capsule, 0, sizeof(capsule_impl));
|
||||
new (impl) capsule_impl{data, destructor};
|
||||
}
|
||||
|
||||
|
||||
@ -1,6 +1,8 @@
|
||||
#pragma once
|
||||
|
||||
#include "internal/class.h"
|
||||
#include "internal/function.h"
|
||||
#include "internal/types.h"
|
||||
|
||||
namespace pkbind {
|
||||
|
||||
@ -14,15 +16,6 @@ inline bool initialized = false;
|
||||
inline void initialize(int object_pool_size = 1024) {
|
||||
if(!initialized) { py_initialize(); }
|
||||
|
||||
// initialize all registers.
|
||||
reg<0>.value = py_getreg(0);
|
||||
reg<1>.value = py_getreg(1);
|
||||
reg<2>.value = py_getreg(2);
|
||||
reg<3>.value = py_getreg(3);
|
||||
reg<4>.value = py_getreg(4);
|
||||
reg<5>.value = py_getreg(5);
|
||||
reg<6>.value = py_getreg(6);
|
||||
|
||||
// initialize ret.
|
||||
retv.value = py_retval();
|
||||
|
||||
@ -31,10 +24,6 @@ inline void initialize(int object_pool_size = 1024) {
|
||||
|
||||
m_type_map = new std::unordered_map<std::type_index, py_Type>();
|
||||
|
||||
// register types.
|
||||
capsule::register_();
|
||||
cpp_function::register_();
|
||||
|
||||
action::initialize();
|
||||
initialized = true;
|
||||
}
|
||||
@ -46,6 +35,8 @@ inline void finalize(bool test = false) {
|
||||
m_type_map = nullptr;
|
||||
object_pool::finalize();
|
||||
if(test) {
|
||||
capsule::tp_capsule.reset();
|
||||
cpp_function::tp_function_record.reset();
|
||||
py_resetvm();
|
||||
} else {
|
||||
py_finalize();
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user