some fix.

This commit is contained in:
ykiko 2024-08-23 00:37:09 +08:00
parent c6e24c69a2
commit 75811061b1
8 changed files with 138 additions and 154 deletions

View File

@ -2,11 +2,15 @@ name: CMake Build and Test
on: on:
push: push:
branches: paths-ignore:
- pkpy-v2 - "docs/**"
- "web/**"
- "**.md"
pull_request: pull_request:
branches: paths-ignore:
- pkpy-v2 - "docs/**"
- "web/**"
- "**.md"
jobs: jobs:
build_linux: build_linux:
@ -14,7 +18,7 @@ jobs:
steps: steps:
- name: Checkout code - name: Checkout code
uses: actions/checkout@v4 uses: actions/checkout@v4
- name: Set up GCC - name: Set up GCC
run: | run: |
sudo apt-get update sudo apt-get update
@ -23,18 +27,11 @@ jobs:
- name: Set up CMake - name: Set up CMake
uses: jwlawson/actions-setup-cmake@v1.10 uses: jwlawson/actions-setup-cmake@v1.10
- name: Install dependencies
run: |
git submodule update --init --recursive
git clone https://github.com/google/googletest.git
- name: Build
run: |
cmake -B build -DENABLE_TEST=ON
cmake --build build --config Release --parallel
- name: Test - name: Test
run: | run: |
cd include/pybind11/tests
cmake -B build
cmake --build build --config Release --parallel
build/pybind11_test build/pybind11_test
build_win: build_win:
@ -42,25 +39,18 @@ jobs:
steps: steps:
- name: Checkout code - name: Checkout code
uses: actions/checkout@v4 uses: actions/checkout@v4
- name: Set up MSVC - name: Set up MSVC
uses: ilammy/msvc-dev-cmd@v1 uses: ilammy/msvc-dev-cmd@v1
- name: Set up CMake - name: Set up CMake
uses: jwlawson/actions-setup-cmake@v1.10 uses: jwlawson/actions-setup-cmake@v1.10
- name: Install dependencies
run: |
git submodule update --init --recursive
git clone https://github.com/google/googletest.git
- name: Build
run: |
cmake -B build -DENABLE_TEST=ON
cmake --build build --config Release --parallel
- name: Test - name: Test
run: | run: |
cd include\pybind11\tests
cmake -B build
cmake --build build --config Release --parallel
build\Release\pybind11_test.exe build\Release\pybind11_test.exe
build_mac: build_mac:
@ -68,7 +58,7 @@ jobs:
steps: steps:
- name: Checkout code - name: Checkout code
uses: actions/checkout@v4 uses: actions/checkout@v4
- name: Set up Clang - name: Set up Clang
run: | run: |
brew install llvm brew install llvm
@ -78,16 +68,9 @@ jobs:
- name: Set up CMake - name: Set up CMake
uses: jwlawson/actions-setup-cmake@v1.10 uses: jwlawson/actions-setup-cmake@v1.10
- name: Install dependencies
run: |
git submodule update --init --recursive
git clone https://github.com/google/googletest.git
- name: Build
run: |
cmake -B build -DENABLE_TEST=ON
cmake --build build --config Release --parallel
- name: Test - name: Test
run: | run: |
cd include/pybind11/tests
cmake -B build -DENABLE_TEST=ON
cmake --build build --config Release --parallel
build/pybind11_test build/pybind11_test

View File

