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