lazy cpp_function and capsule.

This commit is contained in:
ykiko 2024-09-22 19:33:58 +08:00
parent e1d52653bf
commit bf8b91b9f8
5 changed files with 68 additions and 97 deletions

View File

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

View File

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

View File

@ -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 () & {

View File

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

View File

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