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 initiailization 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); // To prevent init_instance from registering it
132  v_h.type->init_instance(v_h.inst, nullptr); // Set up the holder
133  Holder<Class> temp_holder(std::move(v_h.holder<Holder<Class>>())); // Steal the holder
134  v_h.type->dealloc(v_h); // Destroys the moved-out holder remains, resets value ptr to null
135  v_h.set_instance_registered(false);
136 
137  construct_alias_from_cpp<Class>(is_alias_constructible<Class>{}, v_h, std::move(*ptr));
138  } else {
139  // Otherwise the type isn't inherited, so we don't need an Alias
140  v_h.value_ptr() = ptr;
141  }
142 }
143 
144 // Pointer return v2: a factory that always returns an alias instance ptr. We simply take over
145 // ownership of the pointer.
146 template <typename Class, enable_if_t<Class::has_alias, int> = 0>
147 void construct(value_and_holder &v_h, Alias<Class> *alias_ptr, bool) {
148  no_nullptr(alias_ptr);
149  v_h.value_ptr() = static_cast<Cpp<Class> *>(alias_ptr);
150 }
151 
152 // Holder return: copy its pointer, and move or copy the returned holder into the new instance's
153 // holder. This also handles types like std::shared_ptr<T> and std::unique_ptr<T> where T is a
154 // derived type (through those holder's implicit conversion from derived class holder
155 // constructors).
156 template <typename Class>
157 void construct(value_and_holder &v_h, Holder<Class> holder, bool need_alias) {
159  auto *ptr = holder_helper<Holder<Class>>::get(holder);
160  no_nullptr(ptr);
161  // If we need an alias, check that the held pointer is actually an alias instance
162  if (Class::has_alias && need_alias && !is_alias<Class>(ptr)) {
163  throw type_error("pybind11::init(): construction failed: returned holder-wrapped instance "
164  "is not an alias instance");
165  }
166 
167  v_h.value_ptr() = ptr;
168  v_h.type->init_instance(v_h.inst, &holder);
169 }
170 
171 // return-by-value version 1: returning a cpp class by value. If the class has an alias and an
172 // alias is required the alias must have an `Alias(Cpp &&)` constructor so that we can construct
173 // the alias from the base when needed (i.e. because of Python-side inheritance). When we don't
174 // need it, we simply move-construct the cpp value into a new instance.
175 template <typename Class>
176 void construct(value_and_holder &v_h, Cpp<Class> &&result, bool need_alias) {
178  static_assert(is_move_constructible<Cpp<Class>>::value,
179  "pybind11::init() return-by-value factory function requires a movable class");
180  if (Class::has_alias && need_alias) {
181  construct_alias_from_cpp<Class>(is_alias_constructible<Class>{}, v_h, std::move(result));
182  } else {
183  v_h.value_ptr() = new Cpp<Class>(std::move(result));
184  }
185 }
186 
187 // return-by-value version 2: returning a value of the alias type itself. We move-construct an
188 // Alias instance (even if no the python-side inheritance is involved). The is intended for
189 // cases where Alias initialization is always desired.
190 template <typename Class>
192  static_assert(
194  "pybind11::init() return-by-alias-value factory function requires a movable alias class");
195  v_h.value_ptr() = new Alias<Class>(std::move(result));
196 }
197 
198 // Implementing class for py::init<...>()
199 template <typename... Args>
200 struct constructor {
201  template <typename Class, typename... Extra, enable_if_t<!Class::has_alias, int> = 0>
202  static void execute(Class &cl, const Extra &...extra) {
203  cl.def(
204  "__init__",
205  [](value_and_holder &v_h, Args... args) {
206  v_h.value_ptr() = construct_or_initialize<Cpp<Class>>(std::forward<Args>(args)...);
207  },
209  extra...);
210  }
211 
212  template <
213  typename Class,
214  typename... Extra,
216  = 0>
217  static void execute(Class &cl, const Extra &...extra) {
218  cl.def(
219  "__init__",
220  [](value_and_holder &v_h, Args... args) {
221  if (Py_TYPE(v_h.inst) == v_h.type->type) {
222  v_h.value_ptr()
223  = construct_or_initialize<Cpp<Class>>(std::forward<Args>(args)...);
224  } else {
225  v_h.value_ptr()
226  = construct_or_initialize<Alias<Class>>(std::forward<Args>(args)...);
227  }
228  },
230  extra...);
231  }
232 
233  template <
234  typename Class,
235  typename... Extra,
237  = 0>
238  static void execute(Class &cl, const Extra &...extra) {
239  cl.def(
240  "__init__",
241  [](value_and_holder &v_h, Args... args) {
242  v_h.value_ptr()
243  = construct_or_initialize<Alias<Class>>(std::forward<Args>(args)...);
244  },
246  extra...);
247  }
248 };
249 
250 // Implementing class for py::init_alias<...>()
251 template <typename... Args>
253  template <
254  typename Class,
255  typename... Extra,
257  = 0>
258  static void execute(Class &cl, const Extra &...extra) {
259  cl.def(
260  "__init__",
261  [](value_and_holder &v_h, Args... args) {
262  v_h.value_ptr()
263  = construct_or_initialize<Alias<Class>>(std::forward<Args>(args)...);
264  },
266  extra...);
267  }
268 };
269 
270 // Implementation class for py::init(Func) and py::init(Func, AliasFunc)
271 template <typename CFunc,
272  typename AFunc = void_type (*)(),
273  typename = function_signature_t<CFunc>,
274  typename = function_signature_t<AFunc>>
275 struct factory;
276 
277 // Specialization for py::init(Func)
278 template <typename Func, typename Return, typename... Args>
279 struct factory<Func, void_type (*)(), Return(Args...)> {
281 
282  // NOLINTNEXTLINE(google-explicit-constructor)
283  factory(Func &&f) : class_factory(std::forward<Func>(f)) {}
284 
285  // The given class either has no alias or has no separate alias factory;
286  // this always constructs the class itself. If the class is registered with an alias
287  // type and an alias instance is needed (i.e. because the final type is a Python class
288  // inheriting from the C++ type) the returned value needs to either already be an alias
289  // instance, or the alias needs to be constructible from a `Class &&` argument.
290  template <typename Class, typename... Extra>
291  void execute(Class &cl, const Extra &...extra) && {
292 #if defined(PYBIND11_CPP14)
293  cl.def(
294  "__init__",
295  [func = std::move(class_factory)]
296 #else
297  auto &func = class_factory;
298  cl.def(
299  "__init__",
300  [func]
301 #endif
302  (value_and_holder &v_h, Args... args) {
303  construct<Class>(
304  v_h, func(std::forward<Args>(args)...), Py_TYPE(v_h.inst) != v_h.type->type);
305  },
307  extra...);
308  }
309 };
310 
311 // Specialization for py::init(Func, AliasFunc)
312 template <typename CFunc,
313  typename AFunc,
314  typename CReturn,
315  typename... CArgs,
316  typename AReturn,
317  typename... AArgs>
318 struct factory<CFunc, AFunc, CReturn(CArgs...), AReturn(AArgs...)> {
319  static_assert(sizeof...(CArgs) == sizeof...(AArgs),
320  "pybind11::init(class_factory, alias_factory): class and alias factories "
321  "must have identical argument signatures");
322  static_assert(all_of<std::is_same<CArgs, AArgs>...>::value,
323  "pybind11::init(class_factory, alias_factory): class and alias factories "
324  "must have identical argument signatures");
325 
328 
329  factory(CFunc &&c, AFunc &&a)
330  : class_factory(std::forward<CFunc>(c)), alias_factory(std::forward<AFunc>(a)) {}
331 
332  // The class factory is called when the `self` type passed to `__init__` is the direct
333  // class (i.e. not inherited), the alias factory when `self` is a Python-side subtype.
334  template <typename Class, typename... Extra>
335  void execute(Class &cl, const Extra &...extra) && {
336  static_assert(Class::has_alias,
337  "The two-argument version of `py::init()` can "
338  "only be used if the class has an alias");
339 #if defined(PYBIND11_CPP14)
340  cl.def(
341  "__init__",
342  [class_func = std::move(class_factory), alias_func = std::move(alias_factory)]
343 #else
344  auto &class_func = class_factory;
345  auto &alias_func = alias_factory;
346  cl.def(
347  "__init__",
348  [class_func, alias_func]
349 #endif
350  (value_and_holder &v_h, CArgs... args) {
351  if (Py_TYPE(v_h.inst) == v_h.type->type) {
352  // If the instance type equals the registered type we don't have inheritance,
353  // so don't need the alias and can construct using the class function:
354  construct<Class>(v_h, class_func(std::forward<CArgs>(args)...), false);
355  } else {
356  construct<Class>(v_h, alias_func(std::forward<CArgs>(args)...), true);
357  }
358  },
360  extra...);
361  }
362 };
363 
365 template <typename Class, typename T>
366 void setstate(value_and_holder &v_h, T &&result, bool need_alias) {
367  construct<Class>(v_h, std::forward<T>(result), need_alias);
368 }
369 
371 template <typename Class,
372  typename T,
373  typename O,
375 void setstate(value_and_holder &v_h, std::pair<T, O> &&result, bool need_alias) {
376  construct<Class>(v_h, std::move(result.first), need_alias);
377  auto d = handle(result.second);
378  if (PyDict_Check(d.ptr()) && PyDict_Size(d.ptr()) == 0) {
379  // Skipping setattr below, to not force use of py::dynamic_attr() for Class unnecessarily.
380  // See PR #2972 for details.
381  return;
382  }
383  setattr((PyObject *) v_h.inst, "__dict__", d);
384 }
385 
387 template <typename Get,
388  typename Set,
389  typename = function_signature_t<Get>,
390  typename = function_signature_t<Set>>
392 
393 template <typename Get,
394  typename Set,
395  typename RetState,
396  typename Self,
397  typename NewInstance,
398  typename ArgState>
399 struct pickle_factory<Get, Set, RetState(Self), NewInstance(ArgState)> {
400  static_assert(std::is_same<intrinsic_t<RetState>, intrinsic_t<ArgState>>::value,
401  "The type returned by `__getstate__` must be the same "
402  "as the argument accepted by `__setstate__`");
403 
406 
407  pickle_factory(Get get, Set set) : get(std::forward<Get>(get)), set(std::forward<Set>(set)) {}
408 
409  template <typename Class, typename... Extra>
410  void execute(Class &cl, const Extra &...extra) && {
411  cl.def("__getstate__", std::move(get));
412 
413 #if defined(PYBIND11_CPP14)
414  cl.def(
415  "__setstate__",
416  [func = std::move(set)]
417 #else
418  auto &func = set;
419  cl.def(
420  "__setstate__",
421  [func]
422 #endif
423  (value_and_holder &v_h, ArgState state) {
424  setstate<Class>(
425  v_h, func(std::forward<ArgState>(state)), Py_TYPE(v_h.inst) != v_h.type->type);
426  },
428  extra...);
429  }
430 };
431 
432 PYBIND11_NAMESPACE_END(initimpl)
constructor::execute
static void execute(Class &cl, const Extra &...extra)
Definition: init.h:202
factory< Func, void_type(*)(), Return(Args...)>::class_factory
remove_reference_t< Func > class_factory
Definition: init.h:280
all_of
std::is_same< bools< Ts::value..., true >, bools< true, Ts::value... > > all_of
Definition: wrap/pybind11/include/pybind11/detail/common.h:726
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:905
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:329
set
Definition: pytypes.h:2185
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:366
pickle_factory< Get, Set, RetState(Self), NewInstance(ArgState)>::execute
void execute(Class &cl, const Extra &...extra) &&
Definition: init.h:410
c
Scalar Scalar * c
Definition: benchVecAdd.cpp:17
factory
Definition: init.h:275
PYBIND11_NAMESPACE_END
#define PYBIND11_NAMESPACE_END(name)
Definition: wrap/pybind11/include/pybind11/detail/common.h:80
value_and_holder
Definition: type_caster_base.h:253
factory< Func, void_type(*)(), Return(Args...)>::execute
void execute(Class &cl, const Extra &...extra) &&
Definition: init.h:291
T
Eigen::Triplet< double > T
Definition: Tutorial_sparse_example.cpp:6
detail
Definition: testSerializationNonlinear.cpp:70
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:972
pickle_factory
Implementation for py::pickle(GetState, SetState)
Definition: init.h:391
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: type_caster_base.h:303
alias_constructor
Definition: init.h:252
intrinsic_t
typename intrinsic_type< T >::type intrinsic_t
Definition: wrap/pybind11/include/pybind11/detail/common.h:798
handle
Definition: pytypes.h:217
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:407
value_and_holder::inst
instance * inst
Definition: type_caster_base.h:254
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:402
factory< CFunc, AFunc, CReturn(CArgs...), AReturn(AArgs...)>::execute
void execute(Class &cl, const Extra &...extra) &&
Definition: init.h:335
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:258
cl
Definition: cxx11_tensor_builtins_sycl.cpp:30
holder_helper
Definition: cast.h:733
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: type_caster_base.h:272
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:327
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:1217
factory< Func, void_type(*)(), Return(Args...)>::factory
factory(Func &&f)
Definition: init.h:283
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:960
forward
Definition: testScenarioRunner.cpp:79
Holder
typename Class::holder_type Holder
Definition: init.h:51
constructor
Definition: init.h:200
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:801
value_and_holder::holder
H & holder() const
Definition: type_caster_base.h:279
args
Definition: pytypes.h:2163
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:640
factory< CFunc, AFunc, CReturn(CArgs...), AReturn(AArgs...)>::class_factory
remove_reference_t< CFunc > class_factory
Definition: init.h:321
value_and_holder::type
const detail::type_info * type
Definition: type_caster_base.h:256
test_callbacks.value
value
Definition: test_callbacks.py:158
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:646
pickle_factory< Get, Set, RetState(Self), NewInstance(ArgState)>::set
remove_reference_t< Set > set
Definition: init.h:405
make_changelog.state
state
Definition: make_changelog.py:28


gtsam
Author(s):
autogenerated on Thu Jun 13 2024 03:02:37