mirror of
https://github.com/pocketpy/pocketpy
synced 2025-11-04 18:50:16 +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
|
} // namespace impl
|
||||||
|
|
||||||
class cpp_function : public function {
|
class cpp_function : public function {
|
||||||
inline static py_Type m_type = 0;
|
|
||||||
|
|
||||||
PKBIND_TYPE_IMPL(function, cpp_function, tp_function);
|
PKBIND_TYPE_IMPL(function, cpp_function, tp_function);
|
||||||
|
|
||||||
static void register_() {
|
inline static lazy<py_Type> tp_function_record = +[](py_Type& type) {
|
||||||
m_type = py_newtype("function_record", tp_object, nullptr, [](void* data) {
|
type = py_newtype("function_record", tp_object, nullptr, [](void* data) {
|
||||||
static_cast<impl::function_record*>(data)->~function_record();
|
static_cast<impl::function_record*>(data)->~function_record();
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
static bool is_function_record(handle h) {
|
static bool is_function_record(handle h) {
|
||||||
if(isinstance<function>(h)) {
|
if(isinstance<function>(h)) {
|
||||||
auto slot = py_getslot(h.ptr(), 0);
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
@ -539,47 +537,42 @@ class cpp_function : public function {
|
|||||||
// bind the function
|
// bind the function
|
||||||
std::string sig = name;
|
std::string sig = name;
|
||||||
sig += is_method ? "(self, *args, **kwargs)" : "(*args, **kwargs)";
|
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);
|
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...);
|
new (data) impl::function_record(std::forward<Fn>(fn), extras...);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Fn, typename... Extras>
|
private:
|
||||||
cpp_function(Fn&& fn, const Extras&... extras) :
|
static bool call(int argc, py_Ref stack) {
|
||||||
cpp_function("lambda", std::forward<Fn>(fn), extras...) {}
|
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 {
|
class property : public object {
|
||||||
|
|||||||
@ -6,6 +6,7 @@
|
|||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
|
#include <optional>
|
||||||
#include <typeindex>
|
#include <typeindex>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
@ -17,27 +18,6 @@ namespace pkbind {
|
|||||||
|
|
||||||
class handle;
|
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 {
|
struct retv_t {
|
||||||
py_Ref value;
|
py_Ref value;
|
||||||
|
|
||||||
@ -140,8 +120,28 @@ struct action {
|
|||||||
static void register_start(function func) { starts.push_back(func); }
|
static void register_start(function func) { starts.push_back(func); }
|
||||||
};
|
};
|
||||||
|
|
||||||
template <int N>
|
template <typename T>
|
||||||
inline reg_t<N> reg;
|
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;
|
inline retv_t retv;
|
||||||
|
|
||||||
|
|||||||
@ -281,17 +281,6 @@ T borrow(handle h) {
|
|||||||
return T(h, object::realloc_t{});
|
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 void retv_t::operator= (handle h) & { py_assign(value, h.ptr()); }
|
||||||
|
|
||||||
inline retv_t::operator handle () & {
|
inline retv_t::operator handle () & {
|
||||||
|
|||||||
@ -330,24 +330,22 @@ class kwargs : public dict {
|
|||||||
|
|
||||||
// TODO:
|
// TODO:
|
||||||
class capsule : public object {
|
class capsule : public object {
|
||||||
|
PKBIND_TYPE_IMPL(object, capsule, *tp_capsule);
|
||||||
|
|
||||||
struct capsule_impl {
|
struct capsule_impl {
|
||||||
void* data;
|
void* data;
|
||||||
void (*destructor)(void*);
|
void (*destructor)(void*);
|
||||||
};
|
};
|
||||||
|
|
||||||
inline static py_Type m_type = 0;
|
inline static lazy<py_Type> tp_capsule = +[](py_Type& type) {
|
||||||
|
type = py_newtype("capsule", tp_object, nullptr, [](void* data) {
|
||||||
PKBIND_TYPE_IMPL(object, capsule, m_type);
|
|
||||||
|
|
||||||
static void register_() {
|
|
||||||
m_type = py_newtype("capsule", tp_object, nullptr, [](void* data) {
|
|
||||||
auto impl = static_cast<capsule_impl*>(data);
|
auto impl = static_cast<capsule_impl*>(data);
|
||||||
if(impl->data && impl->destructor) { impl->destructor(impl->data); }
|
if(impl->data && impl->destructor) { impl->destructor(impl->data); }
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
capsule(void* data, void (*destructor)(void*) = nullptr) : object(alloc_t{}) {
|
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};
|
new (impl) capsule_impl{data, destructor};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,6 +1,8 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "internal/class.h"
|
#include "internal/class.h"
|
||||||
|
#include "internal/function.h"
|
||||||
|
#include "internal/types.h"
|
||||||
|
|
||||||
namespace pkbind {
|
namespace pkbind {
|
||||||
|
|
||||||
@ -14,15 +16,6 @@ inline bool initialized = false;
|
|||||||
inline void initialize(int object_pool_size = 1024) {
|
inline void initialize(int object_pool_size = 1024) {
|
||||||
if(!initialized) { py_initialize(); }
|
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.
|
// initialize ret.
|
||||||
retv.value = py_retval();
|
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>();
|
m_type_map = new std::unordered_map<std::type_index, py_Type>();
|
||||||
|
|
||||||
// register types.
|
|
||||||
capsule::register_();
|
|
||||||
cpp_function::register_();
|
|
||||||
|
|
||||||
action::initialize();
|
action::initialize();
|
||||||
initialized = true;
|
initialized = true;
|
||||||
}
|
}
|
||||||
@ -46,6 +35,8 @@ inline void finalize(bool test = false) {
|
|||||||
m_type_map = nullptr;
|
m_type_map = nullptr;
|
||||||
object_pool::finalize();
|
object_pool::finalize();
|
||||||
if(test) {
|
if(test) {
|
||||||
|
capsule::tp_capsule.reset();
|
||||||
|
cpp_function::tp_function_record.reset();
|
||||||
py_resetvm();
|
py_resetvm();
|
||||||
} else {
|
} else {
|
||||||
py_finalize();
|
py_finalize();
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user