File indexing completed on 2026-04-01 08:27:28
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010 #pragma once
0011
0012 #include "class.h"
0013 #include "using_smart_holder.h"
0014
0015 PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
0016
0017 PYBIND11_WARNING_DISABLE_MSVC(4127)
0018
0019 PYBIND11_NAMESPACE_BEGIN(detail)
0020
0021 template <>
0022 class type_caster<value_and_holder> {
0023 public:
0024 bool load(handle h, bool) {
0025 value = reinterpret_cast<value_and_holder *>(h.ptr());
0026 return true;
0027 }
0028
0029 template <typename>
0030 using cast_op_type = value_and_holder &;
0031 explicit operator value_and_holder &() { return *value; }
0032 static constexpr auto name = const_name<value_and_holder>();
0033
0034 private:
0035 value_and_holder *value = nullptr;
0036 };
0037
0038 PYBIND11_NAMESPACE_BEGIN(initimpl)
0039
0040 inline void no_nullptr(const void *ptr) {
0041 if (!ptr) {
0042 throw type_error("pybind11::init(): factory function returned nullptr");
0043 }
0044 }
0045
0046
0047 template <typename Class>
0048 using Cpp = typename Class::type;
0049 template <typename Class>
0050 using Alias = typename Class::type_alias;
0051 template <typename Class>
0052 using Holder = typename Class::holder_type;
0053
0054 template <typename Class>
0055 using is_alias_constructible = std::is_constructible<Alias<Class>, Cpp<Class> &&>;
0056
0057
0058 template <typename Class, enable_if_t<Class::has_alias, int> = 0>
0059 bool is_alias(Cpp<Class> *ptr) {
0060 return dynamic_cast<Alias<Class> *>(ptr) != nullptr;
0061 }
0062
0063 template <typename >
0064 constexpr bool is_alias(const void *) {
0065 return false;
0066 }
0067
0068
0069
0070
0071
0072
0073 template <typename Class,
0074 typename... Args,
0075 detail::enable_if_t<std::is_constructible<Class, Args...>::value, int> = 0>
0076 inline Class *construct_or_initialize(Args &&...args) {
0077 return new Class(std::forward<Args>(args)...);
0078 }
0079 template <typename Class,
0080 typename... Args,
0081 detail::enable_if_t<!std::is_constructible<Class, Args...>::value, int> = 0>
0082 inline Class *construct_or_initialize(Args &&...args) {
0083 return new Class{std::forward<Args>(args)...};
0084 }
0085
0086
0087
0088
0089
0090
0091 template <typename Class>
0092 void construct_alias_from_cpp(std::true_type ,
0093 value_and_holder &v_h,
0094 Cpp<Class> &&base) {
0095 v_h.value_ptr() = new Alias<Class>(std::move(base));
0096 }
0097 template <typename Class>
0098 [[noreturn]] void construct_alias_from_cpp(std::false_type ,
0099 value_and_holder &,
0100 Cpp<Class> &&) {
0101 throw type_error("pybind11::init(): unable to convert returned instance to required "
0102 "alias class: no `Alias<Class>(Class &&)` constructor available");
0103 }
0104
0105
0106
0107 template <typename Class>
0108 void construct(...) {
0109 static_assert(!std::is_same<Class, Class>::value ,
0110 "pybind11::init(): init function must return a compatible pointer, "
0111 "holder, or value");
0112 }
0113
0114
0115
0116
0117
0118 template <typename Class>
0119 void construct(value_and_holder &v_h, Cpp<Class> *ptr, bool need_alias) {
0120 PYBIND11_WORKAROUND_INCORRECT_MSVC_C4100(need_alias);
0121 no_nullptr(ptr);
0122 if (Class::has_alias && need_alias && !is_alias<Class>(ptr)) {
0123
0124
0125
0126
0127
0128
0129
0130
0131 v_h.value_ptr() = ptr;
0132 v_h.set_instance_registered(true);
0133
0134 v_h.type->init_instance(v_h.inst, nullptr);
0135 Holder<Class> temp_holder(std::move(v_h.holder<Holder<Class>>()));
0136 v_h.type->dealloc(v_h);
0137 v_h.set_instance_registered(false);
0138
0139
0140 construct_alias_from_cpp<Class>(is_alias_constructible<Class>{}, v_h, std::move(*ptr));
0141 } else {
0142
0143 v_h.value_ptr() = ptr;
0144 }
0145 }
0146
0147
0148
0149 template <typename Class, enable_if_t<Class::has_alias, int> = 0>
0150 void construct(value_and_holder &v_h, Alias<Class> *alias_ptr, bool) {
0151 no_nullptr(alias_ptr);
0152 v_h.value_ptr() = static_cast<Cpp<Class> *>(alias_ptr);
0153 }
0154
0155
0156
0157
0158
0159 template <typename Class, detail::enable_if_t<!is_smart_holder<Holder<Class>>::value, int> = 0>
0160 void construct(value_and_holder &v_h, Holder<Class> holder, bool need_alias) {
0161 PYBIND11_WORKAROUND_INCORRECT_MSVC_C4100(need_alias);
0162 auto *ptr = holder_helper<Holder<Class>>::get(holder);
0163 no_nullptr(ptr);
0164
0165 if (Class::has_alias && need_alias && !is_alias<Class>(ptr)) {
0166 throw type_error("pybind11::init(): construction failed: returned holder-wrapped instance "
0167 "is not an alias instance");
0168 }
0169
0170
0171
0172
0173
0174
0175 v_h.value_ptr() = const_cast<void *>(static_cast<const void *>(ptr));
0176 v_h.type->init_instance(v_h.inst, &holder);
0177 }
0178
0179
0180
0181
0182
0183 template <typename Class>
0184 void construct(value_and_holder &v_h, Cpp<Class> &&result, bool need_alias) {
0185 PYBIND11_WORKAROUND_INCORRECT_MSVC_C4100(need_alias);
0186 static_assert(is_move_constructible<Cpp<Class>>::value,
0187 "pybind11::init() return-by-value factory function requires a movable class");
0188 if (Class::has_alias && need_alias) {
0189 construct_alias_from_cpp<Class>(is_alias_constructible<Class>{}, v_h, std::move(result));
0190 } else {
0191 v_h.value_ptr() = new Cpp<Class>(std::move(result));
0192 }
0193 }
0194
0195
0196
0197
0198 template <typename Class>
0199 void construct(value_and_holder &v_h, Alias<Class> &&result, bool) {
0200 static_assert(
0201 is_move_constructible<Alias<Class>>::value,
0202 "pybind11::init() return-by-alias-value factory function requires a movable alias class");
0203 v_h.value_ptr() = new Alias<Class>(std::move(result));
0204 }
0205
0206 template <typename T, typename D>
0207 smart_holder init_smart_holder_from_unique_ptr(std::unique_ptr<T, D> &&unq_ptr,
0208 bool void_cast_raw_ptr) {
0209 void *void_ptr = void_cast_raw_ptr ? static_cast<void *>(unq_ptr.get()) : nullptr;
0210 return smart_holder::from_unique_ptr(std::move(unq_ptr), void_ptr);
0211 }
0212
0213 template <typename Class,
0214 typename D = std::default_delete<Cpp<Class>>,
0215 detail::enable_if_t<is_smart_holder<Holder<Class>>::value, int> = 0>
0216 void construct(value_and_holder &v_h, std::unique_ptr<Cpp<Class>, D> &&unq_ptr, bool need_alias) {
0217 PYBIND11_WORKAROUND_INCORRECT_MSVC_C4100(need_alias);
0218 auto *ptr = unq_ptr.get();
0219 no_nullptr(ptr);
0220 if (Class::has_alias && need_alias && !is_alias<Class>(ptr)) {
0221 throw type_error("pybind11::init(): construction failed: returned std::unique_ptr pointee "
0222 "is not an alias instance");
0223 }
0224
0225
0226
0227
0228
0229 auto smhldr = init_smart_holder_from_unique_ptr(
0230 std::move(unq_ptr), Class::has_alias && is_alias<Class>(ptr));
0231 v_h.value_ptr() = ptr;
0232 v_h.type->init_instance(v_h.inst, &smhldr);
0233 }
0234
0235 template <typename Class,
0236 typename D = std::default_delete<Alias<Class>>,
0237 detail::enable_if_t<is_smart_holder<Holder<Class>>::value, int> = 0>
0238 void construct(value_and_holder &v_h,
0239 std::unique_ptr<Alias<Class>, D> &&unq_ptr,
0240 bool ) {
0241 auto *ptr = unq_ptr.get();
0242 no_nullptr(ptr);
0243 auto smhldr
0244 = init_smart_holder_from_unique_ptr(std::move(unq_ptr), true);
0245 v_h.value_ptr() = ptr;
0246 v_h.type->init_instance(v_h.inst, &smhldr);
0247 }
0248
0249 template <typename PtrType, typename Class>
0250 void construct_from_shared_ptr(value_and_holder &v_h,
0251 std::shared_ptr<PtrType> &&shd_ptr,
0252 bool need_alias) {
0253 static_assert(std::is_same<PtrType, Cpp<Class>>::value
0254 || std::is_same<PtrType, const Cpp<Class>>::value,
0255 "Expected (const) Cpp<Class> as shared_ptr pointee");
0256 auto *ptr = shd_ptr.get();
0257 no_nullptr(ptr);
0258 if (Class::has_alias && need_alias && !is_alias<Class>(ptr)) {
0259 throw type_error("pybind11::init(): construction failed: returned std::shared_ptr pointee "
0260 "is not an alias instance");
0261 }
0262
0263 auto smhldr
0264 = smart_holder::from_shared_ptr(std::const_pointer_cast<Cpp<Class>>(std::move(shd_ptr)));
0265 v_h.value_ptr() = const_cast<Cpp<Class> *>(ptr);
0266 v_h.type->init_instance(v_h.inst, &smhldr);
0267 }
0268
0269 template <typename Class, detail::enable_if_t<is_smart_holder<Holder<Class>>::value, int> = 0>
0270 void construct(value_and_holder &v_h, std::shared_ptr<Cpp<Class>> &&shd_ptr, bool need_alias) {
0271 construct_from_shared_ptr<Cpp<Class>, Class>(v_h, std::move(shd_ptr), need_alias);
0272 }
0273
0274 template <typename Class, detail::enable_if_t<is_smart_holder<Holder<Class>>::value, int> = 0>
0275 void construct(value_and_holder &v_h,
0276 std::shared_ptr<const Cpp<Class>> &&shd_ptr,
0277 bool need_alias) {
0278 construct_from_shared_ptr<const Cpp<Class>, Class>(v_h, std::move(shd_ptr), need_alias);
0279 }
0280
0281 template <typename Class, detail::enable_if_t<is_smart_holder<Holder<Class>>::value, int> = 0>
0282 void construct(value_and_holder &v_h,
0283 std::shared_ptr<Alias<Class>> &&shd_ptr,
0284 bool ) {
0285 auto *ptr = shd_ptr.get();
0286 no_nullptr(ptr);
0287 auto smhldr = smart_holder::from_shared_ptr(shd_ptr);
0288 v_h.value_ptr() = ptr;
0289 v_h.type->init_instance(v_h.inst, &smhldr);
0290 }
0291
0292
0293 template <typename... Args>
0294 struct constructor {
0295 template <typename Class, typename... Extra, enable_if_t<!Class::has_alias, int> = 0>
0296 static void execute(Class &cl, const Extra &...extra) {
0297 cl.def(
0298 "__init__",
0299 [](value_and_holder &v_h,
0300 Args... args) {
0301 v_h.value_ptr() = construct_or_initialize<Cpp<Class>>(std::forward<Args>(args)...);
0302 },
0303 is_new_style_constructor(),
0304 extra...);
0305 }
0306
0307 template <
0308 typename Class,
0309 typename... Extra,
0310 enable_if_t<Class::has_alias && std::is_constructible<Cpp<Class>, Args...>::value, int>
0311 = 0>
0312 static void execute(Class &cl, const Extra &...extra) {
0313 cl.def(
0314 "__init__",
0315 [](value_and_holder &v_h, Args... args) {
0316 if (Py_TYPE(v_h.inst) == v_h.type->type) {
0317 v_h.value_ptr()
0318 = construct_or_initialize<Cpp<Class>>(std::forward<Args>(args)...);
0319 } else {
0320 v_h.value_ptr()
0321 = construct_or_initialize<Alias<Class>>(std::forward<Args>(args)...);
0322 }
0323 },
0324 is_new_style_constructor(),
0325 extra...);
0326 }
0327
0328 template <
0329 typename Class,
0330 typename... Extra,
0331 enable_if_t<Class::has_alias && !std::is_constructible<Cpp<Class>, Args...>::value, int>
0332 = 0>
0333 static void execute(Class &cl, const Extra &...extra) {
0334 cl.def(
0335 "__init__",
0336 [](value_and_holder &v_h, Args... args) {
0337 v_h.value_ptr()
0338 = construct_or_initialize<Alias<Class>>(std::forward<Args>(args)...);
0339 },
0340 is_new_style_constructor(),
0341 extra...);
0342 }
0343 };
0344
0345
0346 template <typename... Args>
0347 struct alias_constructor {
0348 template <
0349 typename Class,
0350 typename... Extra,
0351 enable_if_t<Class::has_alias && std::is_constructible<Alias<Class>, Args...>::value, int>
0352 = 0>
0353 static void execute(Class &cl, const Extra &...extra) {
0354 cl.def(
0355 "__init__",
0356 [](value_and_holder &v_h, Args... args) {
0357 v_h.value_ptr()
0358 = construct_or_initialize<Alias<Class>>(std::forward<Args>(args)...);
0359 },
0360 is_new_style_constructor(),
0361 extra...);
0362 }
0363 };
0364
0365
0366 template <typename CFunc,
0367 typename AFunc = void_type (*)(),
0368 typename = function_signature_t<CFunc>,
0369 typename = function_signature_t<AFunc>>
0370 struct factory;
0371
0372
0373 template <typename Func, typename Return, typename... Args>
0374 struct factory<Func, void_type (*)(), Return(Args...)> {
0375 remove_reference_t<Func> class_factory;
0376
0377
0378 factory(Func &&f) : class_factory(std::forward<Func>(f)) {}
0379
0380
0381
0382
0383
0384
0385 template <typename Class, typename... Extra>
0386 void execute(Class &cl, const Extra &...extra) && {
0387 #if defined(PYBIND11_CPP14)
0388 cl.def(
0389 "__init__",
0390 [func = std::move(class_factory)]
0391 #else
0392 auto &func = class_factory;
0393 cl.def(
0394 "__init__",
0395 [func]
0396 #endif
0397 (value_and_holder &v_h, Args... args) {
0398 construct<Class>(
0399 v_h, func(std::forward<Args>(args)...), Py_TYPE(v_h.inst) != v_h.type->type);
0400 },
0401 is_new_style_constructor(),
0402 extra...);
0403 }
0404 };
0405
0406
0407 template <typename CFunc,
0408 typename AFunc,
0409 typename CReturn,
0410 typename... CArgs,
0411 typename AReturn,
0412 typename... AArgs>
0413 struct factory<CFunc, AFunc, CReturn(CArgs...), AReturn(AArgs...)> {
0414 static_assert(sizeof...(CArgs) == sizeof...(AArgs),
0415 "pybind11::init(class_factory, alias_factory): class and alias factories "
0416 "must have identical argument signatures");
0417 static_assert(all_of<std::is_same<CArgs, AArgs>...>::value,
0418 "pybind11::init(class_factory, alias_factory): class and alias factories "
0419 "must have identical argument signatures");
0420
0421 remove_reference_t<CFunc> class_factory;
0422 remove_reference_t<AFunc> alias_factory;
0423
0424 factory(CFunc &&c, AFunc &&a)
0425 : class_factory(std::forward<CFunc>(c)), alias_factory(std::forward<AFunc>(a)) {}
0426
0427
0428
0429 template <typename Class, typename... Extra>
0430 void execute(Class &cl, const Extra &...extra) && {
0431 static_assert(Class::has_alias,
0432 "The two-argument version of `py::init()` can "
0433 "only be used if the class has an alias");
0434 #if defined(PYBIND11_CPP14)
0435 cl.def(
0436 "__init__",
0437 [class_func = std::move(class_factory), alias_func = std::move(alias_factory)]
0438 #else
0439 auto &class_func = class_factory;
0440 auto &alias_func = alias_factory;
0441 cl.def(
0442 "__init__",
0443 [class_func, alias_func]
0444 #endif
0445 (value_and_holder &v_h, CArgs... args) {
0446 if (Py_TYPE(v_h.inst) == v_h.type->type) {
0447
0448
0449 construct<Class>(v_h, class_func(std::forward<CArgs>(args)...), false);
0450 } else {
0451 construct<Class>(v_h, alias_func(std::forward<CArgs>(args)...), true);
0452 }
0453 },
0454 is_new_style_constructor(),
0455 extra...);
0456 }
0457 };
0458
0459
0460 template <typename Class, typename T>
0461 void setstate(value_and_holder &v_h, T &&result, bool need_alias) {
0462 construct<Class>(v_h, std::forward<T>(result), need_alias);
0463 }
0464
0465
0466 template <typename Class,
0467 typename T,
0468 typename O,
0469 enable_if_t<std::is_convertible<O, handle>::value, int> = 0>
0470 void setstate(value_and_holder &v_h, std::pair<T, O> &&result, bool need_alias) {
0471 construct<Class>(v_h, std::move(result.first), need_alias);
0472 auto d = handle(result.second);
0473 if (PyDict_Check(d.ptr()) && PyDict_Size(d.ptr()) == 0) {
0474
0475
0476 return;
0477 }
0478
0479 auto dict = getattr((PyObject *) v_h.inst, "__dict__", none());
0480 if (dict.is_none()) {
0481 setattr((PyObject *) v_h.inst, "__dict__", d);
0482 } else {
0483
0484 if (PyDict_Update(dict.ptr(), d.ptr()) < 0) {
0485 throw error_already_set();
0486 }
0487 }
0488 }
0489
0490
0491 template <typename Get,
0492 typename Set,
0493 typename = function_signature_t<Get>,
0494 typename = function_signature_t<Set>>
0495 struct pickle_factory;
0496
0497 template <typename Get,
0498 typename Set,
0499 typename RetState,
0500 typename Self,
0501 typename NewInstance,
0502 typename ArgState>
0503 struct pickle_factory<Get, Set, RetState(Self), NewInstance(ArgState)> {
0504 static_assert(std::is_same<intrinsic_t<RetState>, intrinsic_t<ArgState>>::value,
0505 "The type returned by `__getstate__` must be the same "
0506 "as the argument accepted by `__setstate__`");
0507
0508 remove_reference_t<Get> get;
0509 remove_reference_t<Set> set;
0510
0511 pickle_factory(Get get, Set set) : get(std::forward<Get>(get)), set(std::forward<Set>(set)) {}
0512
0513 template <typename Class, typename... Extra>
0514 void execute(Class &cl, const Extra &...extra) && {
0515 cl.def("__getstate__", std::move(get), pos_only());
0516
0517 #if defined(PYBIND11_CPP14)
0518 cl.def(
0519 "__setstate__",
0520 [func = std::move(set)]
0521 #else
0522 auto &func = set;
0523 cl.def(
0524 "__setstate__",
0525 [func]
0526 #endif
0527 (value_and_holder &v_h, ArgState state) {
0528 setstate<Class>(
0529 v_h, func(std::forward<ArgState>(state)), Py_TYPE(v_h.inst) != v_h.type->type);
0530 },
0531 is_new_style_constructor(),
0532 extra...);
0533 }
0534 };
0535
0536 PYBIND11_NAMESPACE_END(initimpl)
0537 PYBIND11_NAMESPACE_END(detail)
0538 PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)