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


gtsam
Author(s):
autogenerated on Wed Mar 19 2025 03:01:50