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 14NAMESPACE_BEGIN(PYBIND11_NAMESPACE) 15NAMESPACE_BEGIN(detail) 16 17template <> 18class type_caster<value_and_holder> { 19public: 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 29private: 30 value_and_holder *value = nullptr; 31}; 32 33NAMESPACE_BEGIN(initimpl) 34 35inline 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(...) 40template <typename Class> using Cpp = typename Class::type; 41template <typename Class> using Alias = typename Class::type_alias; 42template <typename Class> using Holder = typename Class::holder_type; 43 44template <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. 47template <typename Class, enable_if_t<Class::has_alias, int> = 0> 48bool 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) 52template <typename /*Class*/> 53constexpr 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). 60template <typename Class, typename... Args, detail::enable_if_t<std::is_constructible<Class, Args...>::value, int> = 0> 61inline Class *construct_or_initialize(Args &&...args) { return new Class(std::forward<Args>(args)...); } 62template <typename Class, typename... Args, detail::enable_if_t<!std::is_constructible<Class, Args...>::value, int> = 0> 63inline 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. 70template <typename Class> 71void 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} 75template <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. 84template <typename Class> 85void 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. 95template <typename Class> 96void 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. 123template <typename Class, enable_if_t<Class::has_alias, int> = 0> 124void 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). 132template <typename Class> 133void 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. 148template <typename Class> 149void 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. 161template <typename Class> 162void 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<...>() 169template <typename... Args> 170struct 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<...>() 201template <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) 212template <typename CFunc, typename AFunc = void_type (*)(), 213 typename = function_signature_t<CFunc>, typename = function_signature_t<AFunc>> 214struct factory; 215 216// Specialization for py::init(Func) 217template <typename Func, typename Return, typename... Args> 218struct 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) 244template <typename CFunc, typename AFunc, 245 typename CReturn, typename... CArgs, typename AReturn, typename... AArgs> 246struct 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__`. 285template <typename Class, typename T> 286void 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 291template <typename Class, typename T, typename O, 292 enable_if_t<std::is_convertible<O, handle>::value, int> = 0> 293void 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) 299template <typename Get, typename Set, 300 typename = function_signature_t<Get>, typename = function_signature_t<Set>> 301struct pickle_factory; 302 303template <typename Get, typename Set, 304 typename RetState, typename Self, typename NewInstance, typename ArgState> 305struct 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 333NAMESPACE_END(initimpl) 334NAMESPACE_END(detail) 335NAMESPACE_END(pybind11) 336