Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 10:06:12

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 
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 // Implementing functions for all forms of py::init<...> and py::init(...)
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 // Takes a Cpp pointer and returns true if it actually is a polymorphic Alias instance.
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 // Failing fallback version of the above for a no-alias class (always returns false)
0062 template <typename /*Class*/>
0063 constexpr bool is_alias(void *) {
0064     return false;
0065 }
0066 
0067 // Constructs and returns a new object; if the given arguments don't map to a constructor, we fall
0068 // back to brace aggregate initialization so that for aggregate initialization can be used with
0069 // py::init, e.g.  `py::init<int, int>` to initialize a `struct T { int a; int b; }`.  For
0070 // non-aggregate types, we need to use an ordinary T(...) constructor (invoking as `T{...}` usually
0071 // works, but will not do the expected thing when `T` has an `initializer_list<T>` constructor).
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 // Attempts to constructs an alias using a `Alias(Cpp &&)` constructor.  This allows types with
0086 // an alias to provide only a single Cpp factory function as long as the Alias can be
0087 // constructed from an rvalue reference of the base Cpp type.  This means that Alias classes
0088 // can, when appropriate, simply define a `Alias(Cpp &&)` constructor rather than needing to
0089 // inherit all the base class constructors.
0090 template <typename Class>
0091 void construct_alias_from_cpp(std::true_type /*is_alias_constructible*/,
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 /*!is_alias_constructible*/,
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 // Error-generating fallback for factories that don't match one of the below construction
0105 // mechanisms.
0106 template <typename Class>
0107 void construct(...) {
0108     static_assert(!std::is_same<Class, Class>::value /* always false */,
0109                   "pybind11::init(): init function must return a compatible pointer, "
0110                   "holder, or value");
0111 }
0112 
0113 // Pointer return v1: the factory function returns a class pointer for a registered class.
0114 // If we don't need an alias (because this class doesn't have one, or because the final type is
0115 // inherited on the Python side) we can simply take over ownership.  Otherwise we need to try to
0116 // construct an Alias from the returned base instance.
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         // We're going to try to construct an alias by moving the cpp type.  Whether or not
0123         // that succeeds, we still need to destroy the original cpp pointer (either the
0124         // moved away leftover, if the alias construction works, or the value itself if we
0125         // throw an error), but we can't just call `delete ptr`: it might have a special
0126         // deleter, or might be shared_from_this.  So we construct a holder around it as if
0127         // it was a normal instance, then steal the holder away into a local variable; thus
0128         // the holder and destruction happens when we leave the C++ scope, and the holder
0129         // class gets to handle the destruction however it likes.
0130         v_h.value_ptr() = ptr;
0131         v_h.set_instance_registered(true); // Trick to prevent init_instance from registering it
0132         // DANGER ZONE BEGIN: exceptions will leave v_h in an invalid state.
0133         v_h.type->init_instance(v_h.inst, nullptr);                        // Set up the holder
0134         Holder<Class> temp_holder(std::move(v_h.holder<Holder<Class>>())); // Steal the holder
0135         v_h.type->dealloc(v_h); // Destroys the moved-out holder remains, resets value ptr to null
0136         v_h.set_instance_registered(false);
0137         // DANGER ZONE END.
0138 
0139         construct_alias_from_cpp<Class>(is_alias_constructible<Class>{}, v_h, std::move(*ptr));
0140     } else {
0141         // Otherwise the type isn't inherited, so we don't need an Alias
0142         v_h.value_ptr() = ptr;
0143     }
0144 }
0145 
0146 // Pointer return v2: a factory that always returns an alias instance ptr.  We simply take over
0147 // ownership of the pointer.
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 // Holder return: copy its pointer, and move or copy the returned holder into the new instance's
0155 // holder.  This also handles types like std::shared_ptr<T> and std::unique_ptr<T> where T is a
0156 // derived type (through those holder's implicit conversion from derived class holder
0157 // constructors).
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     // If we need an alias, check that the held pointer is actually an alias instance
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 // return-by-value version 1: returning a cpp class by value.  If the class has an alias and an
0174 // alias is required the alias must have an `Alias(Cpp &&)` constructor so that we can construct
0175 // the alias from the base when needed (i.e. because of Python-side inheritance).  When we don't
0176 // need it, we simply move-construct the cpp value into a new instance.
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 // return-by-value version 2: returning a value of the alias type itself.  We move-construct an
0190 // Alias instance (even if no the python-side inheritance is involved).  The is intended for
0191 // cases where Alias initialization is always desired.
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 // Implementing class for py::init<...>()
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 // Implementing class for py::init_alias<...>()
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 // Implementation class for py::init(Func) and py::init(Func, AliasFunc)
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 // Specialization for py::init(Func)
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     // NOLINTNEXTLINE(google-explicit-constructor)
0285     factory(Func &&f) : class_factory(std::forward<Func>(f)) {}
0286 
0287     // The given class either has no alias or has no separate alias factory;
0288     // this always constructs the class itself.  If the class is registered with an alias
0289     // type and an alias instance is needed (i.e. because the final type is a Python class
0290     // inheriting from the C++ type) the returned value needs to either already be an alias
0291     // instance, or the alias needs to be constructible from a `Class &&` argument.
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 // Specialization for py::init(Func, AliasFunc)
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     // The class factory is called when the `self` type passed to `__init__` is the direct
0335     // class (i.e. not inherited), the alias factory when `self` is a Python-side subtype.
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                     // If the instance type equals the registered type we don't have inheritance,
0355                     // so don't need the alias and can construct using the class function:
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 /// Set just the C++ state. Same as `__init__`.
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 /// Set both the C++ and Python states
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         // Skipping setattr below, to not force use of py::dynamic_attr() for Class unnecessarily.
0382         // See PR #2972 for details.
0383         return;
0384     }
0385     setattr((PyObject *) v_h.inst, "__dict__", d);
0386 }
0387 
0388 /// Implementation for py::pickle(GetState, SetState)
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)