File indexing completed on 2026-01-09 10:20:47
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037
0038
0039
0040
0041
0042
0043
0044
0045
0046
0047
0048
0049 #pragma once
0050
0051 #include "pybind11_namespace_macros.h"
0052
0053 #include <cstring>
0054 #include <functional>
0055 #include <memory>
0056 #include <stdexcept>
0057 #include <string>
0058 #include <type_traits>
0059 #include <typeinfo>
0060 #include <utility>
0061
0062 PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
0063 PYBIND11_NAMESPACE_BEGIN(memory)
0064
0065
0066 static constexpr bool type_has_shared_from_this(...) { return false; }
0067
0068
0069
0070 template <typename T>
0071 static auto type_has_shared_from_this(const T *ptr)
0072 -> decltype(static_cast<const std::enable_shared_from_this<T> *>(ptr), true) {
0073 return true;
0074 }
0075
0076
0077 template <typename T>
0078 static constexpr bool type_has_shared_from_this(const void *) {
0079 return false;
0080 }
0081
0082 struct guarded_delete {
0083
0084 std::weak_ptr<void> released_ptr;
0085 std::function<void(void *)> del_fun;
0086 void (*del_ptr)(void *);
0087 bool use_del_fun;
0088 bool armed_flag;
0089 guarded_delete(std::function<void(void *)> &&del_fun, bool armed_flag)
0090 : del_fun{std::move(del_fun)}, del_ptr{nullptr}, use_del_fun{true},
0091 armed_flag{armed_flag} {}
0092 guarded_delete(void (*del_ptr)(void *), bool armed_flag)
0093 : del_ptr{del_ptr}, use_del_fun{false}, armed_flag{armed_flag} {}
0094 void operator()(void *raw_ptr) const {
0095 if (armed_flag) {
0096 if (use_del_fun) {
0097 del_fun(raw_ptr);
0098 } else {
0099 del_ptr(raw_ptr);
0100 }
0101 }
0102 }
0103 };
0104
0105 inline guarded_delete *get_guarded_delete(const std::shared_ptr<void> &ptr) {
0106 return std::get_deleter<guarded_delete>(ptr);
0107 }
0108
0109 using get_guarded_delete_fn = guarded_delete *(*) (const std::shared_ptr<void> &);
0110
0111 template <typename T, typename std::enable_if<std::is_destructible<T>::value, int>::type = 0>
0112 inline void std_default_delete_if_destructible(void *raw_ptr) {
0113 std::default_delete<T>{}(static_cast<T *>(raw_ptr));
0114 }
0115
0116 template <typename T, typename std::enable_if<!std::is_destructible<T>::value, int>::type = 0>
0117 inline void std_default_delete_if_destructible(void *) {
0118
0119
0120
0121
0122 }
0123
0124 template <typename T>
0125 guarded_delete make_guarded_std_default_delete(bool armed_flag) {
0126 return guarded_delete(std_default_delete_if_destructible<T>, armed_flag);
0127 }
0128
0129 template <typename T, typename D>
0130 struct custom_deleter {
0131
0132 D deleter;
0133 explicit custom_deleter(D &&deleter) : deleter{std::forward<D>(deleter)} {}
0134 void operator()(void *raw_ptr) { deleter(static_cast<T *>(raw_ptr)); }
0135 };
0136
0137 template <typename T, typename D>
0138 guarded_delete make_guarded_custom_deleter(D &&uqp_del, bool armed_flag) {
0139 return guarded_delete(
0140 std::function<void(void *)>(custom_deleter<T, D>(std::forward<D>(uqp_del))), armed_flag);
0141 }
0142
0143 template <typename T, typename D>
0144 constexpr bool uqp_del_is_std_default_delete() {
0145 return std::is_same<D, std::default_delete<T>>::value
0146 || std::is_same<D, std::default_delete<T const>>::value;
0147 }
0148
0149 inline bool type_info_equal_across_dso_boundaries(const std::type_info &a,
0150 const std::type_info &b) {
0151
0152
0153 return a == b || std::strcmp(a.name(), b.name()) == 0;
0154 }
0155
0156 struct smart_holder {
0157
0158 const std::type_info *rtti_uqp_del = nullptr;
0159 std::shared_ptr<void> vptr;
0160 bool vptr_is_using_noop_deleter : 1;
0161 bool vptr_is_using_std_default_delete : 1;
0162 bool vptr_is_external_shared_ptr : 1;
0163 bool is_populated : 1;
0164 bool is_disowned : 1;
0165
0166
0167 smart_holder(smart_holder &&) = default;
0168 smart_holder(const smart_holder &) = delete;
0169 smart_holder &operator=(smart_holder &&) = delete;
0170 smart_holder &operator=(const smart_holder &) = delete;
0171
0172 smart_holder()
0173 : vptr_is_using_noop_deleter{false}, vptr_is_using_std_default_delete{false},
0174 vptr_is_external_shared_ptr{false}, is_populated{false}, is_disowned{false} {}
0175
0176 bool has_pointee() const { return vptr != nullptr; }
0177
0178 template <typename T>
0179 static void ensure_pointee_is_destructible(const char *context) {
0180 if (!std::is_destructible<T>::value) {
0181 throw std::invalid_argument(std::string("Pointee is not destructible (") + context
0182 + ").");
0183 }
0184 }
0185
0186 void ensure_is_populated(const char *context) const {
0187 if (!is_populated) {
0188 throw std::runtime_error(std::string("Unpopulated holder (") + context + ").");
0189 }
0190 }
0191 void ensure_is_not_disowned(const char *context) const {
0192 if (is_disowned) {
0193 throw std::runtime_error(std::string("Holder was disowned already (") + context
0194 + ").");
0195 }
0196 }
0197
0198 void ensure_vptr_is_using_std_default_delete(const char *context) const {
0199 if (vptr_is_external_shared_ptr) {
0200 throw std::invalid_argument(std::string("Cannot disown external shared_ptr (")
0201 + context + ").");
0202 }
0203 if (vptr_is_using_noop_deleter) {
0204 throw std::invalid_argument(std::string("Cannot disown non-owning holder (") + context
0205 + ").");
0206 }
0207 if (!vptr_is_using_std_default_delete) {
0208 throw std::invalid_argument(std::string("Cannot disown custom deleter (") + context
0209 + ").");
0210 }
0211 }
0212
0213 template <typename T, typename D>
0214 void ensure_compatible_uqp_del(const char *context) const {
0215 if (!rtti_uqp_del) {
0216 if (!uqp_del_is_std_default_delete<T, D>()) {
0217 throw std::invalid_argument(std::string("Missing unique_ptr deleter (") + context
0218 + ").");
0219 }
0220 ensure_vptr_is_using_std_default_delete(context);
0221 return;
0222 }
0223 if (uqp_del_is_std_default_delete<T, D>() && vptr_is_using_std_default_delete) {
0224 return;
0225 }
0226 if (!type_info_equal_across_dso_boundaries(typeid(D), *rtti_uqp_del)) {
0227 throw std::invalid_argument(std::string("Incompatible unique_ptr deleter (") + context
0228 + ").");
0229 }
0230 }
0231
0232 void ensure_has_pointee(const char *context) const {
0233 if (!has_pointee()) {
0234 throw std::invalid_argument(std::string("Disowned holder (") + context + ").");
0235 }
0236 }
0237
0238 void ensure_use_count_1(const char *context) const {
0239 if (vptr == nullptr) {
0240 throw std::invalid_argument(std::string("Cannot disown nullptr (") + context + ").");
0241 }
0242
0243
0244
0245
0246
0247 if (vptr.use_count() != 1) {
0248 throw std::invalid_argument(std::string("Cannot disown use_count != 1 (") + context
0249 + ").");
0250 }
0251 }
0252
0253 void reset_vptr_deleter_armed_flag(const get_guarded_delete_fn ggd_fn, bool armed_flag) const {
0254 auto *gd = ggd_fn(vptr);
0255 if (gd == nullptr) {
0256 throw std::runtime_error(
0257 "smart_holder::reset_vptr_deleter_armed_flag() called in an invalid context.");
0258 }
0259 gd->armed_flag = armed_flag;
0260 }
0261
0262
0263 template <typename T, typename D>
0264 std::unique_ptr<D> extract_deleter(const char *context,
0265 const get_guarded_delete_fn ggd_fn) const {
0266 auto *gd = ggd_fn(vptr);
0267 if (gd && gd->use_del_fun) {
0268 const auto &custom_deleter_ptr = gd->del_fun.template target<custom_deleter<T, D>>();
0269 if (custom_deleter_ptr == nullptr) {
0270 throw std::runtime_error(
0271 std::string("smart_holder::extract_deleter() precondition failure (") + context
0272 + ").");
0273 }
0274 static_assert(std::is_copy_constructible<D>::value,
0275 "Required for compatibility with smart_holder functionality.");
0276 return std::unique_ptr<D>(new D(custom_deleter_ptr->deleter));
0277 }
0278 return nullptr;
0279 }
0280
0281 static smart_holder from_raw_ptr_unowned(void *raw_ptr) {
0282 smart_holder hld;
0283 hld.vptr.reset(raw_ptr, [](void *) {});
0284 hld.vptr_is_using_noop_deleter = true;
0285 hld.is_populated = true;
0286 return hld;
0287 }
0288
0289 template <typename T>
0290 T *as_raw_ptr_unowned() const {
0291 return static_cast<T *>(vptr.get());
0292 }
0293
0294 template <typename T>
0295 static smart_holder from_raw_ptr_take_ownership(T *raw_ptr, bool void_cast_raw_ptr = false) {
0296 ensure_pointee_is_destructible<T>("from_raw_ptr_take_ownership");
0297 smart_holder hld;
0298 auto gd = make_guarded_std_default_delete<T>(true);
0299 if (void_cast_raw_ptr) {
0300 hld.vptr.reset(static_cast<void *>(raw_ptr), std::move(gd));
0301 } else {
0302 hld.vptr.reset(raw_ptr, std::move(gd));
0303 }
0304 hld.vptr_is_using_std_default_delete = true;
0305 hld.is_populated = true;
0306 return hld;
0307 }
0308
0309
0310
0311 void disown(const get_guarded_delete_fn ggd_fn) {
0312 reset_vptr_deleter_armed_flag(ggd_fn, false);
0313 is_disowned = true;
0314 }
0315
0316
0317
0318 void reclaim_disowned(const get_guarded_delete_fn ggd_fn) {
0319 reset_vptr_deleter_armed_flag(ggd_fn, true);
0320 is_disowned = false;
0321 }
0322
0323
0324
0325 void release_disowned() { vptr.reset(); }
0326
0327 void ensure_can_release_ownership(const char *context = "ensure_can_release_ownership") const {
0328 ensure_is_not_disowned(context);
0329 ensure_vptr_is_using_std_default_delete(context);
0330 ensure_use_count_1(context);
0331 }
0332
0333
0334
0335 void release_ownership(const get_guarded_delete_fn ggd_fn) {
0336 reset_vptr_deleter_armed_flag(ggd_fn, false);
0337 release_disowned();
0338 }
0339
0340 template <typename T, typename D>
0341 static smart_holder from_unique_ptr(std::unique_ptr<T, D> &&unq_ptr,
0342 void *void_ptr = nullptr) {
0343 smart_holder hld;
0344 hld.rtti_uqp_del = &typeid(D);
0345 hld.vptr_is_using_std_default_delete = uqp_del_is_std_default_delete<T, D>();
0346 guarded_delete gd{nullptr, false};
0347 if (hld.vptr_is_using_std_default_delete) {
0348 gd = make_guarded_std_default_delete<T>(true);
0349 } else {
0350 gd = make_guarded_custom_deleter<T, D>(std::move(unq_ptr.get_deleter()), true);
0351 }
0352 if (void_ptr != nullptr) {
0353 hld.vptr.reset(void_ptr, std::move(gd));
0354 } else {
0355 hld.vptr.reset(unq_ptr.get(), std::move(gd));
0356 }
0357 (void) unq_ptr.release();
0358 hld.is_populated = true;
0359 return hld;
0360 }
0361
0362 template <typename T>
0363 static smart_holder from_shared_ptr(const std::shared_ptr<T> &shd_ptr) {
0364 smart_holder hld;
0365 hld.vptr = std::static_pointer_cast<void>(shd_ptr);
0366 hld.vptr_is_external_shared_ptr = true;
0367 hld.is_populated = true;
0368 return hld;
0369 }
0370
0371 template <typename T>
0372 std::shared_ptr<T> as_shared_ptr() const {
0373 return std::static_pointer_cast<T>(vptr);
0374 }
0375 };
0376
0377 PYBIND11_NAMESPACE_END(memory)
0378 PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)