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