@ -79,7 +79,7 @@ struct type_caster<T, std::enable_if_t<is_integer_v<T>>> {
bool load(handle src, bool) { bool load(handle src, bool) {
if(isinstance<int_>(src)) { if(isinstance<int_>(src)) {
data = py_toint(src.ptr()); data = static_cast<T>(py_toint(src.ptr()));
return true; return true;
} }

View File

@ -1,6 +1,7 @@
#pragma once #pragma once
#include "module.h" #include "module.h"
#include "type_traits.h"
namespace pkbind { namespace pkbind {
@ -38,7 +39,8 @@ public:
[[maybe_unused]] auto kwargs = py_offset(stack, 2); [[maybe_unused]] auto kwargs = py_offset(stack, 2);
auto info = &type_info::of<T>(); auto info = &type_info::of<T>();
int slot = (type_list<Args...>::template count<dynamic_attr> ? -1 : 0); int slot = ((std::is_same_v<dynamic_attr, Args> || ...) ? -1 : 0);
std::cout << "<< " << slot << "\n";
void* data = py_newobject(retv, steal<type>(cls).index(), slot, sizeof(instance)); void* data = py_newobject(retv, steal<type>(cls).index(), slot, sizeof(instance));
new (data) instance{instance::Flag::Own, operator new (info->size), info}; new (data) instance{instance::Flag::Own, operator new (info->size), info};
return true; return true;
@ -82,8 +84,9 @@ public:
constexpr bool is_first_base_of_v = std::is_base_of_v<first, T> || std::is_same_v<first, T>; constexpr bool is_first_base_of_v = std::is_base_of_v<first, T> || std::is_same_v<first, T>;
if constexpr(!is_first_base_of_v) { if constexpr(!is_first_base_of_v) {
static_assert(is_first_base_of_v, static_assert(
"If you want to bind member function, the first argument must be the base class"); is_first_base_of_v,
"If you want to bind member function, the first argument must be the base class");
} else { } else {
impl::bind_function<true, false>(*this, name, std::forward<Fn>(f), extra...); impl::bind_function<true, false>(*this, name, std::forward<Fn>(f), extra...);
} }
@ -108,7 +111,8 @@ public:
template <typename MP, typename... Extras> template <typename MP, typename... Extras>
class_& def_readwrite(const char* name, MP mp, const Extras&... extras) { class_& def_readwrite(const char* name, MP mp, const Extras&... extras) {
if constexpr(!std::is_member_object_pointer_v<MP>) { if constexpr(!std::is_member_object_pointer_v<MP>) {
static_assert(std::is_member_object_pointer_v<MP>, "def_readwrite only supports pointer to data member"); static_assert(std::is_member_object_pointer_v<MP>,
"def_readwrite only supports pointer to data member");
} else { } else {
impl::bind_property( impl::bind_property(
*this, *this,
@ -127,7 +131,8 @@ public:
template <typename MP, typename... Extras> template <typename MP, typename... Extras>
class_& def_readonly(const char* name, MP mp, const Extras&... extras) { class_& def_readonly(const char* name, MP mp, const Extras&... extras) {
if constexpr(!std::is_member_object_pointer_v<MP>) { if constexpr(!std::is_member_object_pointer_v<MP>) {
static_assert(std::is_member_object_pointer_v<MP>, "def_readonly only supports pointer to data member"); static_assert(std::is_member_object_pointer_v<MP>,
"def_readonly only supports pointer to data member");
} else { } else {
impl::bind_property( impl::bind_property(
*this, *this,
@ -143,7 +148,11 @@ public:
template <typename Getter, typename Setter, typename... Extras> template <typename Getter, typename Setter, typename... Extras>
class_& def_property(const char* name, Getter&& g, Setter&& s, const Extras&... extras) { class_& def_property(const char* name, Getter&& g, Setter&& s, const Extras&... extras) {
impl::bind_property(*this, name, std::forward<Getter>(g), std::forward<Setter>(s), extras...); impl::bind_property(*this,
name,
std::forward<Getter>(g),
std::forward<Setter>(s),
extras...);
return *this; return *this;
} }

View File

@ -147,8 +147,8 @@ public:
using Callable = std::decay_t<Fn>; using Callable = std::decay_t<Fn>;
if constexpr(std::is_trivially_copyable_v<Callable> && sizeof(Callable) <= sizeof(buffer)) { if constexpr(std::is_trivially_copyable_v<Callable> && sizeof(Callable) <= sizeof(buffer)) {
// if the callable object is trivially copyable and the size is less than 16 bytes, store it in the // if the callable object is trivially copyable and the size is less than 16 bytes,
// buffer // store it in the buffer
new (buffer) auto(std::forward<Fn>(f)); new (buffer) auto(std::forward<Fn>(f));
destructor = [](function_record* self) { destructor = [](function_record* self) {
reinterpret_cast<Callable*>(self->buffer)->~Callable(); reinterpret_cast<Callable*>(self->buffer)->~Callable();
@ -178,18 +178,10 @@ public:
function_record& operator= (function_record&&) = delete; function_record& operator= (function_record&&) = delete;
~function_record() { ~function_record() {
if(destructor) { if(destructor) { destructor(this); }
destructor(this); if(arguments) { delete arguments; }
} if(next) { delete next; }
if(arguments) { if(signature) { delete[] signature; }
delete arguments;
}
if(next) {
delete next;
}
if(signature) {
delete[] signature;
}
} }
void append(function_record* record) { void append(function_record* record) {
@ -220,9 +212,7 @@ public:
bool has_self = argc == 3; bool has_self = argc == 3;
std::vector<handle> args; std::vector<handle> args;
handle self = py_offset(stack.ptr(), 0); handle self = py_offset(stack.ptr(), 0);
if(has_self) { if(has_self) { args.push_back(self); }
args.push_back(self);
}
auto tuple = py_offset(stack.ptr(), 0 + has_self); auto tuple = py_offset(stack.ptr(), 0 + has_self);
for(int i = 0; i < py_tuple_len(tuple); ++i) { for(int i = 0; i < py_tuple_len(tuple); ++i) {
@ -239,9 +229,7 @@ public:
// foreach function record and call the function with not convert // foreach function record and call the function with not convert
while(p != nullptr) { while(p != nullptr) {
auto result = p->wrapper(*p, args, kwargs, false, self); auto result = p->wrapper(*p, args, kwargs, false, self);
if(result) { if(result) { return; }
return;
}
p = p->next; p = p->next;
} }
@ -249,9 +237,7 @@ public:
// foreach function record and call the function with convert // foreach function record and call the function with convert
while(p != nullptr) { while(p != nullptr) {
auto result = p->wrapper(*p, args, kwargs, true, self); auto result = p->wrapper(*p, args, kwargs, true, self);
if(result) { if(result) { return; }
return;
}
p = p->next; p = p->next;
} }
@ -299,14 +285,16 @@ void invoke(Fn&& fn,
}; };
if constexpr(!is_void) { if constexpr(!is_void) {
py_assign(py_retval(), pkbind::cast(unpack(std::get<Is>(casters).value()...), policy, parent).ptr()); py_assign(py_retval(),
pkbind::cast(unpack(std::get<Is>(casters).value()...), policy, parent).ptr());
} else { } else {
unpack(std::get<Is>(casters).value()...); unpack(std::get<Is>(casters).value()...);
py_newnone(py_retval()); py_newnone(py_retval());
} }
} else { } else {
if constexpr(!is_void) { if constexpr(!is_void) {
py_assign(py_retval(), pkbind::cast(fn(std::get<Is>(casters).value()...), policy, parent).ptr()); py_assign(py_retval(),
pkbind::cast(fn(std::get<Is>(casters).value()...), policy, parent).ptr());
} else { } else {
fn(std::get<Is>(casters).value()...); fn(std::get<Is>(casters).value()...);
py_newnone(py_retval()); py_newnone(py_retval());
@ -315,7 +303,10 @@ void invoke(Fn&& fn,
} }
template <typename Callable, typename... Extras, typename... Args, std::size_t... Is> template <typename Callable, typename... Extras, typename... Args, std::size_t... Is>
struct template_parser<Callable, std::tuple<Extras...>, std::tuple<Args...>, std::index_sequence<Is...>> { struct template_parser<Callable,
std::tuple<Extras...>,
std::tuple<Args...>,
std::index_sequence<Is...>> {
using types = type_list<Args...>; using types = type_list<Args...>;
/// count of the Callable parameters. /// count of the Callable parameters.
@ -333,7 +324,8 @@ struct template_parser<Callable, std::tuple<Extras...>, std::tuple<Args...>, std
// FIXME: temporarily, args and kwargs must be at the end of the arguments list // FIXME: temporarily, args and kwargs must be at the end of the arguments list
/// if have py::kwargs, it must be at the end of the arguments list. /// if have py::kwargs, it must be at the end of the arguments list.
static_assert(kwargs_count == 0 || kwargs_pos == argc - 1, "py::kwargs must be the last parameter"); static_assert(kwargs_count == 0 || kwargs_pos == argc - 1,
"py::kwargs must be the last parameter");
/// if have py::args, it must be before py::kwargs or at the end of the arguments list. /// if have py::args, it must be before py::kwargs or at the end of the arguments list.
static_assert(args_count == 0 || args_pos == kwargs_pos - 1 || args_pos == argc - 1, static_assert(args_count == 0 || args_pos == kwargs_pos - 1 || args_pos == argc - 1,
"py::args must be before py::kwargs or at the end of the parameter list"); "py::args must be before py::kwargs or at the end of the parameter list");
@ -348,14 +340,18 @@ struct template_parser<Callable, std::tuple<Extras...>, std::tuple<Args...>, std
constexpr inline static auto policy_pos = extras::template find<pkbind::return_value_policy>; constexpr inline static auto policy_pos = extras::template find<pkbind::return_value_policy>;
constexpr inline static auto last_arg_without_default_pos = types::template find_last<pkbind::arg>; constexpr inline static auto last_arg_without_default_pos =
constexpr inline static auto first_arg_with_default_pos = types::template find<pkbind::arg_with_default>; types::template find_last<pkbind::arg>;
static_assert(last_arg_without_default_pos < first_arg_with_default_pos || first_arg_with_default_pos == -1, constexpr inline static auto first_arg_with_default_pos =
types::template find<pkbind::arg_with_default>;
static_assert(last_arg_without_default_pos < first_arg_with_default_pos ||
first_arg_with_default_pos == -1,
"parameter with default value must be after parameter without default value"); "parameter with default value must be after parameter without default value");
/// count of named parameters(explicit with name). /// count of named parameters(explicit with name).
constexpr inline static auto named_only_argc = extras::template count<pkbind::arg>; constexpr inline static auto named_only_argc = extras::template count<pkbind::arg>;
constexpr inline static auto named_default_argc = extras::template count<pkbind::arg_with_default>; constexpr inline static auto named_default_argc =
extras::template count<pkbind::arg_with_default>;
constexpr inline static auto named_argc = named_only_argc + named_default_argc; constexpr inline static auto named_argc = named_only_argc + named_default_argc;
/// count of normal parameters(which are not py::args or py::kwargs). /// count of normal parameters(which are not py::args or py::kwargs).
@ -368,9 +364,7 @@ struct template_parser<Callable, std::tuple<Extras...>, std::tuple<Args...>, std
static void initialize(function_record& record, const Extras&... extras) { static void initialize(function_record& record, const Extras&... extras) {
auto extras_tuple = std::make_tuple(extras...); auto extras_tuple = std::make_tuple(extras...);
constexpr static bool has_named_args = (named_argc > 0); constexpr static bool has_named_args = (named_argc > 0);
if constexpr(policy_pos != -1) { if constexpr(policy_pos != -1) { record.policy = std::get<policy_pos>(extras_tuple); }
record.policy = std::get<policy_pos>(extras_tuple);
}
// TODO: set others // TODO: set others
@ -410,15 +404,15 @@ struct template_parser<Callable, std::tuple<Extras...>, std::tuple<Args...>, std
sig += type_info::of<T>().name; sig += type_info::of<T>().name;
if(!record.arguments->defaults[index].empty()) { if(!record.arguments->defaults[index].empty()) {
sig += " = "; sig += " = ";
sig += record.arguments->defaults[index].attr("__repr__")().cast<std::string_view>(); sig += record.arguments->defaults[index]
.attr("__repr__")()
.cast<std::string_view>();
} }
} else { } else {
sig += "_: "; sig += "_: ";
sig += type_info::of<T>().name; sig += type_info::of<T>().name;
} }
if(index + 1 < argc) { if(index + 1 < argc) { sig += ", "; }
sig += ", ";
}
index++; index++;
}; };
(append(type_identity<Args>{}), ...); (append(type_identity<Args>{}), ...);
@ -430,8 +424,8 @@ struct template_parser<Callable, std::tuple<Extras...>, std::tuple<Args...>, std
} }
} }
/// try to call a C++ function(store in function_record) with the arguments which are from Python. /// try to call a C++ function(store in function_record) with the arguments which are from
/// if success, return true, otherwise return false. /// Python. if success, return true, otherwise return false.
static bool call(function_record& record, static bool call(function_record& record,
std::vector<handle>& args, std::vector<handle>& args,
std::vector<std::pair<handle, handle>>& kwargs, std::vector<std::pair<handle, handle>>& kwargs,
@ -451,9 +445,7 @@ struct template_parser<Callable, std::tuple<Extras...>, std::tuple<Args...>, std
// load arguments from call arguments // load arguments from call arguments
if(args.size() > normal_argc) { if(args.size() > normal_argc) {
if constexpr(args_pos == -1) { if constexpr(args_pos == -1) { return false; }
return false;
}
} }
for(std::size_t i = 0; i < std::min(normal_argc, (int)args.size()); ++i) { for(std::size_t i = 0; i < std::min(normal_argc, (int)args.size()); ++i) {
@ -463,9 +455,10 @@ struct template_parser<Callable, std::tuple<Extras...>, std::tuple<Args...>, std
object repack_args; object repack_args;
// pack the args // pack the args
if constexpr(args_pos != -1) { if constexpr(args_pos != -1) {
const auto n = args.size() > normal_argc ? args.size() - normal_argc : 0; const auto n =
static_cast<int>(args.size() > normal_argc ? args.size() - normal_argc : 0);
auto pack = tuple(n); auto pack = tuple(n);
for(std::size_t i = 0; i < n; ++i) { for(int i = 0; i < n; ++i) {
pack[i] = args[normal_argc + i]; pack[i] = args[normal_argc + i];
} }
repack_args = std::move(pack); repack_args = std::move(pack);
@ -500,16 +493,18 @@ struct template_parser<Callable, std::tuple<Extras...>, std::tuple<Args...>, std
// check if all the arguments are valid // check if all the arguments are valid
for(std::size_t i = 0; i < argc; ++i) { for(std::size_t i = 0; i < argc; ++i) {
if(!stack[i]) { if(!stack[i]) { return false; }
return false;
}
} }
// ok, all the arguments are valid, call the function // ok, all the arguments are valid, call the function
std::tuple<type_caster<Args>...> casters; std::tuple<type_caster<Args>...> casters;
if(((std::get<Is>(casters).load(stack[Is], convert)) && ...)) { if(((std::get<Is>(casters).load(stack[Is], convert)) && ...)) {
invoke(record.as<Callable>(), std::index_sequence<Is...>{}, casters, record.policy, parent); invoke(record.as<Callable>(),
std::index_sequence<Is...>{},
casters,
record.policy,
parent);
return true; return true;
} }
@ -533,15 +528,14 @@ class cpp_function : public function {
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) { if(slot) { return py_typeof(slot) == m_type; }
return py_typeof(slot) == m_type;
}
} }
return false; return false;
} }
template <typename Fn, typename... Extras> template <typename Fn, typename... Extras>
cpp_function(bool is_method, const char* name, Fn&& fn, const Extras&... extras) : function(alloc_t{}) { cpp_function(bool is_method, const char* name, Fn&& fn, const Extras&... extras) :
function(alloc_t{}) {
// 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)";
@ -562,13 +556,9 @@ class cpp_function : public function {
py_exception(tp_IndexError, e.what()); py_exception(tp_IndexError, e.what());
} catch(std::range_error& e) { } catch(std::range_error& e) {
py_exception(tp_ValueError, e.what()); py_exception(tp_ValueError, e.what());
} catch(stop_iteration& e) { } catch(stop_iteration&) { StopIteration(); } catch(index_error& e) {
StopIteration();
} catch(index_error& e) {
py_exception(tp_IndexError, e.what()); py_exception(tp_IndexError, e.what());
} catch(key_error& e) { } catch(key_error& e) { py_exception(tp_KeyError, e.what()); } catch(value_error& e) {
py_exception(tp_KeyError, e.what());
} catch(value_error& e) {
py_exception(tp_ValueError, e.what()); py_exception(tp_ValueError, e.what());
} catch(type_error& e) { } catch(type_error& e) {
py_exception(tp_TypeError, e.what()); py_exception(tp_TypeError, e.what());
@ -576,9 +566,7 @@ class cpp_function : public function {
py_exception(tp_ImportError, e.what()); py_exception(tp_ImportError, e.what());
} catch(attribute_error& e) { } catch(attribute_error& e) {
py_exception(tp_AttributeError, e.what()); py_exception(tp_AttributeError, e.what());
} catch(std::exception& e) { } catch(std::exception& e) { py_exception(tp_RuntimeError, e.what()); }
py_exception(tp_RuntimeError, e.what());
}
return false; return false;
}; };
py_newfunction(m_ptr, sig.c_str(), call, nullptr, 1); py_newfunction(m_ptr, sig.c_str(), call, nullptr, 1);
@ -590,7 +578,8 @@ class cpp_function : public function {
} }
template <typename Fn, typename... Extras> template <typename Fn, typename... Extras>
cpp_function(Fn&& fn, const Extras&... extras) : cpp_function("lambda", std::forward<Fn>(fn), extras...) {} cpp_function(Fn&& fn, const Extras&... extras) :
cpp_function("lambda", std::forward<Fn>(fn), extras...) {}
}; };
class property : public object { class property : public object {
@ -620,7 +609,8 @@ namespace impl {
template <bool is_method, bool is_static, typename Fn, typename... Extras> template <bool is_method, bool is_static, typename Fn, typename... Extras>
void bind_function(handle obj, const char* name_, Fn&& fn, const Extras&... extras) { void bind_function(handle obj, const char* name_, Fn&& fn, const Extras&... extras) {
constexpr bool has_named_args = ((std::is_same_v<Extras, arg> || std::is_same_v<Extras, arg_with_default>) || ...); constexpr bool has_named_args =
((std::is_same_v<Extras, arg> || std::is_same_v<Extras, arg_with_default>) || ...);
auto name = py_name(name_); auto name = py_name(name_);
auto func = py_getdict(obj.ptr(), name); auto func = py_getdict(obj.ptr(), name);
@ -634,23 +624,33 @@ void bind_function(handle obj, const char* name_, Fn&& fn, const Extras&... extr
} }
} else { } else {
if constexpr(is_static) { if constexpr(is_static) {
py_setdict(obj.ptr(), py_setdict(
name, obj.ptr(),
staticmethod(cpp_function(is_method, name_, std::forward<Fn>(fn), extras...).ptr()).ptr()); name,
staticmethod(cpp_function(is_method, name_, std::forward<Fn>(fn), extras...).ptr())
.ptr());
} else { } else {
if constexpr(has_named_args && is_method) { if constexpr(has_named_args && is_method) {
py_setdict(
obj.ptr(),
name,
cpp_function(is_method, name_, std::forward<Fn>(fn), arg("self"), extras...)
.ptr());
} else {
py_setdict(obj.ptr(), py_setdict(obj.ptr(),
name, name,
cpp_function(is_method, name_, std::forward<Fn>(fn), arg("self"), extras...).ptr()); cpp_function(is_method, name_, std::forward<Fn>(fn), extras...).ptr());
} else {
py_setdict(obj.ptr(), name, cpp_function(is_method, name_, std::forward<Fn>(fn), extras...).ptr());
} }
} }
} }
} }
template <typename Getter, typename Setter, typename... Extras> template <typename Getter, typename Setter, typename... Extras>
void bind_property(handle obj, const char* name, Getter&& getter_, Setter&& setter_, const Extras&... extras) { void bind_property(handle obj,
const char* name,
Getter&& getter_,
Setter&& setter_,
const Extras&... extras) {
if constexpr(std::is_same_v<std::decay_t<Setter>, std::nullptr_t>) { if constexpr(std::is_same_v<std::decay_t<Setter>, std::nullptr_t>) {
cpp_function getter(true, cpp_function getter(true,
name, name,

View File

@ -120,7 +120,7 @@ public:
name(const char* data, int size) : data(py_namev({data, size})) {} name(const char* data, int size) : data(py_namev({data, size})) {}
name(std::string_view str) : name(str.data(), str.size()) {} name(std::string_view str) : name(str.data(), static_cast<int>(str.size())) {}
name(handle h); name(handle h);
@ -198,9 +198,7 @@ public:
object() = default; object() = default;
object(const object& other) : handle(other), m_index(other.m_index) { object(const object& other) : handle(other), m_index(other.m_index) {
if(other.in_pool()) { if(other.in_pool()) { object_pool::inc_ref(other); }
object_pool::inc_ref(other);
}
} }
object(object&& other) : handle(other), m_index(other.m_index) { object(object&& other) : handle(other), m_index(other.m_index) {
@ -210,12 +208,8 @@ public:
object& operator= (const object& other) { object& operator= (const object& other) {
if(this != &other) { if(this != &other) {
if(in_pool()) { if(in_pool()) { object_pool::dec_ref(*this); }
object_pool::dec_ref(*this); if(other.in_pool()) { object_pool::inc_ref(other); }
}
if(other.in_pool()) {
object_pool::inc_ref(other);
}
m_ptr = other.m_ptr; m_ptr = other.m_ptr;
m_index = other.m_index; m_index = other.m_index;
} }
@ -224,9 +218,7 @@ public:
object& operator= (object&& other) { object& operator= (object&& other) {
if(this != &other) { if(this != &other) {
if(in_pool()) { if(in_pool()) { object_pool::dec_ref(*this); }
object_pool::dec_ref(*this);
}
m_ptr = other.m_ptr; m_ptr = other.m_ptr;
m_index = other.m_index; m_index = other.m_index;
other.m_ptr = nullptr; other.m_ptr = nullptr;
@ -236,9 +228,7 @@ public:
} }
~object() { ~object() {
if(in_pool()) { if(in_pool()) { object_pool::dec_ref(*this); }
object_pool::dec_ref(*this);
}
} }
bool is_singleton() const { return m_ptr && m_index == -1; } bool is_singleton() const { return m_ptr && m_index == -1; }

View File

@ -4,22 +4,24 @@
namespace pkbind { namespace pkbind {
#define PKBIND_TYPE_IMPL(parent, child, expr) \ #define PKBIND_TYPE_IMPL(parent, child, expr) \
\ \
private: \ private: \
friend class type; \ friend class type; \
static auto type_or_check() { return expr; } \ static auto type_or_check() { return expr; } \
\ \
public: \ public: \
using parent::parent; \ using parent::parent; \
using parent::operator=; \ using parent::operator=; \
child(const object& o) : parent(type::isinstance<child>(o) ? o : type::of<child>()(o)) {} \ child(const object& o) : parent(type::isinstance<child>(o) ? o : type::of<child>()(o)) {} \
child(object&& o) : parent(type::isinstance<child>(o) ? std::move(o) : type::of<child>()(std::move(o))) {} child(object&& o) : \
parent(type::isinstance<child>(o) ? std::move(o) : type::of<child>()(std::move(o))) {}
class type : public object { class type : public object {
protected: protected:
template <typename T> template <typename T>
constexpr inline static bool is_check_v = std::is_invocable_r_v<bool, decltype(T::type_or_check()), handle>; constexpr inline static bool is_check_v =
std::is_invocable_r_v<bool, decltype(T::type_or_check()), handle>;
static auto type_or_check() { return tp_type; } static auto type_or_check() { return tp_type; }
@ -108,7 +110,9 @@ public:
object operator* () const { return m_value; } object operator* () const { return m_value; }
friend bool operator== (const iterator& lhs, const iterator& rhs) { return lhs.m_value.ptr() == rhs.m_value.ptr(); } friend bool operator== (const iterator& lhs, const iterator& rhs) {
return lhs.m_value.ptr() == rhs.m_value.ptr();
}
friend bool operator!= (const iterator& lhs, const iterator& rhs) { return !(lhs == rhs); } friend bool operator!= (const iterator& lhs, const iterator& rhs) { return !(lhs == rhs); }
@ -134,7 +138,7 @@ class str : public object {
str(const char* data, int size) : object(alloc_t{}) { py_newstrn(m_ptr, data, size); } str(const char* data, int size) : object(alloc_t{}) { py_newstrn(m_ptr, data, size); }
str(const char* data) : str(data, strlen(data)) {} str(const char* data) : str(data, static_cast<int>(strlen(data))) {}
str(std::string_view s) : str(s.data(), static_cast<int>(s.size())) {} str(std::string_view s) : str(s.data(), static_cast<int>(s.size())) {}
@ -147,7 +151,7 @@ class tuple : public object {
tuple(int size) : object(alloc_t{}) { py_newtuple(m_ptr, size); } tuple(int size) : object(alloc_t{}) { py_newtuple(m_ptr, size); }
tuple(std::initializer_list<handle> args) : tuple(args.size()) { tuple(std::initializer_list<handle> args) : tuple(static_cast<int>(args.size())) {
int index = 0; int index = 0;
for(auto& arg: args) { for(auto& arg: args) {
py_tuple_setitem(m_ptr, index++, arg.ptr()); py_tuple_setitem(m_ptr, index++, arg.ptr());
@ -194,7 +198,7 @@ class list : public object {
list(int size) : object(alloc_t{}) { py_newlistn(m_ptr, size); } list(int size) : object(alloc_t{}) { py_newlistn(m_ptr, size); }
list(std::initializer_list<handle> args) : list(args.size()) { list(std::initializer_list<handle> args) : list(static_cast<int>(args.size())) {
int index = 0; int index = 0;
for(auto& arg: args) { for(auto& arg: args) {
py_list_setitem(m_ptr, index++, arg.ptr()); py_list_setitem(m_ptr, index++, arg.ptr());
@ -338,9 +342,7 @@ class capsule : public object {
static void register_() { static void register_() {
m_type = py_newtype("capsule", tp_object, nullptr, [](void* data) { 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) { if(impl->data && impl->destructor) { impl->destructor(impl->data); }
impl->destructor(impl->data);
}
}); });
} }

View File

@ -30,7 +30,7 @@ struct type_caster<std::array<T, N>> {
if(list.size() != N) { return false; } if(list.size() != N) { return false; }
for(std::size_t i = 0; i < N; ++i) { for(int i = 0; i < N; ++i) {
type_caster<T> caster; type_caster<T> caster;
if(!caster.load(list[i], convert)) { return false; } if(!caster.load(list[i], convert)) { return false; }
data[i] = std::move(caster.value()); data[i] = std::move(caster.value());
@ -139,7 +139,8 @@ struct type_caster<T, std::enable_if_t<is_py_map_like_v<T>>> {
static object cast(U&& src, return_value_policy policy, handle parent) { static object cast(U&& src, return_value_policy policy, handle parent) {
auto dict = pkbind::dict(); auto dict = pkbind::dict();
for(auto&& [key, value]: src) { for(auto&& [key, value]: src) {
dict[pkbind::cast(std::move(key), policy, parent)] = pkbind::cast(std::move(value), policy, parent); dict[pkbind::cast(std::move(key), policy, parent)] =
pkbind::cast(std::move(value), policy, parent);
} }
return dict; return dict;
} }
@ -167,4 +168,3 @@ struct type_caster<T, std::enable_if_t<is_py_map_like_v<T>>> {
}; };
} // namespace pkbind } // namespace pkbind

View File

@ -351,7 +351,7 @@ TEST_F(PYBIND11_TEST, lambda) {
size_t c; size_t c;
size_t d; size_t d;
int operator() (int x, int y) { return x + y + a + b + c + d; } size_t operator() (size_t x, size_t y) { return x + y + a + b + c + d; }
~NotSmall() { destructor_calls++; } ~NotSmall() { destructor_calls++; }
}; };