/* pybind11/detail/type_caster_base.h (originally first part of pybind11/cast.h) Copyright (c) 2016 Wenzel Jakob All rights reserved. Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. */ #pragma once #include #include #include #include "common.h" #include "cpp_conduit.h" #include "descr.h" #include "dynamic_raw_ptr_cast_if_possible.h" #include "internals.h" #include "typeid.h" #include "using_smart_holder.h" #include "value_and_holder.h" #include #include #include #include #include #include #include #include #include #include #include #include PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE) PYBIND11_NAMESPACE_BEGIN(detail) /// A life support system for temporary objects created by `type_caster::load()`. /// Adding a patient will keep it alive up until the enclosing function returns. class loader_life_support { private: // Thread-local top-of-stack for loader_life_support frames (linked via parent). // Observation: loader_life_support needs to be thread-local, // but we don't need to go to extra effort to keep it // per-interpreter (i.e., by putting it in internals) since // individual function calls are already isolated to a single // interpreter, even though they could potentially call into a // different interpreter later in the same call chain. This // saves a significant cost per function call spent in // loader_life_support destruction. // Note for future C++17 simplification: // inline static thread_local loader_life_support *tls_current_frame = nullptr; static loader_life_support *&tls_current_frame() { static thread_local loader_life_support *frame_ptr = nullptr; return frame_ptr; } loader_life_support *parent = nullptr; std::unordered_set keep_alive; public: /// A new patient frame is created when a function is entered loader_life_support() { auto &frame = tls_current_frame(); parent = frame; frame = this; } /// ... and destroyed after it returns ~loader_life_support() { auto &frame = tls_current_frame(); if (frame != this) { pybind11_fail("loader_life_support: internal error"); } frame = parent; for (auto *item : keep_alive) { Py_DECREF(item); } } /// Keep `h` alive until the current patient frame is destroyed, if there is one. /// Returns false when called outside a bound function (no frame). Use this, rather /// than `add_patient`, when failing to register is acceptable because the caller /// owns the source's lifetime outside the call framework (e.g. a view that points /// into an existing Python object, as opposed to a freshly created temporary). PYBIND11_NOINLINE static bool try_add_patient(handle h) { loader_life_support *frame = tls_current_frame(); if (!frame) { return false; } if (frame->keep_alive.insert(h.ptr()).second) { Py_INCREF(h.ptr()); } return true; } /// This can only be used inside a pybind11-bound function, either by `argument_loader` /// at argument preparation time or by `py::cast()` at execution time. PYBIND11_NOINLINE static void add_patient(handle h) { if (!try_add_patient(h)) { // NOTE: It would be nice to include the stack frames here, as this indicates // use of pybind11::cast<> outside the normal call framework, finding such // a location is challenging. Developers could consider printing out // stack frame addresses here using something like __builtin_frame_address(0) throw cast_error("When called outside a bound function, py::cast() cannot " "do Python -> C++ conversions which require the creation " "of temporary values"); } } }; // Gets the cache entry for the given type, creating it if necessary. The return value is the pair // returned by emplace, i.e. an iterator for the entry and a bool set to `true` if the entry was // just created. inline std::pair all_type_info_get_cache(PyTypeObject *type); // Band-aid workaround to fix a subtle but serious bug in a minimalistic fashion. See PR #4762. inline void all_type_info_add_base_most_derived_first(std::vector &bases, type_info *addl_base) { for (auto it = bases.begin(); it != bases.end(); it++) { type_info *existing_base = *it; if (PyType_IsSubtype(addl_base->type, existing_base->type) != 0) { bases.insert(it, addl_base); return; } } bases.push_back(addl_base); } // Populates a just-created cache entry. PYBIND11_NOINLINE void all_type_info_populate(PyTypeObject *t, std::vector &bases) { assert(bases.empty()); std::vector check; for (handle parent : reinterpret_borrow(t->tp_bases)) { check.push_back(reinterpret_cast(parent.ptr())); } auto const &type_dict = get_internals().registered_types_py; for (size_t i = 0; i < check.size(); i++) { auto *type = check[i]; // Ignore Python2 old-style class super type: if (!PyType_Check((PyObject *) type)) { continue; } // Check `type` in the current set of registered python types: auto it = type_dict.find(type); if (it != type_dict.end()) { // We found a cache entry for it, so it's either pybind-registered or has pre-computed // pybind bases, but we have to make sure we haven't already seen the type(s) before: // we want to follow Python/virtual C++ rules that there should only be one instance of // a common base. for (auto *tinfo : it->second) { // NB: Could use a second set here, rather than doing a linear search, but since // having a large number of immediate pybind11-registered types seems fairly // unlikely, that probably isn't worthwhile. bool found = false; for (auto *known : bases) { if (known == tinfo) { found = true; break; } } if (!found) { all_type_info_add_base_most_derived_first(bases, tinfo); } } } else if (type->tp_bases) { // It's some python type, so keep follow its bases classes to look for one or more // registered types if (i + 1 == check.size()) { // When we're at the end, we can pop off the current element to avoid growing // `check` when adding just one base (which is typical--i.e. when there is no // multiple inheritance) check.pop_back(); i--; } for (handle parent : reinterpret_borrow(type->tp_bases)) { check.push_back(reinterpret_cast(parent.ptr())); } } } } /** * Extracts vector of type_info pointers of pybind-registered roots of the given Python type. Will * be just 1 pybind type for the Python type of a pybind-registered class, or for any Python-side * derived class that uses single inheritance. Will contain as many types as required for a Python * class that uses multiple inheritance to inherit (directly or indirectly) from multiple * pybind-registered classes. Will be empty if neither the type nor any base classes are * pybind-registered. * * The value is cached for the lifetime of the Python type. */ inline const std::vector &all_type_info(PyTypeObject *type) { return all_type_info_get_cache(type).first->second; } /** * Gets a single pybind11 type info for a python type. Returns nullptr if neither the type nor any * ancestors are pybind11-registered. Throws an exception if there are multiple bases--use * `all_type_info` instead if you want to support multiple bases. */ PYBIND11_NOINLINE detail::type_info *get_type_info(PyTypeObject *type) { const auto &bases = all_type_info(type); if (bases.empty()) { return nullptr; } if (bases.size() > 1) { pybind11_fail( "pybind11::detail::get_type_info: type has multiple pybind11-registered bases"); } return bases.front(); } inline detail::type_info *get_local_type_info_lock_held(const std::type_info &tp) { const auto &locals = get_local_internals().registered_types_cpp; auto it = locals.find(&tp); if (it != locals.end()) { return it->second; } return nullptr; } inline detail::type_info *get_local_type_info(const std::type_info &tp) { // NB: internals and local_internals share a single mutex PYBIND11_LOCK_INTERNALS(get_internals()); return get_local_type_info_lock_held(tp); } inline detail::type_info *get_global_type_info_lock_held(const std::type_info &tp) { // This is a two-level lookup. Hopefully we find the type info in // registered_types_cpp_fast, but if not we try // registered_types_cpp and fill registered_types_cpp_fast for // next time. detail::type_info *type_info = nullptr; auto &internals = get_internals(); #if PYBIND11_INTERNALS_VERSION >= 12 auto &fast_types = internals.registered_types_cpp_fast; #endif auto &types = internals.registered_types_cpp; #if PYBIND11_INTERNALS_VERSION >= 12 auto fast_it = fast_types.find(&tp); if (fast_it != fast_types.end()) { # ifndef NDEBUG auto types_it = types.find(std::type_index(tp)); assert(types_it != types.end()); assert(types_it->second == fast_it->second); # endif return fast_it->second; } #endif // PYBIND11_INTERNALS_VERSION >= 12 auto it = types.find(std::type_index(tp)); if (it != types.end()) { #if PYBIND11_INTERNALS_VERSION >= 12 // We found the type in the slow map but not the fast one, so // some other DSO added it (otherwise it would be in the fast // map under &tp) and therefore we must be an alias. Record // that. it->second->alias_chain.push_front(&tp); fast_types.emplace(&tp, it->second); #endif type_info = it->second; } return type_info; } inline detail::type_info *get_global_type_info(const std::type_info &tp) { PYBIND11_LOCK_INTERNALS(get_internals()); return get_global_type_info_lock_held(tp); } /// Return the type info for a given C++ type; on lookup failure can either throw or return /// nullptr. PYBIND11_NOINLINE detail::type_info *get_type_info(const std::type_info &tp, bool throw_if_missing = false) { PYBIND11_LOCK_INTERNALS(get_internals()); if (auto *ltype = get_local_type_info_lock_held(tp)) { return ltype; } if (auto *gtype = get_global_type_info_lock_held(tp)) { return gtype; } if (throw_if_missing) { std::string tname = tp.name(); detail::clean_type_id(tname); pybind11_fail("pybind11::detail::get_type_info: unable to find type info for \"" + std::move(tname) + '"'); } return nullptr; } PYBIND11_NOINLINE handle get_type_handle(const std::type_info &tp, bool throw_if_missing) { detail::type_info *type_info = get_type_info(tp, throw_if_missing); return handle(type_info ? (reinterpret_cast(type_info->type)) : nullptr); } inline bool try_incref(PyObject *obj) { // Tries to increment the reference count of an object if it's not zero. #if defined(Py_GIL_DISABLED) && PY_VERSION_HEX >= 0x030E00A4 return PyUnstable_TryIncRef(obj); #elif defined(Py_GIL_DISABLED) // See // https://github.com/python/cpython/blob/d05140f9f77d7dfc753dd1e5ac3a5962aaa03eff/Include/internal/pycore_object.h#L761 uint32_t local = _Py_atomic_load_uint32_relaxed(&obj->ob_ref_local); local += 1; if (local == 0) { // immortal return true; } if (_Py_IsOwnedByCurrentThread(obj)) { _Py_atomic_store_uint32_relaxed(&obj->ob_ref_local, local); # ifdef Py_REF_DEBUG _Py_INCREF_IncRefTotal(); # endif return true; } Py_ssize_t shared = _Py_atomic_load_ssize_relaxed(&obj->ob_ref_shared); for (;;) { // If the shared refcount is zero and the object is either merged // or may not have weak references, then we cannot incref it. if (shared == 0 || shared == _Py_REF_MERGED) { return false; } if (_Py_atomic_compare_exchange_ssize( &obj->ob_ref_shared, &shared, shared + (1 << _Py_REF_SHARED_SHIFT))) { # ifdef Py_REF_DEBUG _Py_INCREF_IncRefTotal(); # endif return true; } } #else assert(Py_REFCNT(obj) > 0); Py_INCREF(obj); return true; #endif } // Searches the inheritance graph for a registered Python instance, using all_type_info(). PYBIND11_NOINLINE handle find_registered_python_instance(void *src, const detail::type_info *tinfo) { return with_instance_map(src, [&](instance_map &instances) { auto it_instances = instances.equal_range(src); for (auto it_i = it_instances.first; it_i != it_instances.second; ++it_i) { for (auto *instance_type : detail::all_type_info(Py_TYPE(it_i->second))) { if (instance_type && same_type(*instance_type->cpptype, *tinfo->cpptype)) { auto *wrapper = reinterpret_cast(it_i->second); if (try_incref(wrapper)) { return handle(wrapper); } } } } return handle(); }); } // Container for accessing and iterating over an instance's values/holders struct values_and_holders { private: instance *inst; using type_vec = std::vector; const type_vec &tinfo; public: explicit values_and_holders(instance *inst) : inst{inst}, tinfo(all_type_info(Py_TYPE(inst))) {} explicit values_and_holders(PyObject *obj) : inst{nullptr}, tinfo(all_type_info(Py_TYPE(obj))) { if (!tinfo.empty()) { inst = reinterpret_cast(obj); } } struct iterator { private: instance *inst = nullptr; const type_vec *types = nullptr; value_and_holder curr; friend struct values_and_holders; iterator(instance *inst, const type_vec *tinfo) : inst{inst}, types{tinfo} { if (inst != nullptr) { assert(!types->empty()); curr = value_and_holder( inst /* instance */, (*types)[0] /* type info */, 0, /* vpos: (non-simple types only): the first vptr comes first */ 0 /* index */); } } // Past-the-end iterator: explicit iterator(size_t end) : curr(end) {} public: bool operator==(const iterator &other) const { return curr.index == other.curr.index; } bool operator!=(const iterator &other) const { return curr.index != other.curr.index; } iterator &operator++() { if (!inst->simple_layout) { curr.vh += 1 + (*types)[curr.index]->holder_size_in_ptrs; } ++curr.index; curr.type = curr.index < types->size() ? (*types)[curr.index] : nullptr; return *this; } value_and_holder &operator*() { return curr; } value_and_holder *operator->() { return &curr; } }; iterator begin() { return iterator(inst, &tinfo); } iterator end() { return iterator(tinfo.size()); } iterator find(const type_info *find_type) { auto it = begin(), endit = end(); while (it != endit && it->type != find_type) { ++it; } return it; } size_t size() { return tinfo.size(); } // Band-aid workaround to fix a subtle but serious bug in a minimalistic fashion. See PR #4762. bool is_redundant_value_and_holder(const value_and_holder &vh) { for (size_t i = 0; i < vh.index; i++) { if (PyType_IsSubtype(tinfo[i]->type, tinfo[vh.index]->type) != 0) { return true; } } return false; } }; /** * Extracts C++ value and holder pointer references from an instance (which may contain multiple * values/holders for python-side multiple inheritance) that match the given type. Throws an error * if the given type (or ValueType, if omitted) is not a pybind11 base of the given instance. If * `find_type` is omitted (or explicitly specified as nullptr) the first value/holder are returned, * regardless of type (and the resulting .type will be nullptr). * * The returned object should be short-lived: in particular, it must not outlive the called-upon * instance. */ PYBIND11_NOINLINE value_and_holder instance::get_value_and_holder(const type_info *find_type /*= nullptr default in common.h*/, bool throw_if_missing /*= true in common.h*/) { // Optimize common case: if (!find_type || Py_TYPE(this) == find_type->type) { return value_and_holder(this, find_type, 0, 0); } detail::values_and_holders vhs(this); auto it = vhs.find(find_type); if (it != vhs.end()) { return *it; } if (!throw_if_missing) { return value_and_holder(); } #if defined(PYBIND11_DETAILED_ERROR_MESSAGES) pybind11_fail("pybind11::detail::instance::get_value_and_holder: `" + get_fully_qualified_tp_name(find_type->type) + "' is not a pybind11 base of the given `" + get_fully_qualified_tp_name(Py_TYPE(this)) + "' instance"); #else pybind11_fail( "pybind11::detail::instance::get_value_and_holder: " "type is not a pybind11 base of the given instance " "(#define PYBIND11_DETAILED_ERROR_MESSAGES or compile in debug mode for type details)"); #endif } PYBIND11_NOINLINE void instance::allocate_layout() { const auto &tinfo = all_type_info(Py_TYPE(this)); const size_t n_types = tinfo.size(); if (n_types == 0) { pybind11_fail( "instance allocation failed: new instance has no pybind11-registered base types"); } simple_layout = n_types == 1 && tinfo.front()->holder_size_in_ptrs <= instance_simple_holder_in_ptrs(); // Simple path: no python-side multiple inheritance, and a small-enough holder if (simple_layout) { simple_value_holder[0] = nullptr; simple_holder_constructed = false; simple_instance_registered = false; } else { // multiple base types or a too-large holder // Allocate space to hold: [v1*][h1][v2*][h2]...[bb...] where [vN*] is a value pointer, // [hN] is the (uninitialized) holder instance for value N, and [bb...] is a set of bool // values that tracks whether each associated holder has been initialized. Each [block] is // padded, if necessary, to an integer multiple of sizeof(void *). size_t space = 0; for (auto *t : tinfo) { space += 1; // value pointer space += t->holder_size_in_ptrs; // holder instance } size_t flags_at = space; space += size_in_ptrs(n_types); // status bytes (holder_constructed and // instance_registered) // Allocate space for flags, values, and holders, and initialize it to 0 (flags and values, // in particular, need to be 0). Use Python's memory allocation // functions: Python is using pymalloc, which is designed to be // efficient for small allocations like the one we're doing here; // for larger allocations they are just wrappers around malloc. // TODO: is this still true for pure Python 3.6? nonsimple.values_and_holders = static_cast(PyMem_Calloc(space, sizeof(void *))); if (!nonsimple.values_and_holders) { throw std::bad_alloc(); } nonsimple.status = reinterpret_cast(&nonsimple.values_and_holders[flags_at]); } owned = true; } // NOLINTNEXTLINE(readability-make-member-function-const) PYBIND11_NOINLINE void instance::deallocate_layout() { if (!simple_layout) { PyMem_Free(reinterpret_cast(nonsimple.values_and_holders)); } } PYBIND11_NOINLINE bool isinstance_generic(handle obj, const std::type_info &tp) { handle type = detail::get_type_handle(tp, false); if (!type) { return false; } return isinstance(obj, type); } PYBIND11_NOINLINE handle get_object_handle(const void *ptr, const detail::type_info *type) { return with_instance_map(ptr, [&](instance_map &instances) { auto range = instances.equal_range(ptr); for (auto it = range.first; it != range.second; ++it) { for (const auto &vh : values_and_holders(it->second)) { if (vh.type == type) { return handle(reinterpret_cast(it->second)); } } } return handle(); }); } // Information about how type_caster_generic::cast() can obtain its source object struct cast_sources { // A type-erased pointer and the type it points to struct raw_source { const void *cppobj; const std::type_info *cpptype; }; // A C++ pointer and the Python type info we will convert it to; // we expect that cppobj points to something of type tinfo->cpptype struct resolved_source { const void *cppobj; const type_info *tinfo; }; // Use the given pointer with its compile-time type, possibly downcast // via polymorphic_type_hook() template explicit cast_sources(const itype *ptr); // Use the given pointer and type // NOLINTNEXTLINE(google-explicit-constructor) cast_sources(const raw_source &orig) : original(orig) { result = resolve(); } // Use the given object and pybind11 type info. NB: if tinfo is null, // this does not provide enough information to use a foreign type or // to render a useful error message cast_sources(const void *obj, const detail::type_info *tinfo) : original{obj, tinfo ? tinfo->cpptype : nullptr}, result{obj, tinfo} {} // The object passed to cast(), with its static type. // original.type must not be null if resolve() will be called. // original.obj may be null if we're converting nullptr to a Python None raw_source original; // A more-derived version of `original` provided by a // polymorphic_type_hook. downcast.type may be null if this is not // a relevant concept for the current cast. raw_source downcast{}; // The source to use for this cast, and the corresponding pybind11 // type_info. If the type_info is null, then pybind11 doesn't know // about this type. resolved_source result; // Returns true if the cast will use a pybind11 type that uses // a smart holder. bool creates_smart_holder() const { return result.tinfo != nullptr && result.tinfo->holder_enum_v == detail::holder_enum_t::smart_holder; } private: resolved_source resolve() { if (downcast.cpptype) { if (same_type(*original.cpptype, *downcast.cpptype)) { downcast.cpptype = nullptr; } else if (const auto *tpi = get_type_info(*downcast.cpptype)) { return {downcast.cppobj, tpi}; } } if (const auto *tpi = get_type_info(*original.cpptype)) { return {original.cppobj, tpi}; } return {nullptr, nullptr}; } }; // Forward declarations void keep_alive_impl(handle nurse, handle patient); inline PyObject *make_new_instance(PyTypeObject *type); PYBIND11_WARNING_PUSH PYBIND11_WARNING_DISABLE_GCC("-Wredundant-decls") // PYBIND11:REMINDER: Needs refactoring of existing pybind11 code. inline bool deregister_instance(instance *self, void *valptr, const type_info *tinfo); PYBIND11_WARNING_POP PYBIND11_NAMESPACE_BEGIN(smart_holder_type_caster_support) struct value_and_holder_helper { value_and_holder loaded_v_h; bool have_holder() const { return loaded_v_h.vh != nullptr && loaded_v_h.holder_constructed(); } smart_holder &holder() const { return loaded_v_h.holder(); } void throw_if_uninitialized_or_disowned_holder(const char *typeid_name) const { static const std::string missing_value_msg = "Missing value for wrapped C++ type `"; if (!holder().is_populated) { throw value_error(missing_value_msg + clean_type_id(typeid_name) + "`: Python instance is uninitialized."); } if (!holder().has_pointee()) { throw value_error(missing_value_msg + clean_type_id(typeid_name) + "`: Python instance was disowned."); } } void throw_if_uninitialized_or_disowned_holder(const std::type_info &type_info) const { throw_if_uninitialized_or_disowned_holder(type_info.name()); } // have_holder() must be true or this function will fail. void throw_if_instance_is_currently_owned_by_shared_ptr(const type_info *tinfo) const { auto *vptr_gd_ptr = tinfo->get_memory_guarded_delete(holder().vptr); if (vptr_gd_ptr != nullptr && !vptr_gd_ptr->released_ptr.expired()) { throw value_error("Python instance is currently owned by a std::shared_ptr."); } } void *get_void_ptr_or_nullptr() const { if (have_holder()) { auto &hld = holder(); if (hld.is_populated && hld.has_pointee()) { return hld.template as_raw_ptr_unowned(); } } return nullptr; } }; template handle smart_holder_from_unique_ptr(std::unique_ptr &&src, return_value_policy policy, handle parent, const cast_sources::resolved_source &cs) { if (policy == return_value_policy::copy) { throw cast_error("return_value_policy::copy is invalid for unique_ptr."); } if (!src) { return none().release(); } // cs.cppobj is the subobject pointer appropriate for tinfo (may differ from src.get() // under MI/VI). Use this for Python identity/registration, but keep ownership on T*. void *src_raw_void_ptr = const_cast(cs.cppobj); assert(cs.tinfo != nullptr); const detail::type_info *tinfo = cs.tinfo; if (handle existing_inst = find_registered_python_instance(src_raw_void_ptr, tinfo)) { auto *self_life_support = tinfo->get_trampoline_self_life_support(src.get()); if (self_life_support != nullptr) { value_and_holder &v_h = self_life_support->v_h; if (v_h.inst != nullptr && v_h.vh != nullptr) { auto &holder = v_h.holder(); if (!holder.is_disowned) { pybind11_fail("smart_holder_from_unique_ptr: unexpected " "smart_holder.is_disowned failure."); } // Critical transfer-of-ownership section. This must stay together. self_life_support->deactivate_life_support(); holder.reclaim_disowned(tinfo->get_memory_guarded_delete); (void) src.release(); // Critical section end. return existing_inst; } } throw cast_error("Invalid unique_ptr: another instance owns this pointer already."); } auto inst = reinterpret_steal(make_new_instance(tinfo->type)); auto *inst_raw_ptr = reinterpret_cast(inst.ptr()); inst_raw_ptr->owned = true; void *&valueptr = values_and_holders(inst_raw_ptr).begin()->value_ptr(); valueptr = src_raw_void_ptr; if (static_cast(src.get()) == src_raw_void_ptr) { // This is a multiple-inheritance situation that is incompatible with the current // shared_from_this handling (see PR #3023). Is there a better solution? src_raw_void_ptr = nullptr; } auto smhldr = smart_holder::from_unique_ptr(std::move(src), src_raw_void_ptr); tinfo->init_instance(inst_raw_ptr, static_cast(&smhldr)); if (policy == return_value_policy::reference_internal) { keep_alive_impl(inst, parent); } return inst.release(); } template handle smart_holder_from_unique_ptr(std::unique_ptr &&src, return_value_policy policy, handle parent, const cast_sources::resolved_source &cs) { return smart_holder_from_unique_ptr( std::unique_ptr(const_cast(src.release()), std::move(src.get_deleter())), // Const2Mutbl policy, parent, cs); } template handle smart_holder_from_shared_ptr(const std::shared_ptr &src, return_value_policy policy, handle parent, const cast_sources::resolved_source &cs) { switch (policy) { case return_value_policy::automatic: case return_value_policy::automatic_reference: break; case return_value_policy::take_ownership: throw cast_error("Invalid return_value_policy for shared_ptr (take_ownership)."); case return_value_policy::copy: case return_value_policy::move: break; case return_value_policy::reference: throw cast_error("Invalid return_value_policy for shared_ptr (reference)."); case return_value_policy::reference_internal: break; } if (!src) { return none().release(); } // cs.cppobj is the subobject pointer appropriate for tinfo (may differ from src.get() // under MI/VI). Use this for Python identity/registration, but keep ownership on T*. void *src_raw_void_ptr = const_cast(cs.cppobj); assert(cs.tinfo != nullptr); const detail::type_info *tinfo = cs.tinfo; if (handle existing_inst = find_registered_python_instance(src_raw_void_ptr, tinfo)) { // PYBIND11:REMINDER: MISSING: Enforcement of consistency with existing smart_holder. // PYBIND11:REMINDER: MISSING: keep_alive. return existing_inst; } auto inst = reinterpret_steal(make_new_instance(tinfo->type)); auto *inst_raw_ptr = reinterpret_cast(inst.ptr()); inst_raw_ptr->owned = true; void *&valueptr = values_and_holders(inst_raw_ptr).begin()->value_ptr(); valueptr = src_raw_void_ptr; auto smhldr = smart_holder::from_shared_ptr(std::shared_ptr(src, src_raw_void_ptr)); tinfo->init_instance(inst_raw_ptr, static_cast(&smhldr)); if (policy == return_value_policy::reference_internal) { keep_alive_impl(inst, parent); } return inst.release(); } template handle smart_holder_from_shared_ptr(const std::shared_ptr &src, return_value_policy policy, handle parent, const cast_sources::resolved_source &cs) { return smart_holder_from_shared_ptr(std::const_pointer_cast(src), // Const2Mutbl policy, parent, cs); } struct shared_ptr_parent_life_support { PyObject *parent; explicit shared_ptr_parent_life_support(PyObject *parent) : parent{parent} { Py_INCREF(parent); } // NOLINTNEXTLINE(readability-make-member-function-const) void operator()(void *) { gil_scoped_acquire gil; Py_DECREF(parent); } }; struct shared_ptr_trampoline_self_life_support { PyObject *self; explicit shared_ptr_trampoline_self_life_support(instance *inst) : self{reinterpret_cast(inst)} { gil_scoped_acquire gil; Py_INCREF(self); } // NOLINTNEXTLINE(readability-make-member-function-const) void operator()(void *) { gil_scoped_acquire gil; Py_DECREF(self); } }; template ::value, int>::type = 0> inline std::unique_ptr unique_with_deleter(T *raw_ptr, std::unique_ptr &&deleter) { if (deleter == nullptr) { return std::unique_ptr(raw_ptr); } return std::unique_ptr(raw_ptr, std::move(*deleter)); } template ::value, int>::type = 0> inline std::unique_ptr unique_with_deleter(T *raw_ptr, std::unique_ptr &&deleter) { if (deleter == nullptr) { pybind11_fail("smart_holder_type_casters: deleter is not default constructible and no" " instance available to return."); } return std::unique_ptr(raw_ptr, std::move(*deleter)); } template struct load_helper : value_and_holder_helper { bool was_populated = false; bool python_instance_is_alias = false; void maybe_set_python_instance_is_alias(handle src) { if (was_populated) { python_instance_is_alias = reinterpret_cast(src.ptr())->is_alias; } } static std::shared_ptr make_shared_ptr_with_responsible_parent(T *raw_ptr, handle parent) { return std::shared_ptr(raw_ptr, shared_ptr_parent_life_support(parent.ptr())); } std::shared_ptr load_as_shared_ptr(const type_info *tinfo, void *void_raw_ptr, handle responsible_parent = nullptr, // to support py::potentially_slicing_weak_ptr // with minimal added code complexity: bool force_potentially_slicing_shared_ptr = false) const { if (!have_holder()) { return nullptr; } throw_if_uninitialized_or_disowned_holder(typeid(T)); smart_holder &hld = holder(); hld.ensure_is_not_disowned("load_as_shared_ptr"); if (hld.vptr_is_using_noop_deleter) { if (responsible_parent) { return make_shared_ptr_with_responsible_parent(static_cast(void_raw_ptr), responsible_parent); } throw std::runtime_error("Non-owning holder (load_as_shared_ptr)."); } auto *type_raw_ptr = static_cast(void_raw_ptr); if (python_instance_is_alias && !force_potentially_slicing_shared_ptr) { auto *vptr_gd_ptr = tinfo->get_memory_guarded_delete(holder().vptr); if (vptr_gd_ptr != nullptr) { std::shared_ptr released_ptr = vptr_gd_ptr->released_ptr.lock(); if (released_ptr) { return std::shared_ptr(released_ptr, type_raw_ptr); } std::shared_ptr to_be_released( type_raw_ptr, shared_ptr_trampoline_self_life_support(loaded_v_h.inst)); vptr_gd_ptr->released_ptr = to_be_released; return to_be_released; } auto *sptsls_ptr = std::get_deleter(hld.vptr); if (sptsls_ptr != nullptr) { // This code is reachable only if there are multiple registered_instances for the // same pointee. if (reinterpret_cast(loaded_v_h.inst) == sptsls_ptr->self) { pybind11_fail("smart_holder_type_caster_support load_as_shared_ptr failure: " "loaded_v_h.inst == sptsls_ptr->self"); } } if (sptsls_ptr != nullptr || !memory::type_has_shared_from_this(type_raw_ptr)) { return std::shared_ptr( type_raw_ptr, shared_ptr_trampoline_self_life_support(loaded_v_h.inst)); } if (hld.vptr_is_external_shared_ptr) { pybind11_fail("smart_holder_type_casters load_as_shared_ptr failure: not " "implemented: trampoline-self-life-support for external shared_ptr " "to type inheriting from std::enable_shared_from_this."); } pybind11_fail( "smart_holder_type_casters: load_as_shared_ptr failure: internal inconsistency."); } std::shared_ptr void_shd_ptr = hld.template as_shared_ptr(); return std::shared_ptr(void_shd_ptr, type_raw_ptr); } template std::unique_ptr load_as_unique_ptr(const type_info *tinfo, void *raw_void_ptr, const char *context = "load_as_unique_ptr") { if (!have_holder()) { return unique_with_deleter(nullptr, std::unique_ptr()); } throw_if_uninitialized_or_disowned_holder(typeid(T)); throw_if_instance_is_currently_owned_by_shared_ptr(tinfo); holder().ensure_is_not_disowned(context); holder().template ensure_compatible_uqp_del(context); holder().ensure_use_count_1(context); T *raw_type_ptr = static_cast(raw_void_ptr); auto *self_life_support = tinfo->get_trampoline_self_life_support(raw_type_ptr); // This is enforced indirectly by a static_assert in the class_ implementation: assert(!python_instance_is_alias || self_life_support); std::unique_ptr extracted_deleter = holder().template extract_deleter(context, tinfo->get_memory_guarded_delete); // Critical transfer-of-ownership section. This must stay together. if (self_life_support != nullptr) { holder().disown(tinfo->get_memory_guarded_delete); } else { holder().release_ownership(tinfo->get_memory_guarded_delete); } auto result = unique_with_deleter(raw_type_ptr, std::move(extracted_deleter)); if (self_life_support != nullptr) { self_life_support->activate_life_support(loaded_v_h); } else { void *value_void_ptr = loaded_v_h.value_ptr(); loaded_v_h.value_ptr() = nullptr; deregister_instance(loaded_v_h.inst, value_void_ptr, loaded_v_h.type); } // Critical section end. return result; } // This assumes load_as_shared_ptr succeeded(), and the returned shared_ptr is still alive. // The returned unique_ptr is meant to never expire (the behavior is undefined otherwise). template std::unique_ptr load_as_const_unique_ptr(const type_info *tinfo, T *raw_type_ptr, const char *context = "load_as_const_unique_ptr") { if (!have_holder()) { return unique_with_deleter(nullptr, std::unique_ptr()); } holder().template ensure_compatible_uqp_del(context); return unique_with_deleter(raw_type_ptr, std::move(holder().template extract_deleter( context, tinfo->get_memory_guarded_delete))); } }; PYBIND11_NAMESPACE_END(smart_holder_type_caster_support) class type_caster_generic { public: PYBIND11_NOINLINE explicit type_caster_generic(const std::type_info &type_info) : typeinfo(get_type_info(type_info)), cpptype(&type_info) {} explicit type_caster_generic(const type_info *typeinfo) : typeinfo(typeinfo), cpptype(typeinfo ? typeinfo->cpptype : nullptr) {} bool load(handle src, bool convert) { return load_impl(src, convert); } static handle cast(const void *src, return_value_policy policy, handle parent, const detail::type_info *tinfo, void *(*copy_constructor)(const void *), void *(*move_constructor)(const void *), const void *existing_holder = nullptr) { cast_sources srcs{src, tinfo}; return cast(srcs, policy, parent, copy_constructor, move_constructor, existing_holder); } static handle cast_non_owning(const cast_sources &srcs, return_value_policy policy, handle parent, const void *existing_holder = nullptr) { // Reference-like policies alias an existing C++ object instead of creating // a new one, so copy/move constructor callbacks must remain null here. assert(policy == return_value_policy::reference || policy == return_value_policy::reference_internal || policy == return_value_policy::automatic_reference); return cast(srcs, policy, parent, nullptr, nullptr, existing_holder); } PYBIND11_NOINLINE static handle cast(const cast_sources &srcs, return_value_policy policy, handle parent, void *(*copy_constructor)(const void *), void *(*move_constructor)(const void *), const void *existing_holder = nullptr) { if (!srcs.result.tinfo) { // No pybind11 type info. Raise an exception. std::string tname = srcs.downcast.cpptype ? srcs.downcast.cpptype->name() : srcs.original.cpptype ? srcs.original.cpptype->name() : ""; detail::clean_type_id(tname); std::string msg = "Unregistered type : " + tname; set_error(PyExc_TypeError, msg.c_str()); return handle(); } void *src = const_cast(srcs.result.cppobj); if (src == nullptr) { return none().release(); } const type_info *tinfo = srcs.result.tinfo; if (handle registered_inst = find_registered_python_instance(src, tinfo)) { return registered_inst; } auto inst = reinterpret_steal(make_new_instance(tinfo->type)); auto *wrapper = reinterpret_cast(inst.ptr()); wrapper->owned = false; void *&valueptr = values_and_holders(wrapper).begin()->value_ptr(); switch (policy) { case return_value_policy::automatic: case return_value_policy::take_ownership: valueptr = src; wrapper->owned = true; break; case return_value_policy::automatic_reference: case return_value_policy::reference: valueptr = src; wrapper->owned = false; break; case return_value_policy::copy: if (copy_constructor) { valueptr = copy_constructor(src); } else { #if defined(PYBIND11_DETAILED_ERROR_MESSAGES) std::string type_name(tinfo->cpptype->name()); detail::clean_type_id(type_name); throw cast_error("return_value_policy = copy, but type " + type_name + " is non-copyable!"); #else throw cast_error("return_value_policy = copy, but type is " "non-copyable! (#define PYBIND11_DETAILED_ERROR_MESSAGES or " "compile in debug mode for details)"); #endif } wrapper->owned = true; break; case return_value_policy::move: if (move_constructor) { valueptr = move_constructor(src); } else if (copy_constructor) { valueptr = copy_constructor(src); } else { #if defined(PYBIND11_DETAILED_ERROR_MESSAGES) std::string type_name(tinfo->cpptype->name()); detail::clean_type_id(type_name); throw cast_error("return_value_policy = move, but type " + type_name + " is neither movable nor copyable!"); #else throw cast_error("return_value_policy = move, but type is neither " "movable nor copyable! " "(#define PYBIND11_DETAILED_ERROR_MESSAGES or compile in " "debug mode for details)"); #endif } wrapper->owned = true; break; case return_value_policy::reference_internal: valueptr = src; wrapper->owned = false; keep_alive_impl(inst, parent); break; default: throw cast_error("unhandled return_value_policy: should not happen!"); } tinfo->init_instance(wrapper, existing_holder); return inst.release(); } // Base methods for generic caster; there are overridden in copyable_holder_caster void load_value(value_and_holder &&v_h) { if (typeinfo->holder_enum_v == detail::holder_enum_t::smart_holder) { smart_holder_type_caster_support::value_and_holder_helper v_h_helper; v_h_helper.loaded_v_h = v_h; if (v_h_helper.have_holder()) { v_h_helper.throw_if_uninitialized_or_disowned_holder(cpptype->name()); value = v_h_helper.holder().template as_raw_ptr_unowned(); return; } } auto *&vptr = v_h.value_ptr(); // Lazy allocation for unallocated values: if (vptr == nullptr) { const auto *type = v_h.type ? v_h.type : typeinfo; if (type->operator_new) { vptr = type->operator_new(type->type_size); } else { #if defined(__cpp_aligned_new) if (type->type_align > __STDCPP_DEFAULT_NEW_ALIGNMENT__) { vptr = ::operator new(type->type_size, std::align_val_t(type->type_align)); } else { vptr = ::operator new(type->type_size); } #else vptr = ::operator new(type->type_size); #endif } } value = vptr; } bool try_implicit_casts(handle src, bool convert) { for (const auto &cast : typeinfo->implicit_casts) { type_caster_generic sub_caster(*cast.first); if (sub_caster.load(src, convert)) { value = cast.second(sub_caster.value); return true; } } return false; } bool try_direct_conversions(handle src) { for (auto &converter : *typeinfo->direct_conversions) { if (converter(src.ptr(), value)) { return true; } } return false; } bool try_cpp_conduit(handle src) { value = try_raw_pointer_ephemeral_from_cpp_conduit(src, cpptype); if (value != nullptr) { return true; } return false; } void check_holder_compat() {} bool set_foreign_holder(handle) { return true; } PYBIND11_NOINLINE static void *local_load(PyObject *src, const type_info *ti) { auto caster = type_caster_generic(ti); if (caster.load(src, false)) { return caster.value; } return nullptr; } /// Try to load with foreign typeinfo, if available. Used when there is no /// native typeinfo, or when the native one wasn't able to produce a value. PYBIND11_NOINLINE bool try_load_foreign_module_local(handle src) { constexpr auto *local_key = PYBIND11_MODULE_LOCAL_ID; const auto pytype = type::handle_of(src); if (!hasattr(pytype, local_key)) { return false; } type_info *foreign_typeinfo = reinterpret_borrow(getattr(pytype, local_key)); // Only consider this foreign loader if actually foreign and is a loader of the correct cpp // type if (foreign_typeinfo->module_local_load == &local_load || (cpptype && !same_type(*cpptype, *foreign_typeinfo->cpptype))) { return false; } if (auto *result = foreign_typeinfo->module_local_load(src.ptr(), foreign_typeinfo)) { value = result; return true; } return false; } // Implementation of `load`; this takes the type of `this` so that it can dispatch the relevant // bits of code between here and copyable_holder_caster where the two classes need different // logic (without having to resort to virtual inheritance). template PYBIND11_NOINLINE bool load_impl(handle src, bool convert) { auto &this_ = static_cast(*this); if (!src) { return false; } if (!typeinfo) { return try_load_foreign_module_local(src) && this_.set_foreign_holder(src); } this_.check_holder_compat(); PyTypeObject *srctype = Py_TYPE(src.ptr()); // Case 1: If src is an exact type match for the target type then we can reinterpret_cast // the instance's value pointer to the target type: if (srctype == typeinfo->type) { this_.load_value(reinterpret_cast(src.ptr())->get_value_and_holder()); return true; } // Case 2: We have a derived class if (PyType_IsSubtype(srctype, typeinfo->type)) { const auto &bases = all_type_info(srctype); bool no_cpp_mi = typeinfo->simple_type; // Case 2a: the python type is a Python-inherited derived class that inherits from just // one simple (no MI) pybind11 class, or is an exact match, so the C++ instance is of // the right type and we can use reinterpret_cast. // (This is essentially the same as case 2b, but because not using multiple inheritance // is extremely common, we handle it specially to avoid the loop iterator and type // pointer lookup overhead) if (bases.size() == 1 && (no_cpp_mi || bases.front()->type == typeinfo->type)) { this_.load_value(reinterpret_cast(src.ptr())->get_value_and_holder()); return true; } // Case 2b: the python type inherits from multiple C++ bases. Check the bases to see // if we can find an exact match (or, for a simple C++ type, an inherited match); if // so, we can safely reinterpret_cast to the relevant pointer. if (bases.size() > 1) { for (auto *base : bases) { if (no_cpp_mi ? PyType_IsSubtype(base->type, typeinfo->type) : base->type == typeinfo->type) { this_.load_value( reinterpret_cast(src.ptr())->get_value_and_holder(base)); return true; } } } // Case 2c: C++ multiple inheritance is involved and we couldn't find an exact type // match in the registered bases, above, so try implicit casting (needed for proper C++ // casting when MI is involved). if (this_.try_implicit_casts(src, convert)) { return true; } } // Perform an implicit conversion if (convert) { for (const auto &converter : typeinfo->implicit_conversions) { auto temp = reinterpret_steal(converter(src.ptr(), typeinfo->type)); if (load_impl(temp, false)) { loader_life_support::add_patient(temp); return true; } } if (this_.try_direct_conversions(src)) { return true; } } // Failed to match local typeinfo. Try again with global. if (typeinfo->module_local) { if (auto *gtype = get_global_type_info(*typeinfo->cpptype)) { typeinfo = gtype; return load_impl(src, false); } } // Global typeinfo has precedence over foreign module_local if (try_load_foreign_module_local(src)) { return this_.set_foreign_holder(src); } // Custom converters didn't take None, now we convert None to nullptr. if (src.is_none()) { // Defer accepting None to other overloads (if we aren't in convert mode): if (!convert) { return false; } value = nullptr; return true; } if (convert && cpptype && this_.try_cpp_conduit(src)) { return this_.set_foreign_holder(src); } return false; } const type_info *typeinfo = nullptr; const std::type_info *cpptype = nullptr; void *value = nullptr; }; inline object cpp_conduit_method(handle self, const bytes &pybind11_platform_abi_id, const capsule &cpp_type_info_capsule, const bytes &pointer_kind) { #ifdef PYBIND11_HAS_STRING_VIEW using cpp_str = std::string_view; #else using cpp_str = std::string; #endif if (cpp_str(pybind11_platform_abi_id) != PYBIND11_PLATFORM_ABI_ID) { return none(); } if (std::strcmp(cpp_type_info_capsule.name(), typeid(std::type_info).name()) != 0) { return none(); } if (cpp_str(pointer_kind) != "raw_pointer_ephemeral") { throw std::runtime_error("Invalid pointer_kind: \"" + std::string(pointer_kind) + "\""); } const auto *cpp_type_info = cpp_type_info_capsule.get_pointer(); type_caster_generic caster(*cpp_type_info); if (!caster.load(self, false)) { return none(); } return capsule(caster.value, cpp_type_info->name()); } /** * Determine suitable casting operator for pointer-or-lvalue-casting type casters. The type caster * needs to provide `operator T*()` and `operator T&()` operators. * * If the type supports moving the value away via an `operator T&&() &&` method, it should use * `movable_cast_op_type` instead. */ template using cast_op_type = conditional_t>::value, typename std::add_pointer>::type, typename std::add_lvalue_reference>::type>; /** * Determine suitable casting operator for a type caster with a movable value. Such a type caster * needs to provide `operator T*()`, `operator T&()`, and `operator T&&() &&`. The latter will be * called in appropriate contexts where the value can be moved rather than copied. * * These operator are automatically provided when using the PYBIND11_TYPE_CASTER macro. */ template using movable_cast_op_type = conditional_t::type>::value, typename std::add_pointer>::type, conditional_t::value, typename std::add_rvalue_reference>::type, typename std::add_lvalue_reference>::type>>; // Does the container have a mapped type and is it recursive? // Implemented by specializations below. template struct container_mapped_type_traits { static constexpr bool has_mapped_type = false; static constexpr bool has_recursive_mapped_type = false; }; template struct container_mapped_type_traits< Container, typename std::enable_if< std::is_same::value>::type> { static constexpr bool has_mapped_type = true; static constexpr bool has_recursive_mapped_type = true; }; template struct container_mapped_type_traits< Container, typename std::enable_if< negation>::value>::type> { static constexpr bool has_mapped_type = true; static constexpr bool has_recursive_mapped_type = false; }; // Does the container have a value type and is it recursive? // Implemented by specializations below. template struct container_value_type_traits : std::false_type { static constexpr bool has_value_type = false; static constexpr bool has_recursive_value_type = false; }; template struct container_value_type_traits< Container, typename std::enable_if< std::is_same::value>::type> { static constexpr bool has_value_type = true; static constexpr bool has_recursive_value_type = true; }; template struct container_value_type_traits< Container, typename std::enable_if< negation>::value>::type> { static constexpr bool has_value_type = true; static constexpr bool has_recursive_value_type = false; }; /* * Tag to be used for representing the bottom of recursively defined types. * Define this tag so we don't have to use void. */ struct recursive_bottom {}; /* * Implementation detail of `recursive_container_traits` below. * `T` is the `value_type` of the container, which might need to be modified to * avoid recursive types and const types. */ template struct impl_type_to_check_recursively { /* * If the container is recursive, then no further recursion should be done. */ using if_recursive = recursive_bottom; /* * Otherwise yield `T` unchanged. */ using if_not_recursive = T; }; /* * For pairs - only as value type of a map -, the first type should remove the `const`. * Also, if the map is recursive, then the recursive checking should consider * the first type only. */ template struct impl_type_to_check_recursively, /* is_this_a_map = */ true> { using if_recursive = typename std::remove_const::type; using if_not_recursive = std::pair::type, B>; }; /* * Implementation of `recursive_container_traits` below. */ template struct impl_recursive_container_traits { using type_to_check_recursively = recursive_bottom; }; template struct impl_recursive_container_traits< Container, typename std::enable_if::has_value_type>::type> { static constexpr bool is_recursive = container_mapped_type_traits::has_recursive_mapped_type || container_value_type_traits::has_recursive_value_type; /* * This member dictates which type Pybind11 should check recursively in traits * such as `is_move_constructible`, `is_copy_constructible`, `is_move_assignable`, ... * Direct access to `value_type` should be avoided: * 1. `value_type` might recursively contain the type again * 2. `value_type` of STL map types is `std::pair`, the `const` * should be removed. * */ using type_to_check_recursively = typename std::conditional< is_recursive, typename impl_type_to_check_recursively< typename Container::value_type, container_mapped_type_traits::has_mapped_type>::if_recursive, typename impl_type_to_check_recursively< typename Container::value_type, container_mapped_type_traits::has_mapped_type>::if_not_recursive>::type; }; /* * This trait defines the `type_to_check_recursively` which is needed to properly * handle recursively defined traits such as `is_move_constructible` without going * into an infinite recursion. * Should be used instead of directly accessing the `value_type`. * It cancels the recursion by returning the `recursive_bottom` tag. * * The default definition of `type_to_check_recursively` is as follows: * * 1. By default, it is `recursive_bottom`, so that the recursion is canceled. * 2. If the type is non-recursive and defines a `value_type`, then the `value_type` is used. * If the `value_type` is a pair and a `mapped_type` is defined, * then the `const` is removed from the first type. * 3. If the type is recursive and `value_type` is not a pair, then `recursive_bottom` is returned. * 4. If the type is recursive and `value_type` is a pair and a `mapped_type` is defined, * then `const` is removed from the first type and the first type is returned. * * This behavior can be extended by the user as seen in test_stl_binders.cpp. * * This struct is exactly the same as impl_recursive_container_traits. * The duplication achieves that user-defined specializations don't compete * with internal specializations, but take precedence. */ template struct recursive_container_traits : impl_recursive_container_traits {}; template struct is_move_constructible : all_of, is_move_constructible< typename recursive_container_traits::type_to_check_recursively>> {}; template <> struct is_move_constructible : std::true_type {}; // Likewise for std::pair // (after C++17 it is mandatory that the move constructor not exist when the two types aren't // themselves move constructible, but this can not be relied upon when T1 or T2 are themselves // containers). template struct is_move_constructible> : all_of, is_move_constructible> {}; // std::is_copy_constructible isn't quite enough: it lets std::vector (and similar) through when // T is non-copyable, but code containing such a copy constructor fails to actually compile. template struct is_copy_constructible : all_of, is_copy_constructible< typename recursive_container_traits::type_to_check_recursively>> {}; template <> struct is_copy_constructible : std::true_type {}; // Likewise for std::pair // (after C++17 it is mandatory that the copy constructor not exist when the two types aren't // themselves copy constructible, but this can not be relied upon when T1 or T2 are themselves // containers). template struct is_copy_constructible> : all_of, is_copy_constructible> {}; // The same problems arise with std::is_copy_assignable, so we use the same workaround. template struct is_copy_assignable : all_of< std::is_copy_assignable, is_copy_assignable::type_to_check_recursively>> { }; template <> struct is_copy_assignable : std::true_type {}; template struct is_copy_assignable> : all_of, is_copy_assignable> {}; PYBIND11_NAMESPACE_END(detail) // polymorphic_type_hook::get(src, tinfo) determines whether the object pointed // to by `src` actually is an instance of some class derived from `itype`. // If so, it sets `tinfo` to point to the std::type_info representing that derived // type, and returns a pointer to the start of the most-derived object of that type // (in which `src` is a subobject; this will be the same address as `src` in most // single inheritance cases). If not, or if `src` is nullptr, it simply returns `src` // and leaves `tinfo` at its default value of nullptr. // // The default polymorphic_type_hook just returns src. A specialization for polymorphic // types determines the runtime type of the passed object and adjusts the this-pointer // appropriately via dynamic_cast. This is what enables a C++ Animal* to appear // to Python as a Dog (if Dog inherits from Animal, Animal is polymorphic, Dog is // registered with pybind11, and this Animal is in fact a Dog). // // You may specialize polymorphic_type_hook yourself for types that want to appear // polymorphic to Python but do not use C++ RTTI. (This is a not uncommon pattern // in performance-sensitive applications, used most notably in LLVM.) // // polymorphic_type_hook_base allows users to specialize polymorphic_type_hook with // std::enable_if. User provided specializations will always have higher priority than // the default implementation and specialization provided in polymorphic_type_hook_base. template struct polymorphic_type_hook_base { static const void *get(const itype *src, const std::type_info *&) { return src; } }; template struct polymorphic_type_hook_base::value>> { static const void *get(const itype *src, const std::type_info *&type) { type = src ? &typeid(*src) : nullptr; return dynamic_cast(src); } }; template struct polymorphic_type_hook : public polymorphic_type_hook_base {}; PYBIND11_NAMESPACE_BEGIN(detail) template cast_sources::cast_sources(const itype *ptr) : original{ptr, &typeid(itype)} { // If this is a base pointer to a derived type, and the derived type is // registered with pybind11, we want to make the full derived object // available. In the typical case where itype is polymorphic, we get the // correct derived pointer (which may be != base pointer) by a dynamic_cast // to most derived type. If itype is not polymorphic, a user-provided // specialization of polymorphic_type_hook can do the same thing. // If there is no downcast to perform, then the default hook will leave // derived.type set to nullptr, which causes us to ignore derived.obj. downcast.cppobj = polymorphic_type_hook::get(ptr, downcast.cpptype); result = resolve(); } /// Generic type caster for objects stored on the heap template class type_caster_base : public type_caster_generic { using itype = intrinsic_t; public: static constexpr auto name = const_name(); type_caster_base() : type_caster_base(typeid(type)) {} explicit type_caster_base(const std::type_info &info) : type_caster_generic(info) {} // Wrap the generic cast_sources to be only constructible from the type // that's correct in this context, so you can't use type_caster_base // to convert an unrelated B* to Python. struct cast_sources : detail::cast_sources { explicit cast_sources(const itype *ptr) : detail::cast_sources(ptr) {} }; static handle cast(const itype &src, return_value_policy policy, handle parent) { if (policy == return_value_policy::automatic || policy == return_value_policy::automatic_reference) { policy = return_value_policy::copy; } return cast(std::addressof(src), policy, parent); } static handle cast(itype &&src, return_value_policy, handle parent) { return cast(std::addressof(src), return_value_policy::move, parent); } static handle cast(const itype *src, return_value_policy policy, handle parent) { return cast(cast_sources{src}, policy, parent); } static handle cast(const cast_sources &srcs, return_value_policy policy, handle parent) { return type_caster_generic::cast(srcs, policy, parent, make_copy_constructor((const itype *) nullptr), make_move_constructor((const itype *) nullptr)); } static handle cast_holder(const itype *src, const void *holder) { return cast_holder(cast_sources{src}, holder); } static handle cast_holder(const cast_sources &srcs, const void *holder) { auto policy = return_value_policy::take_ownership; return type_caster_generic::cast(srcs, policy, {}, nullptr, nullptr, holder); } template using cast_op_type = detail::cast_op_type; // NOLINTNEXTLINE(google-explicit-constructor) operator itype *() { return (type *) value; } // NOLINTNEXTLINE(google-explicit-constructor) operator itype &() { if (!value) { throw reference_cast_error(); } return *((itype *) value); } protected: using Constructor = void *(*) (const void *); /* Only enabled when the types are {copy,move}-constructible *and* when the type does not have a private operator new implementation. A comma operator is used in the decltype argument to apply SFINAE to the public copy/move constructors.*/ template ::value>> static auto make_copy_constructor(const T *) -> decltype(new T(std::declval()), Constructor{}) { return [](const void *arg) -> void * { return new T(*reinterpret_cast(arg)); }; } template ::value>> static auto make_move_constructor(const T *) -> decltype(new T(std::declval()), Constructor{}) { return [](const void *arg) -> void * { return new T(std::move(*const_cast(reinterpret_cast(arg)))); }; } static Constructor make_copy_constructor(...) { return nullptr; } static Constructor make_move_constructor(...) { return nullptr; } }; inline std::string quote_cpp_type_name(const std::string &cpp_type_name) { return cpp_type_name; // No-op for now. See PR #4888 } PYBIND11_NOINLINE std::string type_info_description(const std::type_info &ti) { if (auto *type_data = get_type_info(ti)) { handle th(reinterpret_cast(type_data->type)); return th.attr("__module__").cast() + '.' + th.attr("__qualname__").cast(); } return quote_cpp_type_name(clean_type_id(ti.name())); } PYBIND11_NAMESPACE_END(detail) PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)