Adding construct() overloads for constructing smart_holder from alias…

Adding construct() overloads for constructing smart_holder from alias unique_ptr, shared_ptr returns.
parent f4d5ee0c
...@@ -176,13 +176,20 @@ template <typename Class, typename D = std::default_delete<Cpp<Class>>, ...@@ -176,13 +176,20 @@ template <typename Class, typename D = std::default_delete<Cpp<Class>>,
void construct(value_and_holder &v_h, std::unique_ptr<Cpp<Class>, D> &&unq_ptr, bool need_alias) { void construct(value_and_holder &v_h, std::unique_ptr<Cpp<Class>, D> &&unq_ptr, bool need_alias) {
auto *ptr = unq_ptr.get(); auto *ptr = unq_ptr.get();
no_nullptr(ptr); no_nullptr(ptr);
// If we need an alias, check that the held pointer is actually an alias instance if (Class::has_alias && need_alias)
if (Class::has_alias && need_alias && !is_alias<Class>(ptr)) throw type_error("pybind11::init(): construction failed: returned std::unique_ptr pointee "
throw type_error("pybind11::init(): construction failed: returned holder-wrapped instance "
"is not an alias instance"); "is not an alias instance");
auto smhldr = smart_holder::from_unique_ptr(std::move(unq_ptr));
v_h.value_ptr() = ptr;
v_h.type->init_instance(v_h.inst, &smhldr);
}
auto smhldr = pybindit::memory::smart_holder::from_unique_ptr(std::move(unq_ptr)); template <typename Class, typename D = std::default_delete<Alias<Class>>,
detail::enable_if_t<detail::is_smart_holder_type_caster<Alias<Class>>::value, int> = 0>
void construct(value_and_holder &v_h, std::unique_ptr<Alias<Class>, D> &&unq_ptr, bool /*need_alias*/) {
auto *ptr = unq_ptr.get();
no_nullptr(ptr);
auto smhldr = smart_holder::from_unique_ptr(std::move(unq_ptr));
v_h.value_ptr() = ptr; v_h.value_ptr() = ptr;
v_h.type->init_instance(v_h.inst, &smhldr); v_h.type->init_instance(v_h.inst, &smhldr);
} }
...@@ -192,13 +199,20 @@ template <typename Class, ...@@ -192,13 +199,20 @@ template <typename Class,
void construct(value_and_holder &v_h, std::shared_ptr<Cpp<Class>> &&shd_ptr, bool need_alias) { void construct(value_and_holder &v_h, std::shared_ptr<Cpp<Class>> &&shd_ptr, bool need_alias) {
auto *ptr = shd_ptr.get(); auto *ptr = shd_ptr.get();
no_nullptr(ptr); no_nullptr(ptr);
// If we need an alias, check that the held pointer is actually an alias instance if (Class::has_alias && need_alias)
if (Class::has_alias && need_alias && !is_alias<Class>(ptr)) throw type_error("pybind11::init(): construction failed: returned std::shared_ptr pointee "
throw type_error("pybind11::init(): construction failed: returned holder-wrapped instance "
"is not an alias instance"); "is not an alias instance");
auto smhldr = smart_holder::from_shared_ptr(std::move(shd_ptr));
v_h.value_ptr() = ptr;
v_h.type->init_instance(v_h.inst, &smhldr);
}
auto smhldr = pybindit::memory::smart_holder::from_shared_ptr(std::move(shd_ptr)); template <typename Class,
detail::enable_if_t<detail::is_smart_holder_type_caster<Alias<Class>>::value, int> = 0>
void construct(value_and_holder &v_h, std::shared_ptr<Alias<Class>> &&shd_ptr, bool /*need_alias*/) {
auto *ptr = shd_ptr.get();
no_nullptr(ptr);
auto smhldr = smart_holder::from_shared_ptr(std::move(shd_ptr));
v_h.value_ptr() = ptr; v_h.value_ptr() = ptr;
v_h.type->init_instance(v_h.inst, &smhldr); v_h.type->init_instance(v_h.inst, &smhldr);
} }
......
...@@ -54,6 +54,15 @@ std::unique_ptr<atyp_udcp const, sddc> rtrn_udcp() { return std::unique_ptr<atyp ...@@ -54,6 +54,15 @@ std::unique_ptr<atyp_udcp const, sddc> rtrn_udcp() { return std::unique_ptr<atyp
// clang-format on // clang-format on
// Minimalistic approach to achieve full coverage of construct() overloads for constructing
// smart_holder from unique_ptr and shared_ptr returns.
struct with_alias {
int val = 0;
virtual ~with_alias() = default;
};
struct with_alias_alias : with_alias {};
struct sddwaa : std::default_delete<with_alias_alias> {};
} // namespace test_class_sh_factory_constructors } // namespace test_class_sh_factory_constructors
} // namespace pybind11_tests } // namespace pybind11_tests
...@@ -69,6 +78,7 @@ PYBIND11_SMART_HOLDER_TYPE_CASTERS(pybind11_tests::test_class_sh_factory_constru ...@@ -69,6 +78,7 @@ PYBIND11_SMART_HOLDER_TYPE_CASTERS(pybind11_tests::test_class_sh_factory_constru
PYBIND11_SMART_HOLDER_TYPE_CASTERS(pybind11_tests::test_class_sh_factory_constructors::atyp_uqcp) PYBIND11_SMART_HOLDER_TYPE_CASTERS(pybind11_tests::test_class_sh_factory_constructors::atyp_uqcp)
PYBIND11_SMART_HOLDER_TYPE_CASTERS(pybind11_tests::test_class_sh_factory_constructors::atyp_udmp) PYBIND11_SMART_HOLDER_TYPE_CASTERS(pybind11_tests::test_class_sh_factory_constructors::atyp_udmp)
PYBIND11_SMART_HOLDER_TYPE_CASTERS(pybind11_tests::test_class_sh_factory_constructors::atyp_udcp) PYBIND11_SMART_HOLDER_TYPE_CASTERS(pybind11_tests::test_class_sh_factory_constructors::atyp_udcp)
PYBIND11_SMART_HOLDER_TYPE_CASTERS(pybind11_tests::test_class_sh_factory_constructors::with_alias)
TEST_SUBMODULE(class_sh_factory_constructors, m) { TEST_SUBMODULE(class_sh_factory_constructors, m) {
using namespace pybind11_tests::test_class_sh_factory_constructors; using namespace pybind11_tests::test_class_sh_factory_constructors;
...@@ -134,4 +144,31 @@ TEST_SUBMODULE(class_sh_factory_constructors, m) { ...@@ -134,4 +144,31 @@ TEST_SUBMODULE(class_sh_factory_constructors, m) {
// classh: ... cannot pass object of non-trivial type ... // classh: ... cannot pass object of non-trivial type ...
// .def(py::init(&rtrn_udcp)) // .def(py::init(&rtrn_udcp))
.def("get_mtxt", get_mtxt<atyp_udcp>); .def("get_mtxt", get_mtxt<atyp_udcp>);
py::classh<with_alias, with_alias_alias>(m, "with_alias")
.def_readonly("val", &with_alias::val)
.def(py::init([](int i) {
auto p = std::unique_ptr<with_alias_alias, sddwaa>(new with_alias_alias);
p->val = i * 100;
return p;
}))
.def(py::init([](int i, int j) {
auto p = std::unique_ptr<with_alias_alias>(new with_alias_alias);
p->val = i * 100 + j * 10;
return p;
}))
.def(py::init([](int i, int j, int k) {
auto p = std::shared_ptr<with_alias_alias>(new with_alias_alias);
p->val = i * 100 + j * 10 + k;
return p;
}))
.def(py::init(
[](int, int, int, int) { return std::unique_ptr<with_alias>(new with_alias); },
[](int, int, int, int) {
return std::unique_ptr<with_alias>(new with_alias); // Invalid alias factory.
}))
.def(py::init([](int, int, int, int, int) { return std::make_shared<with_alias>(); },
[](int, int, int, int, int) {
return std::make_shared<with_alias>(); // Invalid alias factory.
}));
} }
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
import pytest
from pybind11_tests import class_sh_factory_constructors as m from pybind11_tests import class_sh_factory_constructors as m
...@@ -16,3 +17,36 @@ def test_atyp_factories(): ...@@ -16,3 +17,36 @@ def test_atyp_factories():
# sert m.atyp_uqcp().get_mtxt() == "Uqcp" # sert m.atyp_uqcp().get_mtxt() == "Uqcp"
assert m.atyp_udmp().get_mtxt() == "Udmp" assert m.atyp_udmp().get_mtxt() == "Udmp"
# sert m.atyp_udcp().get_mtxt() == "Udcp" # sert m.atyp_udcp().get_mtxt() == "Udcp"
@pytest.mark.parametrize(
"init_args, expected",
[
((3,), 300),
((5, 7), 570),
((9, 11, 13), 1023),
],
)
def test_with_alias_success(init_args, expected):
assert m.with_alias(*init_args).val == expected
@pytest.mark.parametrize(
"num_init_args, smart_ptr",
[
(4, "std::unique_ptr"),
(5, "std::shared_ptr"),
],
)
def test_with_alias_invalid(num_init_args, smart_ptr):
class PyDrvdWithAlias(m.with_alias):
pass
with pytest.raises(TypeError) as excinfo:
PyDrvdWithAlias(*((0,) * num_init_args))
assert (
str(excinfo.value)
== "pybind11::init(): construction failed: returned "
+ smart_ptr
+ " pointee is not an alias instance"
)
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment