| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358 |
- #pragma once
- #include "cast.h"
- #include <bitset>
- namespace pybind11 {
- template <std::size_t Nurse, std::size_t... Patients>
- struct keep_alive {};
- template <typename T>
- struct call_guard {
- static_assert(std::is_default_constructible_v<T>, "call_guard must be default constructible");
- };
- // append the overload to the beginning of the overload list
- struct prepend {};
- template <typename... Args>
- struct init {};
- // TODO: support more customized tags
- // struct kw_only {};
- //
- // struct pos_only {};
- //
- // struct default_arg {};
- //
- // struct arg {
- // const char* name;
- // const char* description;
- // };
- //
- // struct default_arg {
- // const char* name;
- // const char* description;
- // const char* value;
- // };
- template <typename Fn,
- typename Extra,
- typename Args = callable_args_t<std::decay_t<Fn>>,
- typename IndexSequence = std::make_index_sequence<std::tuple_size_v<Args>>>
- struct generator;
- class function_record {
- union {
- void* data;
- char buffer[16];
- };
- // TODO: optimize the function_record size to reduce memory usage
- const char* name;
- function_record* next;
- void (*destructor)(function_record*);
- return_value_policy policy = return_value_policy::automatic;
- handle (*wrapper)(function_record&, pkpy::ArgsView, bool convert, handle parent);
- template <typename Fn, typename Extra, typename Args, typename IndexSequence>
- friend struct generator;
- public:
- template <typename Fn, typename... Extras>
- function_record(Fn&& f, const char* name, const Extras&... extras) : name(name), next(nullptr) {
- if constexpr(sizeof(f) <= sizeof(buffer)) {
- new (buffer) auto(std::forward<Fn>(f));
- destructor = [](function_record* self) {
- reinterpret_cast<Fn*>(self->buffer)->~Fn();
- };
- } else {
- data = new auto(std::forward<Fn>(f));
- destructor = [](function_record* self) {
- delete static_cast<Fn*>(self->data);
- };
- }
- using Generator = generator<std::decay_t<Fn>, std::tuple<Extras...>>;
- Generator::initialize(*this, extras...);
- wrapper = Generator::generate();
- }
- ~function_record() { destructor(this); }
- template <typename Fn>
- auto& cast() {
- if constexpr(sizeof(Fn) <= sizeof(buffer)) {
- return *reinterpret_cast<Fn*>(buffer);
- } else {
- return *static_cast<Fn*>(data);
- }
- }
- void append(function_record* record) {
- function_record* p = this;
- while(p->next != nullptr) {
- p = p->next;
- }
- p->next = record;
- }
- handle operator() (pkpy::ArgsView view) {
- function_record* p = this;
- // foreach function record and call the function with not convert
- while(p != nullptr) {
- handle result = p->wrapper(*this, view, false, {});
- if(result) { return result; }
- p = p->next;
- }
- p = this;
- // foreach function record and call the function with convert
- while(p != nullptr) {
- handle result = p->wrapper(*this, view, true, {});
- if(result) { return result; }
- p = p->next;
- }
- vm->TypeError("no matching function found");
- }
- };
- template <typename Fn, std::size_t... Is, typename... Args>
- handle invoke(Fn&& fn,
- std::index_sequence<Is...>,
- std::tuple<type_caster<Args>...>& casters,
- return_value_policy policy,
- handle parent) {
- using underlying_type = std::decay_t<Fn>;
- using ret = callable_return_t<underlying_type>;
- // if the return type is void, return None
- if constexpr(std::is_void_v<ret>) {
- // resolve the member function pointer
- if constexpr(std::is_member_function_pointer_v<underlying_type>) {
- [&](class_type_t<underlying_type>& self, auto&... args) {
- (self.*fn)(args...);
- }(std::get<Is>(casters).value...);
- } else {
- fn(std::get<Is>(casters).value...);
- }
- return vm->None;
- } else {
- // resolve the member function pointer
- if constexpr(std::is_member_function_pointer_v<remove_cvref_t<Fn>>) {
- return type_caster<ret>::cast(
- [&](class_type_t<underlying_type>& self, auto&... args) {
- return (self.*fn)(args...);
- }(std::get<Is>(casters).value...),
- policy,
- parent);
- } else {
- return type_caster<ret>::cast(fn(std::get<Is>(casters).value...), policy, parent);
- }
- }
- }
- template <typename Fn, typename... Args, std::size_t... Is, typename... Extras>
- struct generator<Fn, std::tuple<Extras...>, std::tuple<Args...>, std::index_sequence<Is...>> {
- static void initialize(function_record& record, const Extras&... extras) {}
- static auto generate() {
- return +[](function_record& self, pkpy::ArgsView view, bool convert, handle parent) {
- // FIXME:
- // Temporarily, args and kwargs must be at the end of the arguments list
- // Named arguments are not supported yet
- constexpr bool has_args = types_count_v<args, remove_cvref_t<Args>...> != 0;
- constexpr bool has_kwargs = types_count_v<kwargs, remove_cvref_t<Args>...> != 0;
- constexpr std::size_t count = sizeof...(Args) - has_args - has_kwargs;
- handle stack[sizeof...(Args)] = {};
- // initialize the stack
- if(!has_args && (view.size() != count)) { return handle(); }
- if(has_args && (view.size() < count)) { return handle(); }
- for(std::size_t i = 0; i < count; ++i) {
- stack[i] = view[i];
- }
- // pack the args and kwargs
- if constexpr(has_args) {
- const auto n = view.size() - count;
- pkpy::PyVar var = vm->new_object<pkpy::Tuple>(vm->tp_tuple, n);
- auto& tuple = var.obj_get<pkpy::Tuple>();
- for(std::size_t i = 0; i < n; ++i) {
- tuple[i] = view[count + i];
- }
- stack[count] = var;
- }
- if constexpr(has_kwargs) {
- const auto n = vm->s_data._sp - view.end();
- pkpy::PyVar var = vm->new_object<pkpy::Dict>(vm->tp_dict);
- auto& dict = var.obj_get<pkpy::Dict>();
- for(std::size_t i = 0; i < n; i += 2) {
- pkpy::i64 index = pkpy::_py_cast<pkpy::i64>(vm, view[count + i]);
- pkpy::PyVar str = vm->new_object<pkpy::Str>(vm->tp_str, pkpy::StrName(index).sv());
- dict.set(vm, str, view[count + i + 1]);
- }
- stack[count + 1] = var;
- }
- // check if all the arguments are not valid
- for(std::size_t i = 0; i < sizeof...(Args); ++i) {
- if(!stack[i]) { return handle(); }
- }
- // ok, all the arguments are valid, call the function
- std::tuple<type_caster<Args>...> casters;
- // check type compatibility
- if(((std::get<Is>(casters).load(stack[Is], convert)) && ...)) {
- return invoke(self.cast<Fn>(), std::index_sequence<Is...>{}, casters, self.policy, parent);
- }
- return handle();
- };
- }
- };
- constexpr inline static auto _wrapper = +[](pkpy::VM*, pkpy::ArgsView view) {
- auto& record = pkpy::lambda_get_userdata<function_record>(view.begin());
- return record(view).ptr();
- };
- class cpp_function : public function {
- public:
- template <typename Fn, typename... Extras>
- cpp_function(Fn&& f, const Extras&... extras) {
- pkpy::any userdata = function_record(std::forward<Fn>(f), "anonymous", extras...);
- m_ptr = vm->bind_func(nullptr, "", -1, _wrapper, std::move(userdata));
- inc_ref();
- }
- };
- template <typename Fn, typename... Extras>
- handle bind_function(const handle& obj, const char* name, Fn&& fn, pkpy::BindType type, const Extras&... extras) {
- // do not use cpp_function directly to avoid unnecessary reference count change
- pkpy::PyVar var = obj.ptr();
- pkpy::PyVar callable = var->attr().try_get(name);
- // if the function is not bound yet, bind it
- if(!callable) {
- pkpy::any userdata = function_record(std::forward<Fn>(fn), name, extras...);
- callable = vm->bind_func(var, name, -1, _wrapper, std::move(userdata));
- } else {
- auto& userdata = callable.obj_get<pkpy::NativeFunc>()._userdata;
- function_record* record = new function_record(std::forward<Fn>(fn), name, extras...);
- constexpr bool is_prepend = (types_count_v<prepend, Extras...> != 0);
- if constexpr(is_prepend) {
- // if prepend is specified, append the new record to the beginning of the list
- function_record* last = (function_record*)userdata.data;
- userdata.data = record;
- record->append(last);
- } else {
- // otherwise, append the new record to the end of the list
- function_record* last = (function_record*)userdata.data;
- last->append(record);
- }
- }
- return callable;
- }
- template <typename Getter_, typename Setter_, typename... Extras>
- handle
- bind_property(const handle& obj, const char* name, Getter_&& getter_, Setter_&& setter_, const Extras&... extras) {
- pkpy::PyVar var = obj.ptr();
- pkpy::PyVar getter = vm->None;
- pkpy::PyVar setter = vm->None;
- using Getter = std::decay_t<Getter_>;
- using Setter = std::decay_t<Setter_>;
- getter = vm->new_object<pkpy::NativeFunc>(
- vm->tp_native_func,
- [](pkpy::VM* vm, pkpy::ArgsView view) -> pkpy::PyVar {
- auto& getter = pkpy::lambda_get_userdata<Getter>(view.begin());
- if constexpr(std::is_member_pointer_v<Getter>) {
- using Self = class_type_t<Getter>;
- auto& self = _builtin_cast<instance>(view[0]).cast<Self>();
- if constexpr(std::is_member_object_pointer_v<Getter>) {
- return type_caster<member_type_t<Getter>>::cast(self.*getter,
- return_value_policy::reference_internal,
- view[0])
- .ptr();
- } else {
- return type_caster<callable_return_t<Getter>>::cast((self.*getter)(),
- return_value_policy::reference_internal,
- view[0])
- .ptr();
- }
- } else {
- using Self = std::tuple_element_t<0, callable_args_t<Getter>>;
- auto& self = _builtin_cast<instance>(view[0]).cast<Self>();
- return type_caster<callable_return_t<Getter>>::cast(getter(self),
- return_value_policy::reference_internal,
- view[0])
- .ptr();
- }
- },
- 1,
- std::forward<Getter_>(getter_));
- if constexpr(!std::is_same_v<Setter, std::nullptr_t>) {
- setter = vm->new_object<pkpy::NativeFunc>(
- vm->tp_native_func,
- [](pkpy::VM* vm, pkpy::ArgsView view) -> pkpy::PyVar {
- auto& setter = pkpy::lambda_get_userdata<Setter>(view.begin());
- if constexpr(std::is_member_pointer_v<Setter>) {
- using Self = class_type_t<Setter>;
- auto& self = _builtin_cast<instance>(view[0]).cast<Self>();
- if constexpr(std::is_member_object_pointer_v<Setter>) {
- type_caster<member_type_t<Setter>> caster;
- if(caster.load(view[1], true)) {
- self.*setter = caster.value;
- return vm->None;
- }
- } else {
- type_caster<std::tuple_element_t<1, callable_args_t<Setter>>> caster;
- if(caster.load(view[1], true)) {
- (self.*setter)(caster.value);
- return vm->None;
- }
- }
- } else {
- using Self = std::tuple_element_t<0, callable_args_t<Setter>>;
- auto& self = _builtin_cast<instance>(view[0]).cast<Self>();
- type_caster<std::tuple_element_t<1, callable_args_t<Setter>>> caster;
- if(caster.load(view[1], true)) {
- setter(self, caster.value);
- return vm->None;
- }
- }
- vm->TypeError("invalid argument");
- },
- 2,
- std::forward<Setter_>(setter_));
- }
- pkpy::PyVar property = vm->new_object<pkpy::Property>(vm->tp_property, getter, setter);
- var->attr().set(name, property);
- return property;
- }
- } // namespace pybind11
|