init.h revision 12391:ceeca8b41e4b
1/*
2    pybind11/detail/init.h: init factory function implementation and support code.
3
4    Copyright (c) 2017 Jason Rhinelander <jason@imaginary.ca>
5
6    All rights reserved. Use of this source code is governed by a
7    BSD-style license that can be found in the LICENSE file.
8*/
9
10#pragma once
11
12#include "class.h"
13
14NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
15NAMESPACE_BEGIN(detail)
16
17template <>
18class type_caster<value_and_holder> {
19public:
20    bool load(handle h, bool) {
21        value = reinterpret_cast<value_and_holder *>(h.ptr());
22        return true;
23    }
24
25    template <typename> using cast_op_type = value_and_holder &;
26    operator value_and_holder &() { return *value; }
27    static PYBIND11_DESCR name() { return type_descr(_<value_and_holder>()); }
28
29private:
30    value_and_holder *value = nullptr;
31};
32
33NAMESPACE_BEGIN(initimpl)
34
35inline void no_nullptr(void *ptr) {
36    if (!ptr) throw type_error("pybind11::init(): factory function returned nullptr");
37}
38
39// Implementing functions for all forms of py::init<...> and py::init(...)
40template <typename Class> using Cpp = typename Class::type;
41template <typename Class> using Alias = typename Class::type_alias;
42template <typename Class> using Holder = typename Class::holder_type;
43
44template <typename Class> using is_alias_constructible = std::is_constructible<Alias<Class>, Cpp<Class> &&>;
45
46// Takes a Cpp pointer and returns true if it actually is a polymorphic Alias instance.
47template <typename Class, enable_if_t<Class::has_alias, int> = 0>
48bool is_alias(Cpp<Class> *ptr) {
49    return dynamic_cast<Alias<Class> *>(ptr) != nullptr;
50}
51// Failing fallback version of the above for a no-alias class (always returns false)
52template <typename /*Class*/>
53constexpr bool is_alias(void *) { return false; }
54
55// Attempts to constructs an alias using a `Alias(Cpp &&)` constructor.  This allows types with
56// an alias to provide only a single Cpp factory function as long as the Alias can be
57// constructed from an rvalue reference of the base Cpp type.  This means that Alias classes
58// can, when appropriate, simply define a `Alias(Cpp &&)` constructor rather than needing to
59// inherit all the base class constructors.
60template <typename Class>
61void construct_alias_from_cpp(std::true_type /*is_alias_constructible*/,
62                              value_and_holder &v_h, Cpp<Class> &&base) {
63    v_h.value_ptr() = new Alias<Class>(std::move(base));
64}
65template <typename Class>
66[[noreturn]] void construct_alias_from_cpp(std::false_type /*!is_alias_constructible*/,
67                                           value_and_holder &, Cpp<Class> &&) {
68    throw type_error("pybind11::init(): unable to convert returned instance to required "
69                     "alias class: no `Alias<Class>(Class &&)` constructor available");
70}
71
72// Error-generating fallback for factories that don't match one of the below construction
73// mechanisms.
74template <typename Class>
75void construct(...) {
76    static_assert(!std::is_same<Class, Class>::value /* always false */,
77            "pybind11::init(): init function must return a compatible pointer, "
78            "holder, or value");
79}
80
81// Pointer return v1: the factory function returns a class pointer for a registered class.
82// If we don't need an alias (because this class doesn't have one, or because the final type is
83// inherited on the Python side) we can simply take over ownership.  Otherwise we need to try to
84// construct an Alias from the returned base instance.
85template <typename Class>
86void construct(value_and_holder &v_h, Cpp<Class> *ptr, bool need_alias) {
87    no_nullptr(ptr);
88    if (Class::has_alias && need_alias && !is_alias<Class>(ptr)) {
89        // We're going to try to construct an alias by moving the cpp type.  Whether or not
90        // that succeeds, we still need to destroy the original cpp pointer (either the
91        // moved away leftover, if the alias construction works, or the value itself if we
92        // throw an error), but we can't just call `delete ptr`: it might have a special
93        // deleter, or might be shared_from_this.  So we construct a holder around it as if
94        // it was a normal instance, then steal the holder away into a local variable; thus
95        // the holder and destruction happens when we leave the C++ scope, and the holder
96        // class gets to handle the destruction however it likes.
97        v_h.value_ptr() = ptr;
98        v_h.set_instance_registered(true); // To prevent init_instance from registering it
99        v_h.type->init_instance(v_h.inst, nullptr); // Set up the holder
100        Holder<Class> temp_holder(std::move(v_h.holder<Holder<Class>>())); // Steal the holder
101        v_h.type->dealloc(v_h); // Destroys the moved-out holder remains, resets value ptr to null
102        v_h.set_instance_registered(false);
103
104        construct_alias_from_cpp<Class>(is_alias_constructible<Class>{}, v_h, std::move(*ptr));
105    } else {
106        // Otherwise the type isn't inherited, so we don't need an Alias
107        v_h.value_ptr() = ptr;
108    }
109}
110
111// Pointer return v2: a factory that always returns an alias instance ptr.  We simply take over
112// ownership of the pointer.
113template <typename Class, enable_if_t<Class::has_alias, int> = 0>
114void construct(value_and_holder &v_h, Alias<Class> *alias_ptr, bool) {
115    no_nullptr(alias_ptr);
116    v_h.value_ptr() = static_cast<Cpp<Class> *>(alias_ptr);
117}
118
119// Holder return: copy its pointer, and move or copy the returned holder into the new instance's
120// holder.  This also handles types like std::shared_ptr<T> and std::unique_ptr<T> where T is a
121// derived type (through those holder's implicit conversion from derived class holder constructors).
122template <typename Class>
123void construct(value_and_holder &v_h, Holder<Class> holder, bool need_alias) {
124    auto *ptr = holder_helper<Holder<Class>>::get(holder);
125    // If we need an alias, check that the held pointer is actually an alias instance
126    if (Class::has_alias && need_alias && !is_alias<Class>(ptr))
127        throw type_error("pybind11::init(): construction failed: returned holder-wrapped instance "
128                         "is not an alias instance");
129
130    v_h.value_ptr() = ptr;
131    v_h.type->init_instance(v_h.inst, &holder);
132}
133
134// return-by-value version 1: returning a cpp class by value.  If the class has an alias and an
135// alias is required the alias must have an `Alias(Cpp &&)` constructor so that we can construct
136// the alias from the base when needed (i.e. because of Python-side inheritance).  When we don't
137// need it, we simply move-construct the cpp value into a new instance.
138template <typename Class>
139void construct(value_and_holder &v_h, Cpp<Class> &&result, bool need_alias) {
140    static_assert(std::is_move_constructible<Cpp<Class>>::value,
141        "pybind11::init() return-by-value factory function requires a movable class");
142    if (Class::has_alias && need_alias)
143        construct_alias_from_cpp<Class>(is_alias_constructible<Class>{}, v_h, std::move(result));
144    else
145        v_h.value_ptr() = new Cpp<Class>(std::move(result));
146}
147
148// return-by-value version 2: returning a value of the alias type itself.  We move-construct an
149// Alias instance (even if no the python-side inheritance is involved).  The is intended for
150// cases where Alias initialization is always desired.
151template <typename Class>
152void construct(value_and_holder &v_h, Alias<Class> &&result, bool) {
153    static_assert(std::is_move_constructible<Alias<Class>>::value,
154        "pybind11::init() return-by-alias-value factory function requires a movable alias class");
155    v_h.value_ptr() = new Alias<Class>(std::move(result));
156}
157
158// Implementing class for py::init<...>()
159template <typename... Args>
160struct constructor {
161    template <typename Class, typename... Extra, enable_if_t<!Class::has_alias, int> = 0>
162    static void execute(Class &cl, const Extra&... extra) {
163        cl.def("__init__", [](value_and_holder &v_h, Args... args) {
164            v_h.value_ptr() = new Cpp<Class>{std::forward<Args>(args)...};
165        }, is_new_style_constructor(), extra...);
166    }
167
168    template <typename Class, typename... Extra,
169              enable_if_t<Class::has_alias &&
170                          std::is_constructible<Cpp<Class>, Args...>::value, int> = 0>
171    static void execute(Class &cl, const Extra&... extra) {
172        cl.def("__init__", [](value_and_holder &v_h, Args... args) {
173            if (Py_TYPE(v_h.inst) == v_h.type->type)
174                v_h.value_ptr() = new Cpp<Class>{std::forward<Args>(args)...};
175            else
176                v_h.value_ptr() = new Alias<Class>{std::forward<Args>(args)...};
177        }, is_new_style_constructor(), extra...);
178    }
179
180    template <typename Class, typename... Extra,
181              enable_if_t<Class::has_alias &&
182                          !std::is_constructible<Cpp<Class>, Args...>::value, int> = 0>
183    static void execute(Class &cl, const Extra&... extra) {
184        cl.def("__init__", [](value_and_holder &v_h, Args... args) {
185            v_h.value_ptr() = new Alias<Class>{std::forward<Args>(args)...};
186        }, is_new_style_constructor(), extra...);
187    }
188};
189
190// Implementing class for py::init_alias<...>()
191template <typename... Args> struct alias_constructor {
192    template <typename Class, typename... Extra,
193              enable_if_t<Class::has_alias && std::is_constructible<Alias<Class>, Args...>::value, int> = 0>
194    static void execute(Class &cl, const Extra&... extra) {
195        cl.def("__init__", [](value_and_holder &v_h, Args... args) {
196            v_h.value_ptr() = new Alias<Class>{std::forward<Args>(args)...};
197        }, is_new_style_constructor(), extra...);
198    }
199};
200
201// Implementation class for py::init(Func) and py::init(Func, AliasFunc)
202template <typename CFunc, typename AFunc = void_type (*)(),
203          typename = function_signature_t<CFunc>, typename = function_signature_t<AFunc>>
204struct factory;
205
206// Specialization for py::init(Func)
207template <typename Func, typename Return, typename... Args>
208struct factory<Func, void_type (*)(), Return(Args...)> {
209    remove_reference_t<Func> class_factory;
210
211    factory(Func &&f) : class_factory(std::forward<Func>(f)) { }
212
213    // The given class either has no alias or has no separate alias factory;
214    // this always constructs the class itself.  If the class is registered with an alias
215    // type and an alias instance is needed (i.e. because the final type is a Python class
216    // inheriting from the C++ type) the returned value needs to either already be an alias
217    // instance, or the alias needs to be constructible from a `Class &&` argument.
218    template <typename Class, typename... Extra>
219    void execute(Class &cl, const Extra &...extra) && {
220        #if defined(PYBIND11_CPP14)
221        cl.def("__init__", [func = std::move(class_factory)]
222        #else
223        auto &func = class_factory;
224        cl.def("__init__", [func]
225        #endif
226        (value_and_holder &v_h, Args... args) {
227            construct<Class>(v_h, func(std::forward<Args>(args)...),
228                             Py_TYPE(v_h.inst) != v_h.type->type);
229        }, is_new_style_constructor(), extra...);
230    }
231};
232
233// Specialization for py::init(Func, AliasFunc)
234template <typename CFunc, typename AFunc,
235          typename CReturn, typename... CArgs, typename AReturn, typename... AArgs>
236struct factory<CFunc, AFunc, CReturn(CArgs...), AReturn(AArgs...)> {
237    static_assert(sizeof...(CArgs) == sizeof...(AArgs),
238                  "pybind11::init(class_factory, alias_factory): class and alias factories "
239                  "must have identical argument signatures");
240    static_assert(all_of<std::is_same<CArgs, AArgs>...>::value,
241                  "pybind11::init(class_factory, alias_factory): class and alias factories "
242                  "must have identical argument signatures");
243
244    remove_reference_t<CFunc> class_factory;
245    remove_reference_t<AFunc> alias_factory;
246
247    factory(CFunc &&c, AFunc &&a)
248        : class_factory(std::forward<CFunc>(c)), alias_factory(std::forward<AFunc>(a)) { }
249
250    // The class factory is called when the `self` type passed to `__init__` is the direct
251    // class (i.e. not inherited), the alias factory when `self` is a Python-side subtype.
252    template <typename Class, typename... Extra>
253    void execute(Class &cl, const Extra&... extra) && {
254        static_assert(Class::has_alias, "The two-argument version of `py::init()` can "
255                                        "only be used if the class has an alias");
256        #if defined(PYBIND11_CPP14)
257        cl.def("__init__", [class_func = std::move(class_factory), alias_func = std::move(alias_factory)]
258        #else
259        auto &class_func = class_factory;
260        auto &alias_func = alias_factory;
261        cl.def("__init__", [class_func, alias_func]
262        #endif
263        (value_and_holder &v_h, CArgs... args) {
264            if (Py_TYPE(v_h.inst) == v_h.type->type)
265                // If the instance type equals the registered type we don't have inheritance, so
266                // don't need the alias and can construct using the class function:
267                construct<Class>(v_h, class_func(std::forward<CArgs>(args)...), false);
268            else
269                construct<Class>(v_h, alias_func(std::forward<CArgs>(args)...), true);
270        }, is_new_style_constructor(), extra...);
271    }
272};
273
274/// Set just the C++ state. Same as `__init__`.
275template <typename Class, typename T>
276void setstate(value_and_holder &v_h, T &&result, bool need_alias) {
277    construct<Class>(v_h, std::forward<T>(result), need_alias);
278}
279
280/// Set both the C++ and Python states
281template <typename Class, typename T, typename O,
282          enable_if_t<std::is_convertible<O, handle>::value, int> = 0>
283void setstate(value_and_holder &v_h, std::pair<T, O> &&result, bool need_alias) {
284    construct<Class>(v_h, std::move(result.first), need_alias);
285    setattr((PyObject *) v_h.inst, "__dict__", result.second);
286}
287
288/// Implementation for py::pickle(GetState, SetState)
289template <typename Get, typename Set,
290          typename = function_signature_t<Get>, typename = function_signature_t<Set>>
291struct pickle_factory;
292
293template <typename Get, typename Set,
294          typename RetState, typename Self, typename NewInstance, typename ArgState>
295struct pickle_factory<Get, Set, RetState(Self), NewInstance(ArgState)> {
296    static_assert(std::is_same<intrinsic_t<RetState>, intrinsic_t<ArgState>>::value,
297                  "The type returned by `__getstate__` must be the same "
298                  "as the argument accepted by `__setstate__`");
299
300    remove_reference_t<Get> get;
301    remove_reference_t<Set> set;
302
303    pickle_factory(Get get, Set set)
304        : get(std::forward<Get>(get)), set(std::forward<Set>(set)) { }
305
306    template <typename Class, typename... Extra>
307    void execute(Class &cl, const Extra &...extra) && {
308        cl.def("__getstate__", std::move(get));
309
310#if defined(PYBIND11_CPP14)
311        cl.def("__setstate__", [func = std::move(set)]
312#else
313        auto &func = set;
314        cl.def("__setstate__", [func]
315#endif
316        (value_and_holder &v_h, ArgState state) {
317            setstate<Class>(v_h, func(std::forward<ArgState>(state)),
318                            Py_TYPE(v_h.inst) != v_h.type->type);
319        }, is_new_style_constructor(), extra...);
320    }
321};
322
323NAMESPACE_END(initimpl)
324NAMESPACE_END(detail)
325NAMESPACE_END(pybind11)
326