μHAL (v2.8.17)
Part of the IPbus software repository
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
init.h
Go to the documentation of this file.
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
16
17template <>
19public:
20 bool load(handle h, bool) {
21 value = reinterpret_cast<value_and_holder *>(h.ptr());
22 return true;
23 }
24
25 template <typename>
27 explicit operator value_and_holder &() { return *value; }
28 static constexpr auto name = const_name<value_and_holder>();
29
30private:
32};
33
35
36inline void no_nullptr(void *ptr) {
37 if (!ptr) {
38 throw type_error("pybind11::init(): factory function returned nullptr");
39 }
40}
41
42// Implementing functions for all forms of py::init<...> and py::init(...)
43template <typename Class>
44using Cpp = typename Class::type;
45template <typename Class>
46using Alias = typename Class::type_alias;
47template <typename Class>
48using Holder = typename Class::holder_type;
49
50template <typename Class>
51using is_alias_constructible = std::is_constructible<Alias<Class>, Cpp<Class> &&>;
52
53// Takes a Cpp pointer and returns true if it actually is a polymorphic Alias instance.
54template <typename Class, enable_if_t<Class::has_alias, int> = 0>
55bool is_alias(Cpp<Class> *ptr) {
56 return dynamic_cast<Alias<Class> *>(ptr) != nullptr;
57}
58// Failing fallback version of the above for a no-alias class (always returns false)
59template <typename /*Class*/>
60constexpr bool is_alias(void *) {
61 return false;
62}
63
64// Constructs and returns a new object; if the given arguments don't map to a constructor, we fall
65// back to brace aggregate initiailization so that for aggregate initialization can be used with
66// py::init, e.g. `py::init<int, int>` to initialize a `struct T { int a; int b; }`. For
67// non-aggregate types, we need to use an ordinary T(...) constructor (invoking as `T{...}` usually
68// works, but will not do the expected thing when `T` has an `initializer_list<T>` constructor).
69template <typename Class,
70 typename... Args,
71 detail::enable_if_t<std::is_constructible<Class, Args...>::value, int> = 0>
72inline Class *construct_or_initialize(Args &&...args) {
73 return new Class(std::forward<Args>(args)...);
74}
75template <typename Class,
76 typename... Args,
77 detail::enable_if_t<!std::is_constructible<Class, Args...>::value, int> = 0>
78inline Class *construct_or_initialize(Args &&...args) {
79 return new Class{std::forward<Args>(args)...};
80}
81
82// Attempts to constructs an alias using a `Alias(Cpp &&)` constructor. This allows types with
83// an alias to provide only a single Cpp factory function as long as the Alias can be
84// constructed from an rvalue reference of the base Cpp type. This means that Alias classes
85// can, when appropriate, simply define a `Alias(Cpp &&)` constructor rather than needing to
86// inherit all the base class constructors.
87template <typename Class>
88void construct_alias_from_cpp(std::true_type /*is_alias_constructible*/,
90 Cpp<Class> &&base) {
91 v_h.value_ptr() = new Alias<Class>(std::move(base));
92}
93template <typename Class>
94[[noreturn]] void construct_alias_from_cpp(std::false_type ,
96 Cpp<Class> &&) {
97 throw type_error("pybind11::init(): unable to convert returned instance to required "
98 "alias class: no `Alias<Class>(Class &&)` constructor available");
99}
100
101// Error-generating fallback for factories that don't match one of the below construction
102// mechanisms.
103template <typename Class>
104void construct(...) {
105 static_assert(!std::is_same<Class, Class>::value /* always false */,
106 "pybind11::init(): init function must return a compatible pointer, "
107 "holder, or value");
108}
109
110// Pointer return v1: the factory function returns a class pointer for a registered class.
111// If we don't need an alias (because this class doesn't have one, or because the final type is
112// inherited on the Python side) we can simply take over ownership. Otherwise we need to try to
113// construct an Alias from the returned base instance.
114template <typename Class>
115void construct(value_and_holder &v_h, Cpp<Class> *ptr, bool need_alias) {
117 no_nullptr(ptr);
118 if (PYBIND11_SILENCE_MSVC_C4127(Class::has_alias) && need_alias && !is_alias<Class>(ptr)) {
119 // We're going to try to construct an alias by moving the cpp type. Whether or not
120 // that succeeds, we still need to destroy the original cpp pointer (either the
121 // moved away leftover, if the alias construction works, or the value itself if we
122 // throw an error), but we can't just call `delete ptr`: it might have a special
123 // deleter, or might be shared_from_this. So we construct a holder around it as if
124 // it was a normal instance, then steal the holder away into a local variable; thus
125 // the holder and destruction happens when we leave the C++ scope, and the holder
126 // class gets to handle the destruction however it likes.
127 v_h.value_ptr() = ptr;
128 v_h.set_instance_registered(true); // To prevent init_instance from registering it
129 v_h.type->init_instance(v_h.inst, nullptr); // Set up the holder
130 Holder<Class> temp_holder(std::move(v_h.holder<Holder<Class>>())); // Steal the holder
131 v_h.type->dealloc(v_h); // Destroys the moved-out holder remains, resets value ptr to null
132 v_h.set_instance_registered(false);
133
134 construct_alias_from_cpp<Class>(is_alias_constructible<Class>{}, v_h, std::move(*ptr));
135 } else {
136 // Otherwise the type isn't inherited, so we don't need an Alias
137 v_h.value_ptr() = ptr;
138 }
139}
140
141// Pointer return v2: a factory that always returns an alias instance ptr. We simply take over
142// ownership of the pointer.
143template <typename Class, enable_if_t<Class::has_alias, int> = 0>
144void construct(value_and_holder &v_h, Alias<Class> *alias_ptr, bool) {
145 no_nullptr(alias_ptr);
146 v_h.value_ptr() = static_cast<Cpp<Class> *>(alias_ptr);
147}
148
149// Holder return: copy its pointer, and move or copy the returned holder into the new instance's
150// holder. This also handles types like std::shared_ptr<T> and std::unique_ptr<T> where T is a
151// derived type (through those holder's implicit conversion from derived class holder
152// constructors).
153template <typename Class>
154void construct(value_and_holder &v_h, Holder<Class> holder, bool need_alias) {
156 auto *ptr = holder_helper<Holder<Class>>::get(holder);
157 no_nullptr(ptr);
158 // If we need an alias, check that the held pointer is actually an alias instance
159 if (PYBIND11_SILENCE_MSVC_C4127(Class::has_alias) && need_alias && !is_alias<Class>(ptr)) {
160 throw type_error("pybind11::init(): construction failed: returned holder-wrapped instance "
161 "is not an alias instance");
162 }
163
164 v_h.value_ptr() = ptr;
165 v_h.type->init_instance(v_h.inst, &holder);
166}
167
168// return-by-value version 1: returning a cpp class by value. If the class has an alias and an
169// alias is required the alias must have an `Alias(Cpp &&)` constructor so that we can construct
170// the alias from the base when needed (i.e. because of Python-side inheritance). When we don't
171// need it, we simply move-construct the cpp value into a new instance.
172template <typename Class>
173void construct(value_and_holder &v_h, Cpp<Class> &&result, bool need_alias) {
175 static_assert(std::is_move_constructible<Cpp<Class>>::value,
176 "pybind11::init() return-by-value factory function requires a movable class");
177 if (PYBIND11_SILENCE_MSVC_C4127(Class::has_alias) && need_alias) {
178 construct_alias_from_cpp<Class>(is_alias_constructible<Class>{}, v_h, std::move(result));
179 } else {
180 v_h.value_ptr() = new Cpp<Class>(std::move(result));
181 }
182}
183
184// return-by-value version 2: returning a value of the alias type itself. We move-construct an
185// Alias instance (even if no the python-side inheritance is involved). The is intended for
186// cases where Alias initialization is always desired.
187template <typename Class>
188void construct(value_and_holder &v_h, Alias<Class> &&result, bool) {
189 static_assert(
190 std::is_move_constructible<Alias<Class>>::value,
191 "pybind11::init() return-by-alias-value factory function requires a movable alias class");
192 v_h.value_ptr() = new Alias<Class>(std::move(result));
193}
194
195// Implementing class for py::init<...>()
196template <typename... Args>
198 template <typename Class, typename... Extra, enable_if_t<!Class::has_alias, int> = 0>
199 static void execute(Class &cl, const Extra &...extra) {
200 cl.def(
201 "__init__",
202 [](value_and_holder &v_h, Args... args) {
203 v_h.value_ptr() = construct_or_initialize<Cpp<Class>>(std::forward<Args>(args)...);
204 },
206 extra...);
207 }
208
209 template <typename Class,
210 typename... Extra,
212 int> = 0>
213 static void execute(Class &cl, const Extra &...extra) {
214 cl.def(
215 "__init__",
216 [](value_and_holder &v_h, Args... args) {
217 if (Py_TYPE(v_h.inst) == v_h.type->type) {
218 v_h.value_ptr()
219 = construct_or_initialize<Cpp<Class>>(std::forward<Args>(args)...);
220 } else {
221 v_h.value_ptr()
222 = construct_or_initialize<Alias<Class>>(std::forward<Args>(args)...);
223 }
224 },
226 extra...);
227 }
228
229 template <typename Class,
230 typename... Extra,
232 int> = 0>
233 static void execute(Class &cl, const Extra &...extra) {
234 cl.def(
235 "__init__",
236 [](value_and_holder &v_h, Args... args) {
237 v_h.value_ptr()
238 = construct_or_initialize<Alias<Class>>(std::forward<Args>(args)...);
239 },
241 extra...);
242 }
243};
244
245// Implementing class for py::init_alias<...>()
246template <typename... Args>
248 template <typename Class,
249 typename... Extra,
251 int> = 0>
252 static void execute(Class &cl, const Extra &...extra) {
253 cl.def(
254 "__init__",
255 [](value_and_holder &v_h, Args... args) {
256 v_h.value_ptr()
257 = construct_or_initialize<Alias<Class>>(std::forward<Args>(args)...);
258 },
260 extra...);
261 }
262};
263
264// Implementation class for py::init(Func) and py::init(Func, AliasFunc)
265template <typename CFunc,
266 typename AFunc = void_type (*)(),
269struct factory;
270
271// Specialization for py::init(Func)
272template <typename Func, typename Return, typename... Args>
273struct factory<Func, void_type (*)(), Return(Args...)> {
275
276 // NOLINTNEXTLINE(google-explicit-constructor)
277 factory(Func &&f) : class_factory(std::forward<Func>(f)) {}
278
279 // The given class either has no alias or has no separate alias factory;
280 // this always constructs the class itself. If the class is registered with an alias
281 // type and an alias instance is needed (i.e. because the final type is a Python class
282 // inheriting from the C++ type) the returned value needs to either already be an alias
283 // instance, or the alias needs to be constructible from a `Class &&` argument.
284 template <typename Class, typename... Extra>
285 void execute(Class &cl, const Extra &...extra) && {
286#if defined(PYBIND11_CPP14)
287 cl.def(
288 "__init__",
289 [func = std::move(class_factory)]
290#else
291 auto &func = class_factory;
292 cl.def(
293 "__init__",
294 [func]
295#endif
296 (value_and_holder &v_h, Args... args) {
297 construct<Class>(
298 v_h, func(std::forward<Args>(args)...), Py_TYPE(v_h.inst) != v_h.type->type);
299 },
301 extra...);
302 }
303};
304
305// Specialization for py::init(Func, AliasFunc)
306template <typename CFunc,
307 typename AFunc,
308 typename CReturn,
309 typename... CArgs,
310 typename AReturn,
311 typename... AArgs>
312struct factory<CFunc, AFunc, CReturn(CArgs...), AReturn(AArgs...)> {
313 static_assert(sizeof...(CArgs) == sizeof...(AArgs),
314 "pybind11::init(class_factory, alias_factory): class and alias factories "
315 "must have identical argument signatures");
316 static_assert(all_of<std::is_same<CArgs, AArgs>...>::value,
317 "pybind11::init(class_factory, alias_factory): class and alias factories "
318 "must have identical argument signatures");
319
322
323 factory(CFunc &&c, AFunc &&a)
324 : class_factory(std::forward<CFunc>(c)), alias_factory(std::forward<AFunc>(a)) {}
325
326 // The class factory is called when the `self` type passed to `__init__` is the direct
327 // class (i.e. not inherited), the alias factory when `self` is a Python-side subtype.
328 template <typename Class, typename... Extra>
329 void execute(Class &cl, const Extra &...extra) && {
330 static_assert(Class::has_alias,
331 "The two-argument version of `py::init()` can "
332 "only be used if the class has an alias");
333#if defined(PYBIND11_CPP14)
334 cl.def(
335 "__init__",
336 [class_func = std::move(class_factory), alias_func = std::move(alias_factory)]
337#else
338 auto &class_func = class_factory;
339 auto &alias_func = alias_factory;
340 cl.def(
341 "__init__",
342 [class_func, alias_func]
343#endif
344 (value_and_holder &v_h, CArgs... args) {
345 if (Py_TYPE(v_h.inst) == v_h.type->type) {
346 // If the instance type equals the registered type we don't have inheritance,
347 // so don't need the alias and can construct using the class function:
348 construct<Class>(v_h, class_func(std::forward<CArgs>(args)...), false);
349 } else {
350 construct<Class>(v_h, alias_func(std::forward<CArgs>(args)...), true);
351 }
352 },
354 extra...);
355 }
356};
357
359template <typename Class, typename T>
360void setstate(value_and_holder &v_h, T &&result, bool need_alias) {
361 construct<Class>(v_h, std::forward<T>(result), need_alias);
362}
363
365template <typename Class,
366 typename T,
367 typename O,
369void setstate(value_and_holder &v_h, std::pair<T, O> &&result, bool need_alias) {
370 construct<Class>(v_h, std::move(result.first), need_alias);
371 auto d = handle(result.second);
372 if (PyDict_Check(d.ptr()) && PyDict_Size(d.ptr()) == 0) {
373 // Skipping setattr below, to not force use of py::dynamic_attr() for Class unnecessarily.
374 // See PR #2972 for details.
375 return;
376 }
377 setattr((PyObject *) v_h.inst, "__dict__", d);
378}
379
381template <typename Get,
382 typename Set,
383 typename = function_signature_t<Get>,
384 typename = function_signature_t<Set>>
386
387template <typename Get,
388 typename Set,
389 typename RetState,
390 typename Self,
391 typename NewInstance,
392 typename ArgState>
393struct pickle_factory<Get, Set, RetState(Self), NewInstance(ArgState)> {
394 static_assert(std::is_same<intrinsic_t<RetState>, intrinsic_t<ArgState>>::value,
395 "The type returned by `__getstate__` must be the same "
396 "as the argument accepted by `__setstate__`");
397
400
401 pickle_factory(Get get, Set set) : get(std::forward<Get>(get)), set(std::forward<Set>(set)) {}
402
403 template <typename Class, typename... Extra>
404 void execute(Class &cl, const Extra &...extra) && {
405 cl.def("__getstate__", std::move(get));
406
407#if defined(PYBIND11_CPP14)
408 cl.def(
409 "__setstate__",
410 [func = std::move(set)]
411#else
412 auto &func = set;
413 cl.def(
414 "__setstate__",
415 [func]
416#endif
417 (value_and_holder &v_h, ArgState state) {
418 setstate<Class>(
419 v_h, func(std::forward<ArgState>(state)), Py_TYPE(v_h.inst) != v_h.type->type);
420 },
422 extra...);
423 }
424};
425
Definition: pytypes.h:1776
\rst Holds a reference to a Python object (no reference counting)
Definition: pytypes.h:194
PyObject * ptr() const
Return the underlying PyObject * pointer.
Definition: pytypes.h:203
Definition: pytypes.h:1783
bool load(handle h, bool)
Definition: init.h:20
void setattr(handle obj, handle name, handle value)
Definition: pytypes.h:569
typename std::enable_if< B, T >::type enable_if_t
from cpp_future import (convenient aliases from C++14/17)
Definition: common.h:625
typename std::remove_reference< T >::type remove_reference_t
Definition: common.h:631
typename intrinsic_type< T >::type intrinsic_t
Definition: common.h:770
#define PYBIND11_WORKAROUND_INCORRECT_MSVC_C4100(...)
Definition: common.h:1187
#define PYBIND11_NAMESPACE_END(name)
Definition: common.h:21
conditional_t< std::is_function< F >::value, F, typename conditional_t< std::is_pointer< F >::value||std::is_member_pointer< F >::value, std::remove_pointer< F >, strip_function_object< F > >::type > function_signature_t
Definition: common.h:930
#define PYBIND11_NAMESPACE_BEGIN(name)
Definition: common.h:20
std::is_same< bools< Ts::value..., true >, bools< true, Ts::value... > > all_of
Definition: common.h:707
#define PYBIND11_SILENCE_MSVC_C4127(...)
Definition: common.h:1206
void setstate(value_and_holder &v_h, T &&result, bool need_alias)
Set just the C++ state. Same as __init__.
Definition: init.h:360
typename Class::holder_type Holder
Definition: init.h:48
typename Class::type_alias Alias
Definition: init.h:46
void construct(...)
Definition: init.h:104
void construct_alias_from_cpp(std::true_type, value_and_holder &v_h, Cpp< Class > &&base)
Definition: init.h:88
Class * construct_or_initialize(Args &&...args)
Definition: init.h:72
void no_nullptr(void *ptr)
Definition: init.h:36
bool is_alias(Cpp< Class > *ptr)
Definition: init.h:55
typename Class::type Cpp
Definition: init.h:44
std::is_constructible< Alias< Class >, Cpp< Class > && > is_alias_constructible
Definition: init.h:51
static void execute(Class &cl, const Extra &...extra)
Definition: init.h:252
Annotation indicating that a class derives from another given type.
Definition: attr.h:60
static void execute(Class &cl, const Extra &...extra)
Definition: init.h:199
void execute(Class &cl, const Extra &...extra) &&
Definition: init.h:329
void execute(Class &cl, const Extra &...extra) &&
Definition: init.h:285
remove_reference_t< Func > class_factory
Definition: init.h:274
Definition: init.h:269
Helper class which abstracts away certain actions.
Definition: cast.h:740
Tag for a new-style __init__ defined in detail/init.h
Definition: attr.h:364
Annotation for function names.
Definition: attr.h:47
void execute(Class &cl, const Extra &...extra) &&
Definition: init.h:404
Implementation for py::pickle(GetState, SetState)
Definition: init.h:385
const detail::type_info * type
V *& value_ptr() const
void set_instance_registered(bool v=true)
Helper type to replace 'void' in some expressions.
Definition: common.h:773