From 2a94c687ea71947de7dddbeae1036a4ddd390123 Mon Sep 17 00:00:00 2001 From: "Ralf W. Grosse-Kunstleve" Date: Tue, 5 Jan 2021 16:25:25 -0800 Subject: [PATCH] Adding from/as unique_ptr and unique_ptr. --- include/pybind11/smart_holder_poc.h | 139 +++++++++++++++++++++------- tests/test_smart_holder_poc.cpp | 49 ++++++++-- 2 files changed, 149 insertions(+), 39 deletions(-) diff --git a/include/pybind11/smart_holder_poc.h b/include/pybind11/smart_holder_poc.h index 43759ed2d..6ea0aa24d 100644 --- a/include/pybind11/smart_holder_poc.h +++ b/include/pybind11/smart_holder_poc.h @@ -5,26 +5,42 @@ PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE) +template +struct guarded_builtin_delete { + bool* flag_ptr; + explicit guarded_builtin_delete(bool* flag_ptr_) : flag_ptr{flag_ptr_} {} + void operator()(T* raw_ptr) { + if (*flag_ptr) delete raw_ptr; + } +}; + +template +struct guarded_custom_deleter { + bool* flag_ptr; + explicit guarded_custom_deleter(bool* flag_ptr_) : flag_ptr{flag_ptr_} {} + void operator()(T* raw_ptr) { + if (*flag_ptr) D()(raw_ptr); + } +}; + struct smart_holder { std::shared_ptr vptr; const std::type_info* rtti_held; const std::type_info* rtti_uqp_del; bool vptr_deleter_flag; - template - struct vptr_deleter { - bool* flag_ptr; - explicit vptr_deleter(bool* flag_ptr_) : flag_ptr{flag_ptr_} {} - void operator()(T* raw_ptr) { - if (*flag_ptr) delete raw_ptr; - } - }; + void clear() { + vptr.reset(); + vptr_deleter_flag = false; + rtti_held = nullptr; + rtti_uqp_del = nullptr; + } smart_holder() : rtti_held{nullptr}, rtti_uqp_del{nullptr}, vptr_deleter_flag{false} {} template - void ensure_compatible_rtti(const char* context) { + void ensure_compatible_rtti_held(const char* context) { const std::type_info* rtti_requested = &typeid(T); if (!(*rtti_requested == *rtti_held)) { throw std::runtime_error(std::string("Incompatible RTTI (") + context + @@ -32,10 +48,12 @@ struct smart_holder { } } - void ensure_use_count_1(const char* context) { - if (vptr.use_count() != 1) { - throw std::runtime_error(std::string("Cannot disown use_count != 1 (") + - context + ")."); + template + void ensure_compatible_rtti_uqp_del(const char* context) { + const std::type_info* rtti_requested = &typeid(D); + if (!(*rtti_requested == *rtti_uqp_del)) { + throw std::runtime_error( + std::string("Incompatible unique_ptr deleter (") + context + ")."); } } @@ -46,32 +64,89 @@ struct smart_holder { } } - template - void from_raw_ptr_owned(T* raw_ptr) { - vptr_deleter_flag = true; - vptr.reset(raw_ptr, vptr_deleter(&vptr_deleter_flag)); - rtti_held = &typeid(T); - } - - template - T* as_raw_ptr_owned() { - static const char* context = "as_raw_ptr_owned"; - ensure_compatible_rtti(context); - ensure_use_count_1(context); - ensure_vptr_deleter_flag_true(context); - std::shared_ptr tptr = std::static_pointer_cast(vptr); - vptr.reset(); - T* result = tptr.get(); - vptr_deleter_flag = false; - return result; + void ensure_use_count_1(const char* context) { + if (vptr.use_count() != 1) { + throw std::runtime_error(std::string("Cannot disown use_count != 1 (") + + context + ")."); + } } template std::shared_ptr as_shared_ptr() { static const char* context = "as_shared_ptr"; - ensure_compatible_rtti(context); + ensure_compatible_rtti_held(context); return std::static_pointer_cast(vptr); } + + template + void from_raw_ptr_owned(T* raw_ptr) { + clear(); + rtti_held = &typeid(T); + vptr_deleter_flag = true; + vptr.reset(raw_ptr, guarded_builtin_delete(&vptr_deleter_flag)); + } + + template + void from_raw_ptr_unowned(T* raw_ptr) { + clear(); + rtti_held = &typeid(T); + vptr_deleter_flag = false; + vptr.reset(raw_ptr, guarded_builtin_delete(&vptr_deleter_flag)); + } + + template + T* as_raw_ptr_owned(const char* context = "as_raw_ptr_owned") { + ensure_compatible_rtti_held(context); + ensure_vptr_deleter_flag_true(context); + ensure_use_count_1(context); + T* raw_ptr = static_cast(vptr.get()); + vptr_deleter_flag = false; + vptr.reset(); + return raw_ptr; + } + + template + T* as_raw_ptr_unowned() { + static const char* context = "as_raw_ptr_unowned"; + ensure_compatible_rtti_held(context); + return static_cast(vptr.get()); + } + + template + void from_unique_ptr(std::unique_ptr&& unq_ptr) { + clear(); + rtti_held = &typeid(T); + vptr_deleter_flag = true; + vptr.reset(unq_ptr.get(), guarded_builtin_delete(&vptr_deleter_flag)); + unq_ptr.release(); + } + + template + std::unique_ptr as_unique_ptr() { + return std::unique_ptr(as_raw_ptr_owned("as_unique_ptr")); + } + + template + void from_unique_ptr_with_deleter(std::unique_ptr&& unq_ptr) { + clear(); + rtti_held = &typeid(T); + rtti_uqp_del = &typeid(D); + vptr_deleter_flag = true; + vptr.reset(unq_ptr.get(), guarded_custom_deleter(&vptr_deleter_flag)); + unq_ptr.release(); + } + + template + std::unique_ptr as_unique_ptr_with_deleter() { + static const char* context = "as_unique_ptr_with_deleter"; + ensure_compatible_rtti_held(context); + ensure_compatible_rtti_uqp_del(context); + ensure_use_count_1(context); + T* raw_ptr = static_cast(vptr.get()); + vptr_deleter_flag = false; + vptr.reset(); + return std::unique_ptr(raw_ptr); + } }; PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE) diff --git a/tests/test_smart_holder_poc.cpp b/tests/test_smart_holder_poc.cpp index 09db276bb..b26363b37 100644 --- a/tests/test_smart_holder_poc.cpp +++ b/tests/test_smart_holder_poc.cpp @@ -10,19 +10,54 @@ namespace smart_holder_poc { inline void to_cout(std::string msg) { std::cout << msg << std::endl; } +template +struct functor_builtin_delete { + void operator()(T* ptr) { delete ptr; } +}; + inline void exercise() { to_cout(""); namespace py = pybind11; - py::smart_holder hld; - hld.from_raw_ptr_owned(new int(13)); - to_cout(hld.rtti_held->name()); { - std::shared_ptr val = hld.as_shared_ptr(); - to_cout(std::to_string(*val)); + py::smart_holder hld; + hld.from_raw_ptr_owned(new int(13)); + to_cout(hld.rtti_held->name()); + { + std::shared_ptr val = hld.as_shared_ptr(); + to_cout(std::to_string(*val)); + } + { + std::unique_ptr val(hld.as_raw_ptr_owned()); + to_cout(std::to_string(*val)); + } + } // namespace ; + { + std::unique_ptr val(new int(13)); + py::smart_holder hld; + hld.from_raw_ptr_unowned(val.get()); + to_cout(std::to_string(*hld.as_raw_ptr_unowned())); } { - std::unique_ptr val(hld.as_raw_ptr_owned()); - to_cout(std::to_string(*val)); + std::unique_ptr val(new int(13)); + py::smart_holder hld; + hld.from_unique_ptr(std::move(val)); + to_cout(std::to_string(*hld.as_raw_ptr_unowned())); + } + { + py::smart_holder hld; + hld.from_raw_ptr_owned(new int(13)); + to_cout(std::to_string(*hld.as_unique_ptr())); + } + { + std::unique_ptr> unq_ptr(new int(13)); + py::smart_holder hld; + hld.from_unique_ptr_with_deleter(std::move(unq_ptr)); + to_cout(std::to_string(unq_ptr.get() == nullptr)); + to_cout(std::to_string(*hld.as_raw_ptr_unowned())); + auto unq_ptr_retrieved = + hld.as_unique_ptr_with_deleter>(); + to_cout(std::to_string(hld.vptr.get() == nullptr)); + to_cout(std::to_string(*unq_ptr_retrieved)); } }