init.h revision 12391:ceeca8b41e4b
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 PYBIND11_DESCR name() { return type_descr(_<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// Attempts to constructs an alias using a `Alias(Cpp &&)` constructor. This allows types with 56// an alias to provide only a single Cpp factory function as long as the Alias can be 57// constructed from an rvalue reference of the base Cpp type. This means that Alias classes 58// can, when appropriate, simply define a `Alias(Cpp &&)` constructor rather than needing to 59// inherit all the base class constructors. 60template <typename Class> 61void construct_alias_from_cpp(std::true_type /*is_alias_constructible*/, 62 value_and_holder &v_h, Cpp<Class> &&base) { 63 v_h.value_ptr() = new Alias<Class>(std::move(base)); 64} 65template <typename Class> 66[[noreturn]] void construct_alias_from_cpp(std::false_type /*!is_alias_constructible*/, 67 value_and_holder &, Cpp<Class> &&) { 68 throw type_error("pybind11::init(): unable to convert returned instance to required " 69 "alias class: no `Alias<Class>(Class &&)` constructor available"); 70} 71 72// Error-generating fallback for factories that don't match one of the below construction 73// mechanisms. 74template <typename Class> 75void construct(...) { 76 static_assert(!std::is_same<Class, Class>::value /* always false */, 77 "pybind11::init(): init function must return a compatible pointer, " 78 "holder, or value"); 79} 80 81// Pointer return v1: the factory function returns a class pointer for a registered class. 82// If we don't need an alias (because this class doesn't have one, or because the final type is 83// inherited on the Python side) we can simply take over ownership. Otherwise we need to try to 84// construct an Alias from the returned base instance. 85template <typename Class> 86void construct(value_and_holder &v_h, Cpp<Class> *ptr, bool need_alias) { 87 no_nullptr(ptr); 88 if (Class::has_alias && need_alias && !is_alias<Class>(ptr)) { 89 // We're going to try to construct an alias by moving the cpp type. Whether or not 90 // that succeeds, we still need to destroy the original cpp pointer (either the 91 // moved away leftover, if the alias construction works, or the value itself if we 92 // throw an error), but we can't just call `delete ptr`: it might have a special 93 // deleter, or might be shared_from_this. So we construct a holder around it as if 94 // it was a normal instance, then steal the holder away into a local variable; thus 95 // the holder and destruction happens when we leave the C++ scope, and the holder 96 // class gets to handle the destruction however it likes. 97 v_h.value_ptr() = ptr; 98 v_h.set_instance_registered(true); // To prevent init_instance from registering it 99 v_h.type->init_instance(v_h.inst, nullptr); // Set up the holder 100 Holder<Class> temp_holder(std::move(v_h.holder<Holder<Class>>())); // Steal the holder 101 v_h.type->dealloc(v_h); // Destroys the moved-out holder remains, resets value ptr to null 102 v_h.set_instance_registered(false); 103 104 construct_alias_from_cpp<Class>(is_alias_constructible<Class>{}, v_h, std::move(*ptr)); 105 } else { 106 // Otherwise the type isn't inherited, so we don't need an Alias 107 v_h.value_ptr() = ptr; 108 } 109} 110 111// Pointer return v2: a factory that always returns an alias instance ptr. We simply take over 112// ownership of the pointer. 113template <typename Class, enable_if_t<Class::has_alias, int> = 0> 114void construct(value_and_holder &v_h, Alias<Class> *alias_ptr, bool) { 115 no_nullptr(alias_ptr); 116 v_h.value_ptr() = static_cast<Cpp<Class> *>(alias_ptr); 117} 118 119// Holder return: copy its pointer, and move or copy the returned holder into the new instance's 120// holder. This also handles types like std::shared_ptr<T> and std::unique_ptr<T> where T is a 121// derived type (through those holder's implicit conversion from derived class holder constructors). 122template <typename Class> 123void construct(value_and_holder &v_h, Holder<Class> holder, bool need_alias) { 124 auto *ptr = holder_helper<Holder<Class>>::get(holder); 125 // If we need an alias, check that the held pointer is actually an alias instance 126 if (Class::has_alias && need_alias && !is_alias<Class>(ptr)) 127 throw type_error("pybind11::init(): construction failed: returned holder-wrapped instance " 128 "is not an alias instance"); 129 130 v_h.value_ptr() = ptr; 131 v_h.type->init_instance(v_h.inst, &holder); 132} 133 134// return-by-value version 1: returning a cpp class by value. If the class has an alias and an 135// alias is required the alias must have an `Alias(Cpp &&)` constructor so that we can construct 136// the alias from the base when needed (i.e. because of Python-side inheritance). When we don't 137// need it, we simply move-construct the cpp value into a new instance. 138template <typename Class> 139void construct(value_and_holder &v_h, Cpp<Class> &&result, bool need_alias) { 140 static_assert(std::is_move_constructible<Cpp<Class>>::value, 141 "pybind11::init() return-by-value factory function requires a movable class"); 142 if (Class::has_alias && need_alias) 143 construct_alias_from_cpp<Class>(is_alias_constructible<Class>{}, v_h, std::move(result)); 144 else 145 v_h.value_ptr() = new Cpp<Class>(std::move(result)); 146} 147 148// return-by-value version 2: returning a value of the alias type itself. We move-construct an 149// Alias instance (even if no the python-side inheritance is involved). The is intended for 150// cases where Alias initialization is always desired. 151template <typename Class> 152void construct(value_and_holder &v_h, Alias<Class> &&result, bool) { 153 static_assert(std::is_move_constructible<Alias<Class>>::value, 154 "pybind11::init() return-by-alias-value factory function requires a movable alias class"); 155 v_h.value_ptr() = new Alias<Class>(std::move(result)); 156} 157 158// Implementing class for py::init<...>() 159template <typename... Args> 160struct constructor { 161 template <typename Class, typename... Extra, enable_if_t<!Class::has_alias, int> = 0> 162 static void execute(Class &cl, const Extra&... extra) { 163 cl.def("__init__", [](value_and_holder &v_h, Args... args) { 164 v_h.value_ptr() = new Cpp<Class>{std::forward<Args>(args)...}; 165 }, is_new_style_constructor(), extra...); 166 } 167 168 template <typename Class, typename... Extra, 169 enable_if_t<Class::has_alias && 170 std::is_constructible<Cpp<Class>, Args...>::value, int> = 0> 171 static void execute(Class &cl, const Extra&... extra) { 172 cl.def("__init__", [](value_and_holder &v_h, Args... args) { 173 if (Py_TYPE(v_h.inst) == v_h.type->type) 174 v_h.value_ptr() = new Cpp<Class>{std::forward<Args>(args)...}; 175 else 176 v_h.value_ptr() = new Alias<Class>{std::forward<Args>(args)...}; 177 }, is_new_style_constructor(), extra...); 178 } 179 180 template <typename Class, typename... Extra, 181 enable_if_t<Class::has_alias && 182 !std::is_constructible<Cpp<Class>, Args...>::value, int> = 0> 183 static void execute(Class &cl, const Extra&... extra) { 184 cl.def("__init__", [](value_and_holder &v_h, Args... args) { 185 v_h.value_ptr() = new Alias<Class>{std::forward<Args>(args)...}; 186 }, is_new_style_constructor(), extra...); 187 } 188}; 189 190// Implementing class for py::init_alias<...>() 191template <typename... Args> struct alias_constructor { 192 template <typename Class, typename... Extra, 193 enable_if_t<Class::has_alias && std::is_constructible<Alias<Class>, Args...>::value, int> = 0> 194 static void execute(Class &cl, const Extra&... extra) { 195 cl.def("__init__", [](value_and_holder &v_h, Args... args) { 196 v_h.value_ptr() = new Alias<Class>{std::forward<Args>(args)...}; 197 }, is_new_style_constructor(), extra...); 198 } 199}; 200 201// Implementation class for py::init(Func) and py::init(Func, AliasFunc) 202template <typename CFunc, typename AFunc = void_type (*)(), 203 typename = function_signature_t<CFunc>, typename = function_signature_t<AFunc>> 204struct factory; 205 206// Specialization for py::init(Func) 207template <typename Func, typename Return, typename... Args> 208struct factory<Func, void_type (*)(), Return(Args...)> { 209 remove_reference_t<Func> class_factory; 210 211 factory(Func &&f) : class_factory(std::forward<Func>(f)) { } 212 213 // The given class either has no alias or has no separate alias factory; 214 // this always constructs the class itself. If the class is registered with an alias 215 // type and an alias instance is needed (i.e. because the final type is a Python class 216 // inheriting from the C++ type) the returned value needs to either already be an alias 217 // instance, or the alias needs to be constructible from a `Class &&` argument. 218 template <typename Class, typename... Extra> 219 void execute(Class &cl, const Extra &...extra) && { 220 #if defined(PYBIND11_CPP14) 221 cl.def("__init__", [func = std::move(class_factory)] 222 #else 223 auto &func = class_factory; 224 cl.def("__init__", [func] 225 #endif 226 (value_and_holder &v_h, Args... args) { 227 construct<Class>(v_h, func(std::forward<Args>(args)...), 228 Py_TYPE(v_h.inst) != v_h.type->type); 229 }, is_new_style_constructor(), extra...); 230 } 231}; 232 233// Specialization for py::init(Func, AliasFunc) 234template <typename CFunc, typename AFunc, 235 typename CReturn, typename... CArgs, typename AReturn, typename... AArgs> 236struct factory<CFunc, AFunc, CReturn(CArgs...), AReturn(AArgs...)> { 237 static_assert(sizeof...(CArgs) == sizeof...(AArgs), 238 "pybind11::init(class_factory, alias_factory): class and alias factories " 239 "must have identical argument signatures"); 240 static_assert(all_of<std::is_same<CArgs, AArgs>...>::value, 241 "pybind11::init(class_factory, alias_factory): class and alias factories " 242 "must have identical argument signatures"); 243 244 remove_reference_t<CFunc> class_factory; 245 remove_reference_t<AFunc> alias_factory; 246 247 factory(CFunc &&c, AFunc &&a) 248 : class_factory(std::forward<CFunc>(c)), alias_factory(std::forward<AFunc>(a)) { } 249 250 // The class factory is called when the `self` type passed to `__init__` is the direct 251 // class (i.e. not inherited), the alias factory when `self` is a Python-side subtype. 252 template <typename Class, typename... Extra> 253 void execute(Class &cl, const Extra&... extra) && { 254 static_assert(Class::has_alias, "The two-argument version of `py::init()` can " 255 "only be used if the class has an alias"); 256 #if defined(PYBIND11_CPP14) 257 cl.def("__init__", [class_func = std::move(class_factory), alias_func = std::move(alias_factory)] 258 #else 259 auto &class_func = class_factory; 260 auto &alias_func = alias_factory; 261 cl.def("__init__", [class_func, alias_func] 262 #endif 263 (value_and_holder &v_h, CArgs... args) { 264 if (Py_TYPE(v_h.inst) == v_h.type->type) 265 // If the instance type equals the registered type we don't have inheritance, so 266 // don't need the alias and can construct using the class function: 267 construct<Class>(v_h, class_func(std::forward<CArgs>(args)...), false); 268 else 269 construct<Class>(v_h, alias_func(std::forward<CArgs>(args)...), true); 270 }, is_new_style_constructor(), extra...); 271 } 272}; 273 274/// Set just the C++ state. Same as `__init__`. 275template <typename Class, typename T> 276void setstate(value_and_holder &v_h, T &&result, bool need_alias) { 277 construct<Class>(v_h, std::forward<T>(result), need_alias); 278} 279 280/// Set both the C++ and Python states 281template <typename Class, typename T, typename O, 282 enable_if_t<std::is_convertible<O, handle>::value, int> = 0> 283void setstate(value_and_holder &v_h, std::pair<T, O> &&result, bool need_alias) { 284 construct<Class>(v_h, std::move(result.first), need_alias); 285 setattr((PyObject *) v_h.inst, "__dict__", result.second); 286} 287 288/// Implementation for py::pickle(GetState, SetState) 289template <typename Get, typename Set, 290 typename = function_signature_t<Get>, typename = function_signature_t<Set>> 291struct pickle_factory; 292 293template <typename Get, typename Set, 294 typename RetState, typename Self, typename NewInstance, typename ArgState> 295struct pickle_factory<Get, Set, RetState(Self), NewInstance(ArgState)> { 296 static_assert(std::is_same<intrinsic_t<RetState>, intrinsic_t<ArgState>>::value, 297 "The type returned by `__getstate__` must be the same " 298 "as the argument accepted by `__setstate__`"); 299 300 remove_reference_t<Get> get; 301 remove_reference_t<Set> set; 302 303 pickle_factory(Get get, Set set) 304 : get(std::forward<Get>(get)), set(std::forward<Set>(set)) { } 305 306 template <typename Class, typename... Extra> 307 void execute(Class &cl, const Extra &...extra) && { 308 cl.def("__getstate__", std::move(get)); 309 310#if defined(PYBIND11_CPP14) 311 cl.def("__setstate__", [func = std::move(set)] 312#else 313 auto &func = set; 314 cl.def("__setstate__", [func] 315#endif 316 (value_and_holder &v_h, ArgState state) { 317 setstate<Class>(v_h, func(std::forward<ArgState>(state)), 318 Py_TYPE(v_h.inst) != v_h.type->type); 319 }, is_new_style_constructor(), extra...); 320 } 321}; 322 323NAMESPACE_END(initimpl) 324NAMESPACE_END(detail) 325NAMESPACE_END(pybind11) 326