File indexing completed on 2025-02-23 05:15:01

0001 /*
0002     pybind11/detail/init.h: init factory function implementation and support code.
0003 
0004     Copyright (c) 2017 Jason Rhinelander <jason@imaginary.ca>
0005 
0006     All rights reserved. Use of this source code is governed by a
0007     BSD-style license that can be found in the LICENSE file.
0008 */
0009 
0010 #pragma once
0011 
0012 #include "class.h"
0013 
0014 PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
0015 PYBIND11_NAMESPACE_BEGIN(detail)
0016 
0017 template <>
0018 class type_caster<value_and_holder> {
0019 public:
0020     bool load(handle h, bool) {
0021         value = reinterpret_cast<value_and_holder *>(h.ptr());
0022         return true;
0023     }
0024 
0025     template <typename> using cast_op_type = value_and_holder &;
0026     explicit operator value_and_holder &() { return *value; }
0027     static constexpr auto name = const_name<value_and_holder>();
0028 
0029 private:
0030     value_and_holder *value = nullptr;
0031 };
0032 
0033 PYBIND11_NAMESPACE_BEGIN(initimpl)
0034 
0035 inline void no_nullptr(void *ptr) {
0036     if (!ptr) throw type_error("pybind11::init(): factory function returned nullptr");
0037 }
0038 
0039 // Implementing functions for all forms of py::init<...> and py::init(...)
0040 template <typename Class> using Cpp = typename Class::type;
0041 template <typename Class> using Alias = typename Class::type_alias;
0042 template <typename Class> using Holder = typename Class::holder_type;
0043 
0044 template <typename Class> using is_alias_constructible = std::is_constructible<Alias<Class>, Cpp<Class> &&>;
0045 
0046 // Takes a Cpp pointer and returns true if it actually is a polymorphic Alias instance.
0047 template <typename Class, enable_if_t<Class::has_alias, int> = 0>
0048 bool is_alias(Cpp<Class> *ptr) {
0049     return dynamic_cast<Alias<Class> *>(ptr) != nullptr;
0050 }
0051 // Failing fallback version of the above for a no-alias class (always returns false)
0052 template <typename /*Class*/>
0053 constexpr bool is_alias(void *) { return false; }
0054 
0055 // Constructs and returns a new object; if the given arguments don't map to a constructor, we fall
0056 // back to brace aggregate initiailization so that for aggregate initialization can be used with
0057 // py::init, e.g.  `py::init<int, int>` to initialize a `struct T { int a; int b; }`.  For
0058 // non-aggregate types, we need to use an ordinary T(...) constructor (invoking as `T{...}` usually
0059 // works, but will not do the expected thing when `T` has an `initializer_list<T>` constructor).
0060 template <typename Class, typename... Args, detail::enable_if_t<std::is_constructible<Class, Args...>::value, int> = 0>
0061 inline Class *construct_or_initialize(Args &&...args) { return new Class(std::forward<Args>(args)...); }
0062 template <typename Class, typename... Args, detail::enable_if_t<!std::is_constructible<Class, Args...>::value, int> = 0>
0063 inline Class *construct_or_initialize(Args &&...args) { return new Class{std::forward<Args>(args)...}; }
0064 
0065 // Attempts to constructs an alias using a `Alias(Cpp &&)` constructor.  This allows types with
0066 // an alias to provide only a single Cpp factory function as long as the Alias can be
0067 // constructed from an rvalue reference of the base Cpp type.  This means that Alias classes
0068 // can, when appropriate, simply define a `Alias(Cpp &&)` constructor rather than needing to
0069 // inherit all the base class constructors.
0070 template <typename Class>
0071 void construct_alias_from_cpp(std::true_type /*is_alias_constructible*/,
0072                               value_and_holder &v_h, Cpp<Class> &&base) {
0073     v_h.value_ptr() = new Alias<Class>(std::move(base));
0074 }
0075 template <typename Class>
0076 [[noreturn]] void construct_alias_from_cpp(std::false_type /*!is_alias_constructible*/,
0077                                            value_and_holder &, Cpp<Class> &&) {
0078     throw type_error("pybind11::init(): unable to convert returned instance to required "
0079                      "alias class: no `Alias<Class>(Class &&)` constructor available");
0080 }
0081 
0082 // Error-generating fallback for factories that don't match one of the below construction
0083 // mechanisms.
0084 template <typename Class>
0085 void construct(...) {
0086     static_assert(!std::is_same<Class, Class>::value /* always false */,
0087             "pybind11::init(): init function must return a compatible pointer, "
0088             "holder, or value");
0089 }
0090 
0091 // Pointer return v1: the factory function returns a class pointer for a registered class.
0092 // If we don't need an alias (because this class doesn't have one, or because the final type is
0093 // inherited on the Python side) we can simply take over ownership.  Otherwise we need to try to
0094 // construct an Alias from the returned base instance.
0095 template <typename Class>
0096 void construct(value_and_holder &v_h, Cpp<Class> *ptr, bool need_alias) {
0097     PYBIND11_WORKAROUND_INCORRECT_MSVC_C4100(need_alias);
0098     no_nullptr(ptr);
0099     if (PYBIND11_SILENCE_MSVC_C4127(Class::has_alias) && need_alias && !is_alias<Class>(ptr)) {
0100         // We're going to try to construct an alias by moving the cpp type.  Whether or not
0101         // that succeeds, we still need to destroy the original cpp pointer (either the
0102         // moved away leftover, if the alias construction works, or the value itself if we
0103         // throw an error), but we can't just call `delete ptr`: it might have a special
0104         // deleter, or might be shared_from_this.  So we construct a holder around it as if
0105         // it was a normal instance, then steal the holder away into a local variable; thus
0106         // the holder and destruction happens when we leave the C++ scope, and the holder
0107         // class gets to handle the destruction however it likes.
0108         v_h.value_ptr() = ptr;
0109         v_h.set_instance_registered(true); // To prevent init_instance from registering it
0110         v_h.type->init_instance(v_h.inst, nullptr); // Set up the holder
0111         Holder<Class> temp_holder(std::move(v_h.holder<Holder<Class>>())); // Steal the holder
0112         v_h.type->dealloc(v_h); // Destroys the moved-out holder remains, resets value ptr to null
0113         v_h.set_instance_registered(false);
0114 
0115         construct_alias_from_cpp<Class>(is_alias_constructible<Class>{}, v_h, std::move(*ptr));
0116     } else {
0117         // Otherwise the type isn't inherited, so we don't need an Alias
0118         v_h.value_ptr() = ptr;
0119     }
0120 }
0121 
0122 // Pointer return v2: a factory that always returns an alias instance ptr.  We simply take over
0123 // ownership of the pointer.
0124 template <typename Class, enable_if_t<Class::has_alias, int> = 0>
0125 void construct(value_and_holder &v_h, Alias<Class> *alias_ptr, bool) {
0126     no_nullptr(alias_ptr);
0127     v_h.value_ptr() = static_cast<Cpp<Class> *>(alias_ptr);
0128 }
0129 
0130 // Holder return: copy its pointer, and move or copy the returned holder into the new instance's
0131 // holder.  This also handles types like std::shared_ptr<T> and std::unique_ptr<T> where T is a
0132 // derived type (through those holder's implicit conversion from derived class holder constructors).
0133 template <typename Class>
0134 void construct(value_and_holder &v_h, Holder<Class> holder, bool need_alias) {
0135     PYBIND11_WORKAROUND_INCORRECT_MSVC_C4100(need_alias);
0136     auto *ptr = holder_helper<Holder<Class>>::get(holder);
0137     no_nullptr(ptr);
0138     // If we need an alias, check that the held pointer is actually an alias instance
0139     if (PYBIND11_SILENCE_MSVC_C4127(Class::has_alias) && need_alias && !is_alias<Class>(ptr))
0140         throw type_error("pybind11::init(): construction failed: returned holder-wrapped instance "
0141                          "is not an alias instance");
0142 
0143     v_h.value_ptr() = ptr;
0144     v_h.type->init_instance(v_h.inst, &holder);
0145 }
0146 
0147 // return-by-value version 1: returning a cpp class by value.  If the class has an alias and an
0148 // alias is required the alias must have an `Alias(Cpp &&)` constructor so that we can construct
0149 // the alias from the base when needed (i.e. because of Python-side inheritance).  When we don't
0150 // need it, we simply move-construct the cpp value into a new instance.
0151 template <typename Class>
0152 void construct(value_and_holder &v_h, Cpp<Class> &&result, bool need_alias) {
0153     PYBIND11_WORKAROUND_INCORRECT_MSVC_C4100(need_alias);
0154     static_assert(std::is_move_constructible<Cpp<Class>>::value,
0155         "pybind11::init() return-by-value factory function requires a movable class");
0156     if (PYBIND11_SILENCE_MSVC_C4127(Class::has_alias) && need_alias)
0157         construct_alias_from_cpp<Class>(is_alias_constructible<Class>{}, v_h, std::move(result));
0158     else
0159         v_h.value_ptr() = new Cpp<Class>(std::move(result));
0160 }
0161 
0162 // return-by-value version 2: returning a value of the alias type itself.  We move-construct an
0163 // Alias instance (even if no the python-side inheritance is involved).  The is intended for
0164 // cases where Alias initialization is always desired.
0165 template <typename Class>
0166 void construct(value_and_holder &v_h, Alias<Class> &&result, bool) {
0167     static_assert(std::is_move_constructible<Alias<Class>>::value,
0168         "pybind11::init() return-by-alias-value factory function requires a movable alias class");
0169     v_h.value_ptr() = new Alias<Class>(std::move(result));
0170 }
0171 
0172 // Implementing class for py::init<...>()
0173 template <typename... Args>
0174 struct constructor {
0175     template <typename Class, typename... Extra, enable_if_t<!Class::has_alias, int> = 0>
0176     static void execute(Class &cl, const Extra&... extra) {
0177         cl.def("__init__", [](value_and_holder &v_h, Args... args) {
0178             v_h.value_ptr() = construct_or_initialize<Cpp<Class>>(std::forward<Args>(args)...);
0179         }, is_new_style_constructor(), extra...);
0180     }
0181 
0182     template <typename Class, typename... Extra,
0183               enable_if_t<Class::has_alias &&
0184                           std::is_constructible<Cpp<Class>, Args...>::value, int> = 0>
0185     static void execute(Class &cl, const Extra&... extra) {
0186         cl.def("__init__", [](value_and_holder &v_h, Args... args) {
0187             if (Py_TYPE(v_h.inst) == v_h.type->type)
0188                 v_h.value_ptr() = construct_or_initialize<Cpp<Class>>(std::forward<Args>(args)...);
0189             else
0190                 v_h.value_ptr() = construct_or_initialize<Alias<Class>>(std::forward<Args>(args)...);
0191         }, is_new_style_constructor(), extra...);
0192     }
0193 
0194     template <typename Class, typename... Extra,
0195               enable_if_t<Class::has_alias &&
0196                           !std::is_constructible<Cpp<Class>, Args...>::value, int> = 0>
0197     static void execute(Class &cl, const Extra&... extra) {
0198         cl.def("__init__", [](value_and_holder &v_h, Args... args) {
0199             v_h.value_ptr() = construct_or_initialize<Alias<Class>>(std::forward<Args>(args)...);
0200         }, is_new_style_constructor(), extra...);
0201     }
0202 };
0203 
0204 // Implementing class for py::init_alias<...>()
0205 template <typename... Args> struct alias_constructor {
0206     template <typename Class, typename... Extra,
0207               enable_if_t<Class::has_alias && std::is_constructible<Alias<Class>, Args...>::value, int> = 0>
0208     static void execute(Class &cl, const Extra&... extra) {
0209         cl.def("__init__", [](value_and_holder &v_h, Args... args) {
0210             v_h.value_ptr() = construct_or_initialize<Alias<Class>>(std::forward<Args>(args)...);
0211         }, is_new_style_constructor(), extra...);
0212     }
0213 };
0214 
0215 // Implementation class for py::init(Func) and py::init(Func, AliasFunc)
0216 template <typename CFunc, typename AFunc = void_type (*)(),
0217           typename = function_signature_t<CFunc>, typename = function_signature_t<AFunc>>
0218 struct factory;
0219 
0220 // Specialization for py::init(Func)
0221 template <typename Func, typename Return, typename... Args>
0222 struct factory<Func, void_type (*)(), Return(Args...)> {
0223     remove_reference_t<Func> class_factory;
0224 
0225     // NOLINTNEXTLINE(google-explicit-constructor)
0226     factory(Func &&f) : class_factory(std::forward<Func>(f)) {}
0227 
0228     // The given class either has no alias or has no separate alias factory;
0229     // this always constructs the class itself.  If the class is registered with an alias
0230     // type and an alias instance is needed (i.e. because the final type is a Python class
0231     // inheriting from the C++ type) the returned value needs to either already be an alias
0232     // instance, or the alias needs to be constructible from a `Class &&` argument.
0233     template <typename Class, typename... Extra>
0234     void execute(Class &cl, const Extra &...extra) && {
0235         #if defined(PYBIND11_CPP14)
0236         cl.def("__init__", [func = std::move(class_factory)]
0237         #else
0238         auto &func = class_factory;
0239         cl.def("__init__", [func]
0240         #endif
0241         (value_and_holder &v_h, Args... args) {
0242             construct<Class>(v_h, func(std::forward<Args>(args)...),
0243                              Py_TYPE(v_h.inst) != v_h.type->type);
0244         }, is_new_style_constructor(), extra...);
0245     }
0246 };
0247 
0248 // Specialization for py::init(Func, AliasFunc)
0249 template <typename CFunc, typename AFunc,
0250           typename CReturn, typename... CArgs, typename AReturn, typename... AArgs>
0251 struct factory<CFunc, AFunc, CReturn(CArgs...), AReturn(AArgs...)> {
0252     static_assert(sizeof...(CArgs) == sizeof...(AArgs),
0253                   "pybind11::init(class_factory, alias_factory): class and alias factories "
0254                   "must have identical argument signatures");
0255     static_assert(all_of<std::is_same<CArgs, AArgs>...>::value,
0256                   "pybind11::init(class_factory, alias_factory): class and alias factories "
0257                   "must have identical argument signatures");
0258 
0259     remove_reference_t<CFunc> class_factory;
0260     remove_reference_t<AFunc> alias_factory;
0261 
0262     factory(CFunc &&c, AFunc &&a)
0263         : class_factory(std::forward<CFunc>(c)), alias_factory(std::forward<AFunc>(a)) { }
0264 
0265     // The class factory is called when the `self` type passed to `__init__` is the direct
0266     // class (i.e. not inherited), the alias factory when `self` is a Python-side subtype.
0267     template <typename Class, typename... Extra>
0268     void execute(Class &cl, const Extra&... extra) && {
0269         static_assert(Class::has_alias, "The two-argument version of `py::init()` can "
0270                                         "only be used if the class has an alias");
0271         #if defined(PYBIND11_CPP14)
0272         cl.def("__init__", [class_func = std::move(class_factory), alias_func = std::move(alias_factory)]
0273         #else
0274         auto &class_func = class_factory;
0275         auto &alias_func = alias_factory;
0276         cl.def("__init__", [class_func, alias_func]
0277         #endif
0278         (value_and_holder &v_h, CArgs... args) {
0279             if (Py_TYPE(v_h.inst) == v_h.type->type)
0280                 // If the instance type equals the registered type we don't have inheritance, so
0281                 // don't need the alias and can construct using the class function:
0282                 construct<Class>(v_h, class_func(std::forward<CArgs>(args)...), false);
0283             else
0284                 construct<Class>(v_h, alias_func(std::forward<CArgs>(args)...), true);
0285         }, is_new_style_constructor(), extra...);
0286     }
0287 };
0288 
0289 /// Set just the C++ state. Same as `__init__`.
0290 template <typename Class, typename T>
0291 void setstate(value_and_holder &v_h, T &&result, bool need_alias) {
0292     construct<Class>(v_h, std::forward<T>(result), need_alias);
0293 }
0294 
0295 /// Set both the C++ and Python states
0296 template <typename Class, typename T, typename O,
0297           enable_if_t<std::is_convertible<O, handle>::value, int> = 0>
0298 void setstate(value_and_holder &v_h, std::pair<T, O> &&result, bool need_alias) {
0299     construct<Class>(v_h, std::move(result.first), need_alias);
0300     auto d = handle(result.second);
0301     if (PyDict_Check(d.ptr()) && PyDict_Size(d.ptr()) == 0) {
0302         // Skipping setattr below, to not force use of py::dynamic_attr() for Class unnecessarily.
0303         // See PR #2972 for details.
0304         return;
0305     }
0306     setattr((PyObject *) v_h.inst, "__dict__", d);
0307 }
0308 
0309 /// Implementation for py::pickle(GetState, SetState)
0310 template <typename Get, typename Set,
0311           typename = function_signature_t<Get>, typename = function_signature_t<Set>>
0312 struct pickle_factory;
0313 
0314 template <typename Get, typename Set,
0315           typename RetState, typename Self, typename NewInstance, typename ArgState>
0316 struct pickle_factory<Get, Set, RetState(Self), NewInstance(ArgState)> {
0317     static_assert(std::is_same<intrinsic_t<RetState>, intrinsic_t<ArgState>>::value,
0318                   "The type returned by `__getstate__` must be the same "
0319                   "as the argument accepted by `__setstate__`");
0320 
0321     remove_reference_t<Get> get;
0322     remove_reference_t<Set> set;
0323 
0324     pickle_factory(Get get, Set set)
0325         : get(std::forward<Get>(get)), set(std::forward<Set>(set)) { }
0326 
0327     template <typename Class, typename... Extra>
0328     void execute(Class &cl, const Extra &...extra) && {
0329         cl.def("__getstate__", std::move(get));
0330 
0331 #if defined(PYBIND11_CPP14)
0332         cl.def("__setstate__", [func = std::move(set)]
0333 #else
0334         auto &func = set;
0335         cl.def("__setstate__", [func]
0336 #endif
0337         (value_and_holder &v_h, ArgState state) {
0338             setstate<Class>(v_h, func(std::forward<ArgState>(state)),
0339                             Py_TYPE(v_h.inst) != v_h.type->type);
0340         }, is_new_style_constructor(), extra...);
0341     }
0342 };
0343 
0344 PYBIND11_NAMESPACE_END(initimpl)
0345 PYBIND11_NAMESPACE_END(detail)
0346 PYBIND11_NAMESPACE_END(pybind11)