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 
17 template <>
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>
27  explicit operator value_and_holder &() { return *value; }
28  static constexpr auto name = const_name<value_and_holder>();
29 
30 private:
31  value_and_holder *value = nullptr;
32 };
33 
35 
36 inline 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(...)
43 template <typename Class>
44 using Cpp = typename Class::type;
45 template <typename Class>
46 using Alias = typename Class::type_alias;
47 template <typename Class>
48 using Holder = typename Class::holder_type;
49 
50 template <typename Class>
51 using 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.
54 template <typename Class, enable_if_t<Class::has_alias, int> = 0>
55 bool 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)
59 template <typename /*Class*/>
60 constexpr 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).
69 template <typename Class,
70  typename... Args,
71  detail::enable_if_t<std::is_constructible<Class, Args...>::value, int> = 0>
72 inline Class *construct_or_initialize(Args &&...args) {
73  return new Class(std::forward<Args>(args)...);
74 }
75 template <typename Class,
76  typename... Args,
77  detail::enable_if_t<!std::is_constructible<Class, Args...>::value, int> = 0>
78 inline 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.
87 template <typename Class>
88 void construct_alias_from_cpp(std::true_type /*is_alias_constructible*/,
89  value_and_holder &v_h,
90  Cpp<Class> &&base) {
91  v_h.value_ptr() = new Alias<Class>(std::move(base));
92 }
93 template <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.
103 template <typename Class>
104 void 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.
114 template <typename Class>
115 void 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.
143 template <typename Class, enable_if_t<Class::has_alias, int> = 0>
144 void 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).
153 template <typename Class>
154 void 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.
172 template <typename Class>
173 void 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.
187 template <typename Class>
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<...>()
196 template <typename... Args>
197 struct constructor {
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<...>()
246 template <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)
265 template <typename CFunc,
266  typename AFunc = void_type (*)(),
267  typename = function_signature_t<CFunc>,
268  typename = function_signature_t<AFunc>>
269 struct factory;
270 
271 // Specialization for py::init(Func)
272 template <typename Func, typename Return, typename... Args>
273 struct 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)
306 template <typename CFunc,
307  typename AFunc,
308  typename CReturn,
309  typename... CArgs,
310  typename AReturn,
311  typename... AArgs>
312 struct 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 
359 template <typename Class, typename T>
360 void setstate(value_and_holder &v_h, T &&result, bool need_alias) {
361  construct<Class>(v_h, std::forward<T>(result), need_alias);
362 }
363 
365 template <typename Class,
366  typename T,
367  typename O,
369 void 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 
381 template <typename Get,
382  typename Set,
383  typename = function_signature_t<Get>,
384  typename = function_signature_t<Set>>
386 
387 template <typename Get,
388  typename Set,
389  typename RetState,
390  typename Self,
391  typename NewInstance,
392  typename ArgState>
393 struct 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 
426 PYBIND11_NAMESPACE_END(initimpl)
void execute(Class &cl, const Extra &...extra) &&
Definition: init.h:329
void construct_alias_from_cpp(std::true_type, value_and_holder &v_h, Cpp< Class > &&base)
Definition: init.h:88
#define PYBIND11_WORKAROUND_INCORRECT_MSVC_C4100(...)
const detail::type_info * type
Class * construct_or_initialize(Args &&...args)
Definition: init.h:72
std::is_constructible< Alias< Class >, Cpp< Class > && > is_alias_constructible
Definition: init.h:51
void construct(...)
Definition: init.h:104
void no_nullptr(void *ptr)
Definition: init.h:36
static void execute(Class &cl, const Extra &...extra)
Definition: init.h:199
Definition: pytypes.h:2012
Tag for a new-style __init__ defined in detail/init.h
Definition: attr.h:366
#define PYBIND11_SILENCE_MSVC_C4127(...)
Scalar Scalar * c
Definition: benchVecAdd.cpp:17
bool load(handle h, bool)
Definition: init.h:20
Definition: BFloat16.h:88
void set_instance_registered(bool v=true)
V *& value_ptr() const
static void execute(Class &cl, const Extra &...extra)
Definition: init.h:252
Definition: init.h:269
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
void execute(Class &cl, const Extra &...extra) &&
Definition: init.h:404
void setstate(value_and_holder &v_h, T &&result, bool need_alias)
Set just the C++ state. Same as __init__.
Definition: init.h:360
Values result
Key O(std::uint64_t j)
void execute(Class &cl, const Extra &...extra) &&
Definition: init.h:285
Eigen::Triplet< double > T
Point2(* f)(const Point3 &, OptionalJacobian< 2, 3 >)
typename Class::holder_type Holder
Definition: init.h:48
typename std::remove_reference< T >::type remove_reference_t
Helper type to replace &#39;void&#39; in some expressions.
typename Class::type Cpp
Definition: init.h:44
std::is_same< bools< Ts::value..., true >, bools< true, Ts::value... > > all_of
remove_reference_t< Func > class_factory
Definition: init.h:274
bool is_alias(Cpp< Class > *ptr)
Definition: init.h:55
const double h
int func(const int &a)
Definition: testDSF.cpp:221
typename intrinsic_type< T >::type intrinsic_t
typename std::enable_if< B, T >::type enable_if_t
from cpp_future import (convenient aliases from C++14/17)
Annotation for function names.
Definition: attr.h:48
Annotation indicating that a class derives from another given type.
Definition: attr.h:61
PyObject * ptr() const
Return the underlying PyObject * pointer.
Definition: pytypes.h:238
Container::iterator get(Container &c, Position position)
typename Class::type_alias Alias
Definition: init.h:46
void setattr(handle obj, handle name, handle value)
Definition: pytypes.h:780
Definition: pytypes.h:2030
Implementation for py::pickle(GetState, SetState)
Definition: init.h:385
#define PYBIND11_NAMESPACE_END(name)
#define PYBIND11_NAMESPACE_BEGIN(name)


gtsam
Author(s):
autogenerated on Tue Jul 4 2023 02:34:22