mirror of
https://github.com/pybind/pybind11.git
synced 2024-11-28 16:11:59 +00:00
Splitting out detail/type_caster_base.h from cast.h, with iwyu cleanup. (#2841)
* Splitting out detail/type_caster_base.h from cast.h. * Include cleanup guided by include-what-you-use 0.12 based on clang version 9.0.1-11.
This commit is contained in:
parent
98f9a33c62
commit
0c42250a4e
@ -105,6 +105,7 @@ set(PYBIND11_HEADERS
|
|||||||
include/pybind11/detail/descr.h
|
include/pybind11/detail/descr.h
|
||||||
include/pybind11/detail/init.h
|
include/pybind11/detail/init.h
|
||||||
include/pybind11/detail/internals.h
|
include/pybind11/detail/internals.h
|
||||||
|
include/pybind11/detail/type_caster_base.h
|
||||||
include/pybind11/detail/typeid.h
|
include/pybind11/detail/typeid.h
|
||||||
include/pybind11/attr.h
|
include/pybind11/attr.h
|
||||||
include/pybind11/buffer_info.h
|
include/pybind11/buffer_info.h
|
||||||
|
@ -11,13 +11,21 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "pytypes.h"
|
#include "pytypes.h"
|
||||||
#include "detail/typeid.h"
|
#include "detail/common.h"
|
||||||
#include "detail/descr.h"
|
#include "detail/descr.h"
|
||||||
#include "detail/internals.h"
|
#include "detail/type_caster_base.h"
|
||||||
|
#include "detail/typeid.h"
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <limits>
|
#include <cstring>
|
||||||
|
#include <functional>
|
||||||
|
#include <iosfwd>
|
||||||
|
#include <iterator>
|
||||||
|
#include <memory>
|
||||||
|
#include <string>
|
||||||
#include <tuple>
|
#include <tuple>
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
|
#include <utility>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
#if defined(PYBIND11_CPP17)
|
#if defined(PYBIND11_CPP17)
|
||||||
# if defined(__has_include)
|
# if defined(__has_include)
|
||||||
@ -39,918 +47,6 @@
|
|||||||
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
|
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
|
||||||
PYBIND11_NAMESPACE_BEGIN(detail)
|
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 {
|
|
||||||
public:
|
|
||||||
/// A new patient frame is created when a function is entered
|
|
||||||
loader_life_support() {
|
|
||||||
get_internals().loader_patient_stack.push_back(nullptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// ... and destroyed after it returns
|
|
||||||
~loader_life_support() {
|
|
||||||
auto &stack = get_internals().loader_patient_stack;
|
|
||||||
if (stack.empty())
|
|
||||||
pybind11_fail("loader_life_support: internal error");
|
|
||||||
|
|
||||||
auto ptr = stack.back();
|
|
||||||
stack.pop_back();
|
|
||||||
Py_CLEAR(ptr);
|
|
||||||
|
|
||||||
// A heuristic to reduce the stack's capacity (e.g. after long recursive calls)
|
|
||||||
if (stack.capacity() > 16 && !stack.empty() && stack.capacity() / stack.size() > 2)
|
|
||||||
stack.shrink_to_fit();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// 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) {
|
|
||||||
auto &stack = get_internals().loader_patient_stack;
|
|
||||||
if (stack.empty())
|
|
||||||
throw cast_error("When called outside a bound function, py::cast() cannot "
|
|
||||||
"do Python -> C++ conversions which require the creation "
|
|
||||||
"of temporary values");
|
|
||||||
|
|
||||||
auto &list_ptr = stack.back();
|
|
||||||
if (list_ptr == nullptr) {
|
|
||||||
list_ptr = PyList_New(1);
|
|
||||||
if (!list_ptr)
|
|
||||||
pybind11_fail("loader_life_support: error allocating list");
|
|
||||||
PyList_SET_ITEM(list_ptr, 0, h.inc_ref().ptr());
|
|
||||||
} else {
|
|
||||||
auto result = PyList_Append(list_ptr, h.ptr());
|
|
||||||
if (result == -1)
|
|
||||||
pybind11_fail("loader_life_support: error adding patient");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// 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<decltype(internals::registered_types_py)::iterator, bool> all_type_info_get_cache(PyTypeObject *type);
|
|
||||||
|
|
||||||
// Populates a just-created cache entry.
|
|
||||||
PYBIND11_NOINLINE inline void all_type_info_populate(PyTypeObject *t, std::vector<type_info *> &bases) {
|
|
||||||
std::vector<PyTypeObject *> check;
|
|
||||||
for (handle parent : reinterpret_borrow<tuple>(t->tp_bases))
|
|
||||||
check.push_back((PyTypeObject *) 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) bases.push_back(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<tuple>(type->tp_bases))
|
|
||||||
check.push_back((PyTypeObject *) 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<detail::type_info *> &all_type_info(PyTypeObject *type) {
|
|
||||||
auto ins = all_type_info_get_cache(type);
|
|
||||||
if (ins.second)
|
|
||||||
// New cache entry: populate it
|
|
||||||
all_type_info_populate(type, ins.first->second);
|
|
||||||
|
|
||||||
return ins.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 inline detail::type_info* get_type_info(PyTypeObject *type) {
|
|
||||||
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(const std::type_index &tp) {
|
|
||||||
auto &locals = registered_local_types_cpp();
|
|
||||||
auto it = locals.find(tp);
|
|
||||||
if (it != locals.end())
|
|
||||||
return it->second;
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline detail::type_info *get_global_type_info(const std::type_index &tp) {
|
|
||||||
auto &types = get_internals().registered_types_cpp;
|
|
||||||
auto it = types.find(tp);
|
|
||||||
if (it != types.end())
|
|
||||||
return it->second;
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Return the type info for a given C++ type; on lookup failure can either throw or return nullptr.
|
|
||||||
PYBIND11_NOINLINE inline detail::type_info *get_type_info(const std::type_index &tp,
|
|
||||||
bool throw_if_missing = false) {
|
|
||||||
if (auto ltype = get_local_type_info(tp))
|
|
||||||
return ltype;
|
|
||||||
if (auto gtype = get_global_type_info(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 \"" + tname + "\"");
|
|
||||||
}
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
PYBIND11_NOINLINE inline 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 ? ((PyObject *) type_info->type) : nullptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Searches the inheritance graph for a registered Python instance, using all_type_info().
|
|
||||||
PYBIND11_NOINLINE inline handle find_registered_python_instance(void *src,
|
|
||||||
const detail::type_info *tinfo) {
|
|
||||||
auto it_instances = get_internals().registered_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))
|
|
||||||
return handle((PyObject *) it_i->second).inc_ref();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return handle();
|
|
||||||
}
|
|
||||||
|
|
||||||
struct value_and_holder {
|
|
||||||
instance *inst = nullptr;
|
|
||||||
size_t index = 0u;
|
|
||||||
const detail::type_info *type = nullptr;
|
|
||||||
void **vh = nullptr;
|
|
||||||
|
|
||||||
// Main constructor for a found value/holder:
|
|
||||||
value_and_holder(instance *i, const detail::type_info *type, size_t vpos, size_t index) :
|
|
||||||
inst{i}, index{index}, type{type},
|
|
||||||
vh{inst->simple_layout ? inst->simple_value_holder : &inst->nonsimple.values_and_holders[vpos]}
|
|
||||||
{}
|
|
||||||
|
|
||||||
// Default constructor (used to signal a value-and-holder not found by get_value_and_holder())
|
|
||||||
value_and_holder() = default;
|
|
||||||
|
|
||||||
// Used for past-the-end iterator
|
|
||||||
value_and_holder(size_t index) : index{index} {}
|
|
||||||
|
|
||||||
template <typename V = void> V *&value_ptr() const {
|
|
||||||
return reinterpret_cast<V *&>(vh[0]);
|
|
||||||
}
|
|
||||||
// True if this `value_and_holder` has a non-null value pointer
|
|
||||||
explicit operator bool() const { return value_ptr(); }
|
|
||||||
|
|
||||||
template <typename H> H &holder() const {
|
|
||||||
return reinterpret_cast<H &>(vh[1]);
|
|
||||||
}
|
|
||||||
bool holder_constructed() const {
|
|
||||||
return inst->simple_layout
|
|
||||||
? inst->simple_holder_constructed
|
|
||||||
: inst->nonsimple.status[index] & instance::status_holder_constructed;
|
|
||||||
}
|
|
||||||
void set_holder_constructed(bool v = true) {
|
|
||||||
if (inst->simple_layout)
|
|
||||||
inst->simple_holder_constructed = v;
|
|
||||||
else if (v)
|
|
||||||
inst->nonsimple.status[index] |= instance::status_holder_constructed;
|
|
||||||
else
|
|
||||||
inst->nonsimple.status[index] &= (uint8_t) ~instance::status_holder_constructed;
|
|
||||||
}
|
|
||||||
bool instance_registered() const {
|
|
||||||
return inst->simple_layout
|
|
||||||
? inst->simple_instance_registered
|
|
||||||
: inst->nonsimple.status[index] & instance::status_instance_registered;
|
|
||||||
}
|
|
||||||
void set_instance_registered(bool v = true) {
|
|
||||||
if (inst->simple_layout)
|
|
||||||
inst->simple_instance_registered = v;
|
|
||||||
else if (v)
|
|
||||||
inst->nonsimple.status[index] |= instance::status_instance_registered;
|
|
||||||
else
|
|
||||||
inst->nonsimple.status[index] &= (uint8_t) ~instance::status_instance_registered;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Container for accessing and iterating over an instance's values/holders
|
|
||||||
struct values_and_holders {
|
|
||||||
private:
|
|
||||||
instance *inst;
|
|
||||||
using type_vec = std::vector<detail::type_info *>;
|
|
||||||
const type_vec &tinfo;
|
|
||||||
|
|
||||||
public:
|
|
||||||
values_and_holders(instance *inst) : inst{inst}, tinfo(all_type_info(Py_TYPE(inst))) {}
|
|
||||||
|
|
||||||
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},
|
|
||||||
curr(inst /* instance */,
|
|
||||||
types->empty() ? nullptr : (*types)[0] /* type info */,
|
|
||||||
0, /* vpos: (non-simple types only): the first vptr comes first */
|
|
||||||
0 /* index */)
|
|
||||||
{}
|
|
||||||
// Past-the-end iterator:
|
|
||||||
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(); }
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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 inline 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(NDEBUG)
|
|
||||||
pybind11_fail("pybind11::detail::instance::get_value_and_holder: "
|
|
||||||
"type is not a pybind11 base of the given instance "
|
|
||||||
"(compile in debug mode for type details)");
|
|
||||||
#else
|
|
||||||
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");
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
PYBIND11_NOINLINE inline void instance::allocate_layout() {
|
|
||||||
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: in Python 3.6
|
|
||||||
// they default to using pymalloc, which is designed to be efficient for small allocations
|
|
||||||
// like the one we're doing here; in earlier versions (and for larger allocations) they are
|
|
||||||
// just wrappers around malloc.
|
|
||||||
#if PY_VERSION_HEX >= 0x03050000
|
|
||||||
nonsimple.values_and_holders = (void **) PyMem_Calloc(space, sizeof(void *));
|
|
||||||
if (!nonsimple.values_and_holders) throw std::bad_alloc();
|
|
||||||
#else
|
|
||||||
nonsimple.values_and_holders = (void **) PyMem_New(void *, space);
|
|
||||||
if (!nonsimple.values_and_holders) throw std::bad_alloc();
|
|
||||||
std::memset(nonsimple.values_and_holders, 0, space * sizeof(void *));
|
|
||||||
#endif
|
|
||||||
nonsimple.status = reinterpret_cast<uint8_t *>(&nonsimple.values_and_holders[flags_at]);
|
|
||||||
}
|
|
||||||
owned = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
PYBIND11_NOINLINE inline void instance::deallocate_layout() {
|
|
||||||
if (!simple_layout)
|
|
||||||
PyMem_Free(nonsimple.values_and_holders);
|
|
||||||
}
|
|
||||||
|
|
||||||
PYBIND11_NOINLINE inline 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 inline std::string error_string() {
|
|
||||||
if (!PyErr_Occurred()) {
|
|
||||||
PyErr_SetString(PyExc_RuntimeError, "Unknown internal error occurred");
|
|
||||||
return "Unknown internal error occurred";
|
|
||||||
}
|
|
||||||
|
|
||||||
error_scope scope; // Preserve error state
|
|
||||||
|
|
||||||
std::string errorString;
|
|
||||||
if (scope.type) {
|
|
||||||
errorString += handle(scope.type).attr("__name__").cast<std::string>();
|
|
||||||
errorString += ": ";
|
|
||||||
}
|
|
||||||
if (scope.value)
|
|
||||||
errorString += (std::string) str(scope.value);
|
|
||||||
|
|
||||||
PyErr_NormalizeException(&scope.type, &scope.value, &scope.trace);
|
|
||||||
|
|
||||||
#if PY_MAJOR_VERSION >= 3
|
|
||||||
if (scope.trace != nullptr)
|
|
||||||
PyException_SetTraceback(scope.value, scope.trace);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if !defined(PYPY_VERSION)
|
|
||||||
if (scope.trace) {
|
|
||||||
auto *trace = (PyTracebackObject *) scope.trace;
|
|
||||||
|
|
||||||
/* Get the deepest trace possible */
|
|
||||||
while (trace->tb_next)
|
|
||||||
trace = trace->tb_next;
|
|
||||||
|
|
||||||
PyFrameObject *frame = trace->tb_frame;
|
|
||||||
errorString += "\n\nAt:\n";
|
|
||||||
while (frame) {
|
|
||||||
int lineno = PyFrame_GetLineNumber(frame);
|
|
||||||
errorString +=
|
|
||||||
" " + handle(frame->f_code->co_filename).cast<std::string>() +
|
|
||||||
"(" + std::to_string(lineno) + "): " +
|
|
||||||
handle(frame->f_code->co_name).cast<std::string>() + "\n";
|
|
||||||
frame = frame->f_back;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return errorString;
|
|
||||||
}
|
|
||||||
|
|
||||||
PYBIND11_NOINLINE inline handle get_object_handle(const void *ptr, const detail::type_info *type ) {
|
|
||||||
auto &instances = get_internals().registered_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((PyObject *) it->second);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return handle();
|
|
||||||
}
|
|
||||||
|
|
||||||
inline PyThreadState *get_thread_state_unchecked() {
|
|
||||||
#if defined(PYPY_VERSION)
|
|
||||||
return PyThreadState_GET();
|
|
||||||
#elif PY_VERSION_HEX < 0x03000000
|
|
||||||
return _PyThreadState_Current;
|
|
||||||
#elif PY_VERSION_HEX < 0x03050000
|
|
||||||
return (PyThreadState*) _Py_atomic_load_relaxed(&_PyThreadState_Current);
|
|
||||||
#elif PY_VERSION_HEX < 0x03050200
|
|
||||||
return (PyThreadState*) _PyThreadState_Current.value;
|
|
||||||
#else
|
|
||||||
return _PyThreadState_UncheckedGet();
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
// Forward declarations
|
|
||||||
inline void keep_alive_impl(handle nurse, handle patient);
|
|
||||||
inline PyObject *make_new_instance(PyTypeObject *type);
|
|
||||||
|
|
||||||
class type_caster_generic {
|
|
||||||
public:
|
|
||||||
PYBIND11_NOINLINE type_caster_generic(const std::type_info &type_info)
|
|
||||||
: typeinfo(get_type_info(type_info)), cpptype(&type_info) { }
|
|
||||||
|
|
||||||
type_caster_generic(const type_info *typeinfo)
|
|
||||||
: typeinfo(typeinfo), cpptype(typeinfo ? typeinfo->cpptype : nullptr) { }
|
|
||||||
|
|
||||||
bool load(handle src, bool convert) {
|
|
||||||
return load_impl<type_caster_generic>(src, convert);
|
|
||||||
}
|
|
||||||
|
|
||||||
PYBIND11_NOINLINE 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) {
|
|
||||||
if (!tinfo) // no type info: error will be set already
|
|
||||||
return handle();
|
|
||||||
|
|
||||||
void *src = const_cast<void *>(_src);
|
|
||||||
if (src == nullptr)
|
|
||||||
return none().release();
|
|
||||||
|
|
||||||
if (handle registered_inst = find_registered_python_instance(src, tinfo))
|
|
||||||
return registered_inst;
|
|
||||||
|
|
||||||
auto inst = reinterpret_steal<object>(make_new_instance(tinfo->type));
|
|
||||||
auto wrapper = reinterpret_cast<instance *>(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(NDEBUG)
|
|
||||||
throw cast_error("return_value_policy = copy, but type is "
|
|
||||||
"non-copyable! (compile in debug mode for details)");
|
|
||||||
#else
|
|
||||||
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!");
|
|
||||||
#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(NDEBUG)
|
|
||||||
throw cast_error("return_value_policy = move, but type is neither "
|
|
||||||
"movable nor copyable! "
|
|
||||||
"(compile in debug mode for details)");
|
|
||||||
#else
|
|
||||||
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!");
|
|
||||||
#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) {
|
|
||||||
auto *&vptr = v_h.value_ptr();
|
|
||||||
// Lazy allocation for unallocated values:
|
|
||||||
if (vptr == nullptr) {
|
|
||||||
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) && (!defined(_MSC_VER) || _MSC_VER >= 1912)
|
|
||||||
if (type->type_align > __STDCPP_DEFAULT_NEW_ALIGNMENT__)
|
|
||||||
vptr = ::operator new(type->type_size,
|
|
||||||
std::align_val_t(type->type_align));
|
|
||||||
else
|
|
||||||
#endif
|
|
||||||
vptr = ::operator new(type->type_size);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
value = vptr;
|
|
||||||
}
|
|
||||||
bool try_implicit_casts(handle src, bool convert) {
|
|
||||||
for (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;
|
|
||||||
}
|
|
||||||
void check_holder_compat() {}
|
|
||||||
|
|
||||||
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<capsule>(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 <typename ThisT>
|
|
||||||
PYBIND11_NOINLINE bool load_impl(handle src, bool convert) {
|
|
||||||
if (!src) return false;
|
|
||||||
if (!typeinfo) return try_load_foreign_module_local(src);
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto &this_ = static_cast<ThisT &>(*this);
|
|
||||||
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<instance *>(src.ptr())->get_value_and_holder());
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
// Case 2: We have a derived class
|
|
||||||
else if (PyType_IsSubtype(srctype, typeinfo->type)) {
|
|
||||||
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<instance *>(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.
|
|
||||||
else 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<instance *>(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 (auto &converter : typeinfo->implicit_conversions) {
|
|
||||||
auto temp = reinterpret_steal<object>(converter(src.ptr(), typeinfo->type));
|
|
||||||
if (load_impl<ThisT>(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(src, false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Global typeinfo has precedence over foreign module_local
|
|
||||||
return try_load_foreign_module_local(src);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Called to do type lookup and wrap the pointer and type in a pair when a dynamic_cast
|
|
||||||
// isn't needed or can't be used. If the type is unknown, sets the error and returns a pair
|
|
||||||
// with .second = nullptr. (p.first = nullptr is not an error: it becomes None).
|
|
||||||
PYBIND11_NOINLINE static std::pair<const void *, const type_info *> src_and_type(
|
|
||||||
const void *src, const std::type_info &cast_type, const std::type_info *rtti_type = nullptr) {
|
|
||||||
if (auto *tpi = get_type_info(cast_type))
|
|
||||||
return {src, const_cast<const type_info *>(tpi)};
|
|
||||||
|
|
||||||
// Not found, set error:
|
|
||||||
std::string tname = rtti_type ? rtti_type->name() : cast_type.name();
|
|
||||||
detail::clean_type_id(tname);
|
|
||||||
std::string msg = "Unregistered type : " + tname;
|
|
||||||
PyErr_SetString(PyExc_TypeError, msg.c_str());
|
|
||||||
return {nullptr, nullptr};
|
|
||||||
}
|
|
||||||
|
|
||||||
const type_info *typeinfo = nullptr;
|
|
||||||
const std::type_info *cpptype = nullptr;
|
|
||||||
void *value = nullptr;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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 <typename T>
|
|
||||||
using cast_op_type =
|
|
||||||
conditional_t<std::is_pointer<remove_reference_t<T>>::value,
|
|
||||||
typename std::add_pointer<intrinsic_t<T>>::type,
|
|
||||||
typename std::add_lvalue_reference<intrinsic_t<T>>::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 <typename T>
|
|
||||||
using movable_cast_op_type =
|
|
||||||
conditional_t<std::is_pointer<typename std::remove_reference<T>::type>::value,
|
|
||||||
typename std::add_pointer<intrinsic_t<T>>::type,
|
|
||||||
conditional_t<std::is_rvalue_reference<T>::value,
|
|
||||||
typename std::add_rvalue_reference<intrinsic_t<T>>::type,
|
|
||||||
typename std::add_lvalue_reference<intrinsic_t<T>>::type>>;
|
|
||||||
|
|
||||||
// std::is_copy_constructible isn't quite enough: it lets std::vector<T> (and similar) through when
|
|
||||||
// T is non-copyable, but code containing such a copy constructor fails to actually compile.
|
|
||||||
template <typename T, typename SFINAE = void> struct is_copy_constructible : std::is_copy_constructible<T> {};
|
|
||||||
|
|
||||||
// Specialization for types that appear to be copy constructible but also look like stl containers
|
|
||||||
// (we specifically check for: has `value_type` and `reference` with `reference = value_type&`): if
|
|
||||||
// so, copy constructability depends on whether the value_type is copy constructible.
|
|
||||||
template <typename Container> struct is_copy_constructible<Container, enable_if_t<all_of<
|
|
||||||
std::is_copy_constructible<Container>,
|
|
||||||
std::is_same<typename Container::value_type &, typename Container::reference>,
|
|
||||||
// Avoid infinite recursion
|
|
||||||
negation<std::is_same<Container, typename Container::value_type>>
|
|
||||||
>::value>> : is_copy_constructible<typename Container::value_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 <typename T1, typename T2> struct is_copy_constructible<std::pair<T1, T2>>
|
|
||||||
: all_of<is_copy_constructible<T1>, is_copy_constructible<T2>> {};
|
|
||||||
|
|
||||||
// The same problems arise with std::is_copy_assignable, so we use the same workaround.
|
|
||||||
template <typename T, typename SFINAE = void> struct is_copy_assignable : std::is_copy_assignable<T> {};
|
|
||||||
template <typename Container> struct is_copy_assignable<Container, enable_if_t<all_of<
|
|
||||||
std::is_copy_assignable<Container>,
|
|
||||||
std::is_same<typename Container::value_type &, typename Container::reference>
|
|
||||||
>::value>> : is_copy_assignable<typename Container::value_type> {};
|
|
||||||
template <typename T1, typename T2> struct is_copy_assignable<std::pair<T1, T2>>
|
|
||||||
: all_of<is_copy_assignable<T1>, is_copy_assignable<T2>> {};
|
|
||||||
|
|
||||||
PYBIND11_NAMESPACE_END(detail)
|
|
||||||
|
|
||||||
// polymorphic_type_hook<itype>::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<void*>. 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 <typename itype, typename SFINAE = void>
|
|
||||||
struct polymorphic_type_hook_base
|
|
||||||
{
|
|
||||||
static const void *get(const itype *src, const std::type_info*&) { return src; }
|
|
||||||
};
|
|
||||||
template <typename itype>
|
|
||||||
struct polymorphic_type_hook_base<itype, detail::enable_if_t<std::is_polymorphic<itype>::value>>
|
|
||||||
{
|
|
||||||
static const void *get(const itype *src, const std::type_info*& type) {
|
|
||||||
type = src ? &typeid(*src) : nullptr;
|
|
||||||
return dynamic_cast<const void*>(src);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
template <typename itype, typename SFINAE = void>
|
|
||||||
struct polymorphic_type_hook : public polymorphic_type_hook_base<itype> {};
|
|
||||||
|
|
||||||
PYBIND11_NAMESPACE_BEGIN(detail)
|
|
||||||
|
|
||||||
/// Generic type caster for objects stored on the heap
|
|
||||||
template <typename type> class type_caster_base : public type_caster_generic {
|
|
||||||
using itype = intrinsic_t<type>;
|
|
||||||
|
|
||||||
public:
|
|
||||||
static constexpr auto name = _<type>();
|
|
||||||
|
|
||||||
type_caster_base() : type_caster_base(typeid(type)) { }
|
|
||||||
explicit type_caster_base(const std::type_info &info) : type_caster_generic(info) { }
|
|
||||||
|
|
||||||
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(&src, policy, parent);
|
|
||||||
}
|
|
||||||
|
|
||||||
static handle cast(itype &&src, return_value_policy, handle parent) {
|
|
||||||
return cast(&src, return_value_policy::move, parent);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Returns a (pointer, type_info) pair taking care of necessary type lookup for a
|
|
||||||
// polymorphic type (using RTTI by default, but can be overridden by specializing
|
|
||||||
// polymorphic_type_hook). If the instance isn't derived, returns the base version.
|
|
||||||
static std::pair<const void *, const type_info *> src_and_type(const itype *src) {
|
|
||||||
auto &cast_type = typeid(itype);
|
|
||||||
const std::type_info *instance_type = nullptr;
|
|
||||||
const void *vsrc = polymorphic_type_hook<itype>::get(src, instance_type);
|
|
||||||
if (instance_type && !same_type(cast_type, *instance_type)) {
|
|
||||||
// This is a base pointer to a derived type. If 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, we won't get here
|
|
||||||
// except via a user-provided specialization of polymorphic_type_hook,
|
|
||||||
// and the user has promised that no this-pointer adjustment is
|
|
||||||
// required in that case, so it's OK to use static_cast.
|
|
||||||
if (const auto *tpi = get_type_info(*instance_type))
|
|
||||||
return {vsrc, tpi};
|
|
||||||
}
|
|
||||||
// Otherwise we have either a nullptr, an `itype` pointer, or an unknown derived pointer, so
|
|
||||||
// don't do a cast
|
|
||||||
return type_caster_generic::src_and_type(src, cast_type, instance_type);
|
|
||||||
}
|
|
||||||
|
|
||||||
static handle cast(const itype *src, return_value_policy policy, handle parent) {
|
|
||||||
auto st = src_and_type(src);
|
|
||||||
return type_caster_generic::cast(
|
|
||||||
st.first, policy, parent, st.second,
|
|
||||||
make_copy_constructor(src), make_move_constructor(src));
|
|
||||||
}
|
|
||||||
|
|
||||||
static handle cast_holder(const itype *src, const void *holder) {
|
|
||||||
auto st = src_and_type(src);
|
|
||||||
return type_caster_generic::cast(
|
|
||||||
st.first, return_value_policy::take_ownership, {}, st.second,
|
|
||||||
nullptr, nullptr, holder);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T> using cast_op_type = detail::cast_op_type<T>;
|
|
||||||
|
|
||||||
operator itype*() { return (type *) value; }
|
|
||||||
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. */
|
|
||||||
template <typename T, typename = enable_if_t<is_copy_constructible<T>::value>>
|
|
||||||
static auto make_copy_constructor(const T *x) -> decltype(new T(*x), Constructor{}) {
|
|
||||||
return [](const void *arg) -> void * {
|
|
||||||
return new T(*reinterpret_cast<const T *>(arg));
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T, typename = enable_if_t<std::is_move_constructible<T>::value>>
|
|
||||||
static auto make_move_constructor(const T *x) -> decltype(new T(std::move(*const_cast<T *>(x))), Constructor{}) {
|
|
||||||
return [](const void *arg) -> void * {
|
|
||||||
return new T(std::move(*const_cast<T *>(reinterpret_cast<const T *>(arg))));
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
static Constructor make_copy_constructor(...) { return nullptr; }
|
|
||||||
static Constructor make_move_constructor(...) { return nullptr; }
|
|
||||||
};
|
|
||||||
|
|
||||||
template <typename type, typename SFINAE = void> class type_caster : public type_caster_base<type> { };
|
template <typename type, typename SFINAE = void> class type_caster : public type_caster_base<type> { };
|
||||||
template <typename type> using make_caster = type_caster<intrinsic_t<type>>;
|
template <typename type> using make_caster = type_caster<intrinsic_t<type>>;
|
||||||
|
|
||||||
@ -1195,7 +291,7 @@ public:
|
|||||||
if (!src) return false;
|
if (!src) return false;
|
||||||
else if (src.ptr() == Py_True) { value = true; return true; }
|
else if (src.ptr() == Py_True) { value = true; return true; }
|
||||||
else if (src.ptr() == Py_False) { value = false; return true; }
|
else if (src.ptr() == Py_False) { value = false; return true; }
|
||||||
else if (convert || !strcmp("numpy.bool_", Py_TYPE(src.ptr())->tp_name)) {
|
else if (convert || !std::strcmp("numpy.bool_", Py_TYPE(src.ptr())->tp_name)) {
|
||||||
// (allow non-implicit conversion for numpy booleans)
|
// (allow non-implicit conversion for numpy booleans)
|
||||||
|
|
||||||
Py_ssize_t res = -1;
|
Py_ssize_t res = -1;
|
||||||
|
944
include/pybind11/detail/type_caster_base.h
Normal file
944
include/pybind11/detail/type_caster_base.h
Normal file
@ -0,0 +1,944 @@
|
|||||||
|
/*
|
||||||
|
pybind11/detail/type_caster_base.h (originally first part of pybind11/cast.h)
|
||||||
|
|
||||||
|
Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch>
|
||||||
|
|
||||||
|
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 "../pytypes.h"
|
||||||
|
#include "common.h"
|
||||||
|
#include "descr.h"
|
||||||
|
#include "internals.h"
|
||||||
|
#include "typeid.h"
|
||||||
|
#include <cstdint>
|
||||||
|
#include <iterator>
|
||||||
|
#include <new>
|
||||||
|
#include <string>
|
||||||
|
#include <type_traits>
|
||||||
|
#include <typeindex>
|
||||||
|
#include <typeinfo>
|
||||||
|
#include <unordered_map>
|
||||||
|
#include <utility>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
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 {
|
||||||
|
public:
|
||||||
|
/// A new patient frame is created when a function is entered
|
||||||
|
loader_life_support() {
|
||||||
|
get_internals().loader_patient_stack.push_back(nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// ... and destroyed after it returns
|
||||||
|
~loader_life_support() {
|
||||||
|
auto &stack = get_internals().loader_patient_stack;
|
||||||
|
if (stack.empty())
|
||||||
|
pybind11_fail("loader_life_support: internal error");
|
||||||
|
|
||||||
|
auto ptr = stack.back();
|
||||||
|
stack.pop_back();
|
||||||
|
Py_CLEAR(ptr);
|
||||||
|
|
||||||
|
// A heuristic to reduce the stack's capacity (e.g. after long recursive calls)
|
||||||
|
if (stack.capacity() > 16 && !stack.empty() && stack.capacity() / stack.size() > 2)
|
||||||
|
stack.shrink_to_fit();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 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) {
|
||||||
|
auto &stack = get_internals().loader_patient_stack;
|
||||||
|
if (stack.empty())
|
||||||
|
throw cast_error("When called outside a bound function, py::cast() cannot "
|
||||||
|
"do Python -> C++ conversions which require the creation "
|
||||||
|
"of temporary values");
|
||||||
|
|
||||||
|
auto &list_ptr = stack.back();
|
||||||
|
if (list_ptr == nullptr) {
|
||||||
|
list_ptr = PyList_New(1);
|
||||||
|
if (!list_ptr)
|
||||||
|
pybind11_fail("loader_life_support: error allocating list");
|
||||||
|
PyList_SET_ITEM(list_ptr, 0, h.inc_ref().ptr());
|
||||||
|
} else {
|
||||||
|
auto result = PyList_Append(list_ptr, h.ptr());
|
||||||
|
if (result == -1)
|
||||||
|
pybind11_fail("loader_life_support: error adding patient");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 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<decltype(internals::registered_types_py)::iterator, bool> all_type_info_get_cache(PyTypeObject *type);
|
||||||
|
|
||||||
|
// Populates a just-created cache entry.
|
||||||
|
PYBIND11_NOINLINE inline void all_type_info_populate(PyTypeObject *t, std::vector<type_info *> &bases) {
|
||||||
|
std::vector<PyTypeObject *> check;
|
||||||
|
for (handle parent : reinterpret_borrow<tuple>(t->tp_bases))
|
||||||
|
check.push_back((PyTypeObject *) 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) bases.push_back(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<tuple>(type->tp_bases))
|
||||||
|
check.push_back((PyTypeObject *) 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<detail::type_info *> &all_type_info(PyTypeObject *type) {
|
||||||
|
auto ins = all_type_info_get_cache(type);
|
||||||
|
if (ins.second)
|
||||||
|
// New cache entry: populate it
|
||||||
|
all_type_info_populate(type, ins.first->second);
|
||||||
|
|
||||||
|
return ins.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 inline detail::type_info* get_type_info(PyTypeObject *type) {
|
||||||
|
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(const std::type_index &tp) {
|
||||||
|
auto &locals = registered_local_types_cpp();
|
||||||
|
auto it = locals.find(tp);
|
||||||
|
if (it != locals.end())
|
||||||
|
return it->second;
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline detail::type_info *get_global_type_info(const std::type_index &tp) {
|
||||||
|
auto &types = get_internals().registered_types_cpp;
|
||||||
|
auto it = types.find(tp);
|
||||||
|
if (it != types.end())
|
||||||
|
return it->second;
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Return the type info for a given C++ type; on lookup failure can either throw or return nullptr.
|
||||||
|
PYBIND11_NOINLINE inline detail::type_info *get_type_info(const std::type_index &tp,
|
||||||
|
bool throw_if_missing = false) {
|
||||||
|
if (auto ltype = get_local_type_info(tp))
|
||||||
|
return ltype;
|
||||||
|
if (auto gtype = get_global_type_info(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 \"" + tname + "\"");
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
PYBIND11_NOINLINE inline 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 ? ((PyObject *) type_info->type) : nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Searches the inheritance graph for a registered Python instance, using all_type_info().
|
||||||
|
PYBIND11_NOINLINE inline handle find_registered_python_instance(void *src,
|
||||||
|
const detail::type_info *tinfo) {
|
||||||
|
auto it_instances = get_internals().registered_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))
|
||||||
|
return handle((PyObject *) it_i->second).inc_ref();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return handle();
|
||||||
|
}
|
||||||
|
|
||||||
|
struct value_and_holder {
|
||||||
|
instance *inst = nullptr;
|
||||||
|
size_t index = 0u;
|
||||||
|
const detail::type_info *type = nullptr;
|
||||||
|
void **vh = nullptr;
|
||||||
|
|
||||||
|
// Main constructor for a found value/holder:
|
||||||
|
value_and_holder(instance *i, const detail::type_info *type, size_t vpos, size_t index) :
|
||||||
|
inst{i}, index{index}, type{type},
|
||||||
|
vh{inst->simple_layout ? inst->simple_value_holder : &inst->nonsimple.values_and_holders[vpos]}
|
||||||
|
{}
|
||||||
|
|
||||||
|
// Default constructor (used to signal a value-and-holder not found by get_value_and_holder())
|
||||||
|
value_and_holder() = default;
|
||||||
|
|
||||||
|
// Used for past-the-end iterator
|
||||||
|
value_and_holder(size_t index) : index{index} {}
|
||||||
|
|
||||||
|
template <typename V = void> V *&value_ptr() const {
|
||||||
|
return reinterpret_cast<V *&>(vh[0]);
|
||||||
|
}
|
||||||
|
// True if this `value_and_holder` has a non-null value pointer
|
||||||
|
explicit operator bool() const { return value_ptr(); }
|
||||||
|
|
||||||
|
template <typename H> H &holder() const {
|
||||||
|
return reinterpret_cast<H &>(vh[1]);
|
||||||
|
}
|
||||||
|
bool holder_constructed() const {
|
||||||
|
return inst->simple_layout
|
||||||
|
? inst->simple_holder_constructed
|
||||||
|
: inst->nonsimple.status[index] & instance::status_holder_constructed;
|
||||||
|
}
|
||||||
|
void set_holder_constructed(bool v = true) {
|
||||||
|
if (inst->simple_layout)
|
||||||
|
inst->simple_holder_constructed = v;
|
||||||
|
else if (v)
|
||||||
|
inst->nonsimple.status[index] |= instance::status_holder_constructed;
|
||||||
|
else
|
||||||
|
inst->nonsimple.status[index] &= (std::uint8_t) ~instance::status_holder_constructed;
|
||||||
|
}
|
||||||
|
bool instance_registered() const {
|
||||||
|
return inst->simple_layout
|
||||||
|
? inst->simple_instance_registered
|
||||||
|
: inst->nonsimple.status[index] & instance::status_instance_registered;
|
||||||
|
}
|
||||||
|
void set_instance_registered(bool v = true) {
|
||||||
|
if (inst->simple_layout)
|
||||||
|
inst->simple_instance_registered = v;
|
||||||
|
else if (v)
|
||||||
|
inst->nonsimple.status[index] |= instance::status_instance_registered;
|
||||||
|
else
|
||||||
|
inst->nonsimple.status[index] &= (std::uint8_t) ~instance::status_instance_registered;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Container for accessing and iterating over an instance's values/holders
|
||||||
|
struct values_and_holders {
|
||||||
|
private:
|
||||||
|
instance *inst;
|
||||||
|
using type_vec = std::vector<detail::type_info *>;
|
||||||
|
const type_vec &tinfo;
|
||||||
|
|
||||||
|
public:
|
||||||
|
values_and_holders(instance *inst) : inst{inst}, tinfo(all_type_info(Py_TYPE(inst))) {}
|
||||||
|
|
||||||
|
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},
|
||||||
|
curr(inst /* instance */,
|
||||||
|
types->empty() ? nullptr : (*types)[0] /* type info */,
|
||||||
|
0, /* vpos: (non-simple types only): the first vptr comes first */
|
||||||
|
0 /* index */)
|
||||||
|
{}
|
||||||
|
// Past-the-end iterator:
|
||||||
|
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(); }
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 inline 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(NDEBUG)
|
||||||
|
pybind11_fail("pybind11::detail::instance::get_value_and_holder: "
|
||||||
|
"type is not a pybind11 base of the given instance "
|
||||||
|
"(compile in debug mode for type details)");
|
||||||
|
#else
|
||||||
|
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");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
PYBIND11_NOINLINE inline void instance::allocate_layout() {
|
||||||
|
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: in Python 3.6
|
||||||
|
// they default to using pymalloc, which is designed to be efficient for small allocations
|
||||||
|
// like the one we're doing here; in earlier versions (and for larger allocations) they are
|
||||||
|
// just wrappers around malloc.
|
||||||
|
#if PY_VERSION_HEX >= 0x03050000
|
||||||
|
nonsimple.values_and_holders = (void **) PyMem_Calloc(space, sizeof(void *));
|
||||||
|
if (!nonsimple.values_and_holders) throw std::bad_alloc();
|
||||||
|
#else
|
||||||
|
nonsimple.values_and_holders = (void **) PyMem_New(void *, space);
|
||||||
|
if (!nonsimple.values_and_holders) throw std::bad_alloc();
|
||||||
|
std::memset(nonsimple.values_and_holders, 0, space * sizeof(void *));
|
||||||
|
#endif
|
||||||
|
nonsimple.status = reinterpret_cast<std::uint8_t *>(&nonsimple.values_and_holders[flags_at]);
|
||||||
|
}
|
||||||
|
owned = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
PYBIND11_NOINLINE inline void instance::deallocate_layout() {
|
||||||
|
if (!simple_layout)
|
||||||
|
PyMem_Free(nonsimple.values_and_holders);
|
||||||
|
}
|
||||||
|
|
||||||
|
PYBIND11_NOINLINE inline 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 inline std::string error_string() {
|
||||||
|
if (!PyErr_Occurred()) {
|
||||||
|
PyErr_SetString(PyExc_RuntimeError, "Unknown internal error occurred");
|
||||||
|
return "Unknown internal error occurred";
|
||||||
|
}
|
||||||
|
|
||||||
|
error_scope scope; // Preserve error state
|
||||||
|
|
||||||
|
std::string errorString;
|
||||||
|
if (scope.type) {
|
||||||
|
errorString += handle(scope.type).attr("__name__").cast<std::string>();
|
||||||
|
errorString += ": ";
|
||||||
|
}
|
||||||
|
if (scope.value)
|
||||||
|
errorString += (std::string) str(scope.value);
|
||||||
|
|
||||||
|
PyErr_NormalizeException(&scope.type, &scope.value, &scope.trace);
|
||||||
|
|
||||||
|
#if PY_MAJOR_VERSION >= 3
|
||||||
|
if (scope.trace != nullptr)
|
||||||
|
PyException_SetTraceback(scope.value, scope.trace);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if !defined(PYPY_VERSION)
|
||||||
|
if (scope.trace) {
|
||||||
|
auto *trace = (PyTracebackObject *) scope.trace;
|
||||||
|
|
||||||
|
/* Get the deepest trace possible */
|
||||||
|
while (trace->tb_next)
|
||||||
|
trace = trace->tb_next;
|
||||||
|
|
||||||
|
PyFrameObject *frame = trace->tb_frame;
|
||||||
|
errorString += "\n\nAt:\n";
|
||||||
|
while (frame) {
|
||||||
|
int lineno = PyFrame_GetLineNumber(frame);
|
||||||
|
errorString +=
|
||||||
|
" " + handle(frame->f_code->co_filename).cast<std::string>() +
|
||||||
|
"(" + std::to_string(lineno) + "): " +
|
||||||
|
handle(frame->f_code->co_name).cast<std::string>() + "\n";
|
||||||
|
frame = frame->f_back;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return errorString;
|
||||||
|
}
|
||||||
|
|
||||||
|
PYBIND11_NOINLINE inline handle get_object_handle(const void *ptr, const detail::type_info *type ) {
|
||||||
|
auto &instances = get_internals().registered_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((PyObject *) it->second);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return handle();
|
||||||
|
}
|
||||||
|
|
||||||
|
inline PyThreadState *get_thread_state_unchecked() {
|
||||||
|
#if defined(PYPY_VERSION)
|
||||||
|
return PyThreadState_GET();
|
||||||
|
#elif PY_VERSION_HEX < 0x03000000
|
||||||
|
return _PyThreadState_Current;
|
||||||
|
#elif PY_VERSION_HEX < 0x03050000
|
||||||
|
return (PyThreadState*) _Py_atomic_load_relaxed(&_PyThreadState_Current);
|
||||||
|
#elif PY_VERSION_HEX < 0x03050200
|
||||||
|
return (PyThreadState*) _PyThreadState_Current.value;
|
||||||
|
#else
|
||||||
|
return _PyThreadState_UncheckedGet();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
// Forward declarations
|
||||||
|
inline void keep_alive_impl(handle nurse, handle patient);
|
||||||
|
inline PyObject *make_new_instance(PyTypeObject *type);
|
||||||
|
|
||||||
|
class type_caster_generic {
|
||||||
|
public:
|
||||||
|
PYBIND11_NOINLINE type_caster_generic(const std::type_info &type_info)
|
||||||
|
: typeinfo(get_type_info(type_info)), cpptype(&type_info) { }
|
||||||
|
|
||||||
|
type_caster_generic(const type_info *typeinfo)
|
||||||
|
: typeinfo(typeinfo), cpptype(typeinfo ? typeinfo->cpptype : nullptr) { }
|
||||||
|
|
||||||
|
bool load(handle src, bool convert) {
|
||||||
|
return load_impl<type_caster_generic>(src, convert);
|
||||||
|
}
|
||||||
|
|
||||||
|
PYBIND11_NOINLINE 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) {
|
||||||
|
if (!tinfo) // no type info: error will be set already
|
||||||
|
return handle();
|
||||||
|
|
||||||
|
void *src = const_cast<void *>(_src);
|
||||||
|
if (src == nullptr)
|
||||||
|
return none().release();
|
||||||
|
|
||||||
|
if (handle registered_inst = find_registered_python_instance(src, tinfo))
|
||||||
|
return registered_inst;
|
||||||
|
|
||||||
|
auto inst = reinterpret_steal<object>(make_new_instance(tinfo->type));
|
||||||
|
auto wrapper = reinterpret_cast<instance *>(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(NDEBUG)
|
||||||
|
throw cast_error("return_value_policy = copy, but type is "
|
||||||
|
"non-copyable! (compile in debug mode for details)");
|
||||||
|
#else
|
||||||
|
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!");
|
||||||
|
#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(NDEBUG)
|
||||||
|
throw cast_error("return_value_policy = move, but type is neither "
|
||||||
|
"movable nor copyable! "
|
||||||
|
"(compile in debug mode for details)");
|
||||||
|
#else
|
||||||
|
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!");
|
||||||
|
#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) {
|
||||||
|
auto *&vptr = v_h.value_ptr();
|
||||||
|
// Lazy allocation for unallocated values:
|
||||||
|
if (vptr == nullptr) {
|
||||||
|
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) && (!defined(_MSC_VER) || _MSC_VER >= 1912)
|
||||||
|
if (type->type_align > __STDCPP_DEFAULT_NEW_ALIGNMENT__)
|
||||||
|
vptr = ::operator new(type->type_size,
|
||||||
|
std::align_val_t(type->type_align));
|
||||||
|
else
|
||||||
|
#endif
|
||||||
|
vptr = ::operator new(type->type_size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
value = vptr;
|
||||||
|
}
|
||||||
|
bool try_implicit_casts(handle src, bool convert) {
|
||||||
|
for (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;
|
||||||
|
}
|
||||||
|
void check_holder_compat() {}
|
||||||
|
|
||||||
|
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<capsule>(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 <typename ThisT>
|
||||||
|
PYBIND11_NOINLINE bool load_impl(handle src, bool convert) {
|
||||||
|
if (!src) return false;
|
||||||
|
if (!typeinfo) return try_load_foreign_module_local(src);
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto &this_ = static_cast<ThisT &>(*this);
|
||||||
|
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<instance *>(src.ptr())->get_value_and_holder());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
// Case 2: We have a derived class
|
||||||
|
else if (PyType_IsSubtype(srctype, typeinfo->type)) {
|
||||||
|
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<instance *>(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.
|
||||||
|
else 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<instance *>(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 (auto &converter : typeinfo->implicit_conversions) {
|
||||||
|
auto temp = reinterpret_steal<object>(converter(src.ptr(), typeinfo->type));
|
||||||
|
if (load_impl<ThisT>(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(src, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Global typeinfo has precedence over foreign module_local
|
||||||
|
return try_load_foreign_module_local(src);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Called to do type lookup and wrap the pointer and type in a pair when a dynamic_cast
|
||||||
|
// isn't needed or can't be used. If the type is unknown, sets the error and returns a pair
|
||||||
|
// with .second = nullptr. (p.first = nullptr is not an error: it becomes None).
|
||||||
|
PYBIND11_NOINLINE static std::pair<const void *, const type_info *> src_and_type(
|
||||||
|
const void *src, const std::type_info &cast_type, const std::type_info *rtti_type = nullptr) {
|
||||||
|
if (auto *tpi = get_type_info(cast_type))
|
||||||
|
return {src, const_cast<const type_info *>(tpi)};
|
||||||
|
|
||||||
|
// Not found, set error:
|
||||||
|
std::string tname = rtti_type ? rtti_type->name() : cast_type.name();
|
||||||
|
detail::clean_type_id(tname);
|
||||||
|
std::string msg = "Unregistered type : " + tname;
|
||||||
|
PyErr_SetString(PyExc_TypeError, msg.c_str());
|
||||||
|
return {nullptr, nullptr};
|
||||||
|
}
|
||||||
|
|
||||||
|
const type_info *typeinfo = nullptr;
|
||||||
|
const std::type_info *cpptype = nullptr;
|
||||||
|
void *value = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 <typename T>
|
||||||
|
using cast_op_type =
|
||||||
|
conditional_t<std::is_pointer<remove_reference_t<T>>::value,
|
||||||
|
typename std::add_pointer<intrinsic_t<T>>::type,
|
||||||
|
typename std::add_lvalue_reference<intrinsic_t<T>>::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 <typename T>
|
||||||
|
using movable_cast_op_type =
|
||||||
|
conditional_t<std::is_pointer<typename std::remove_reference<T>::type>::value,
|
||||||
|
typename std::add_pointer<intrinsic_t<T>>::type,
|
||||||
|
conditional_t<std::is_rvalue_reference<T>::value,
|
||||||
|
typename std::add_rvalue_reference<intrinsic_t<T>>::type,
|
||||||
|
typename std::add_lvalue_reference<intrinsic_t<T>>::type>>;
|
||||||
|
|
||||||
|
// std::is_copy_constructible isn't quite enough: it lets std::vector<T> (and similar) through when
|
||||||
|
// T is non-copyable, but code containing such a copy constructor fails to actually compile.
|
||||||
|
template <typename T, typename SFINAE = void> struct is_copy_constructible : std::is_copy_constructible<T> {};
|
||||||
|
|
||||||
|
// Specialization for types that appear to be copy constructible but also look like stl containers
|
||||||
|
// (we specifically check for: has `value_type` and `reference` with `reference = value_type&`): if
|
||||||
|
// so, copy constructability depends on whether the value_type is copy constructible.
|
||||||
|
template <typename Container> struct is_copy_constructible<Container, enable_if_t<all_of<
|
||||||
|
std::is_copy_constructible<Container>,
|
||||||
|
std::is_same<typename Container::value_type &, typename Container::reference>,
|
||||||
|
// Avoid infinite recursion
|
||||||
|
negation<std::is_same<Container, typename Container::value_type>>
|
||||||
|
>::value>> : is_copy_constructible<typename Container::value_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 <typename T1, typename T2> struct is_copy_constructible<std::pair<T1, T2>>
|
||||||
|
: all_of<is_copy_constructible<T1>, is_copy_constructible<T2>> {};
|
||||||
|
|
||||||
|
// The same problems arise with std::is_copy_assignable, so we use the same workaround.
|
||||||
|
template <typename T, typename SFINAE = void> struct is_copy_assignable : std::is_copy_assignable<T> {};
|
||||||
|
template <typename Container> struct is_copy_assignable<Container, enable_if_t<all_of<
|
||||||
|
std::is_copy_assignable<Container>,
|
||||||
|
std::is_same<typename Container::value_type &, typename Container::reference>
|
||||||
|
>::value>> : is_copy_assignable<typename Container::value_type> {};
|
||||||
|
template <typename T1, typename T2> struct is_copy_assignable<std::pair<T1, T2>>
|
||||||
|
: all_of<is_copy_assignable<T1>, is_copy_assignable<T2>> {};
|
||||||
|
|
||||||
|
PYBIND11_NAMESPACE_END(detail)
|
||||||
|
|
||||||
|
// polymorphic_type_hook<itype>::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<void*>. 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 <typename itype, typename SFINAE = void>
|
||||||
|
struct polymorphic_type_hook_base
|
||||||
|
{
|
||||||
|
static const void *get(const itype *src, const std::type_info*&) { return src; }
|
||||||
|
};
|
||||||
|
template <typename itype>
|
||||||
|
struct polymorphic_type_hook_base<itype, detail::enable_if_t<std::is_polymorphic<itype>::value>>
|
||||||
|
{
|
||||||
|
static const void *get(const itype *src, const std::type_info*& type) {
|
||||||
|
type = src ? &typeid(*src) : nullptr;
|
||||||
|
return dynamic_cast<const void*>(src);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
template <typename itype, typename SFINAE = void>
|
||||||
|
struct polymorphic_type_hook : public polymorphic_type_hook_base<itype> {};
|
||||||
|
|
||||||
|
PYBIND11_NAMESPACE_BEGIN(detail)
|
||||||
|
|
||||||
|
/// Generic type caster for objects stored on the heap
|
||||||
|
template <typename type> class type_caster_base : public type_caster_generic {
|
||||||
|
using itype = intrinsic_t<type>;
|
||||||
|
|
||||||
|
public:
|
||||||
|
static constexpr auto name = _<type>();
|
||||||
|
|
||||||
|
type_caster_base() : type_caster_base(typeid(type)) { }
|
||||||
|
explicit type_caster_base(const std::type_info &info) : type_caster_generic(info) { }
|
||||||
|
|
||||||
|
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(&src, policy, parent);
|
||||||
|
}
|
||||||
|
|
||||||
|
static handle cast(itype &&src, return_value_policy, handle parent) {
|
||||||
|
return cast(&src, return_value_policy::move, parent);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns a (pointer, type_info) pair taking care of necessary type lookup for a
|
||||||
|
// polymorphic type (using RTTI by default, but can be overridden by specializing
|
||||||
|
// polymorphic_type_hook). If the instance isn't derived, returns the base version.
|
||||||
|
static std::pair<const void *, const type_info *> src_and_type(const itype *src) {
|
||||||
|
auto &cast_type = typeid(itype);
|
||||||
|
const std::type_info *instance_type = nullptr;
|
||||||
|
const void *vsrc = polymorphic_type_hook<itype>::get(src, instance_type);
|
||||||
|
if (instance_type && !same_type(cast_type, *instance_type)) {
|
||||||
|
// This is a base pointer to a derived type. If 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, we won't get here
|
||||||
|
// except via a user-provided specialization of polymorphic_type_hook,
|
||||||
|
// and the user has promised that no this-pointer adjustment is
|
||||||
|
// required in that case, so it's OK to use static_cast.
|
||||||
|
if (const auto *tpi = get_type_info(*instance_type))
|
||||||
|
return {vsrc, tpi};
|
||||||
|
}
|
||||||
|
// Otherwise we have either a nullptr, an `itype` pointer, or an unknown derived pointer, so
|
||||||
|
// don't do a cast
|
||||||
|
return type_caster_generic::src_and_type(src, cast_type, instance_type);
|
||||||
|
}
|
||||||
|
|
||||||
|
static handle cast(const itype *src, return_value_policy policy, handle parent) {
|
||||||
|
auto st = src_and_type(src);
|
||||||
|
return type_caster_generic::cast(
|
||||||
|
st.first, policy, parent, st.second,
|
||||||
|
make_copy_constructor(src), make_move_constructor(src));
|
||||||
|
}
|
||||||
|
|
||||||
|
static handle cast_holder(const itype *src, const void *holder) {
|
||||||
|
auto st = src_and_type(src);
|
||||||
|
return type_caster_generic::cast(
|
||||||
|
st.first, return_value_policy::take_ownership, {}, st.second,
|
||||||
|
nullptr, nullptr, holder);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T> using cast_op_type = detail::cast_op_type<T>;
|
||||||
|
|
||||||
|
operator itype*() { return (type *) value; }
|
||||||
|
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. */
|
||||||
|
template <typename T, typename = enable_if_t<is_copy_constructible<T>::value>>
|
||||||
|
static auto make_copy_constructor(const T *x) -> decltype(new T(*x), Constructor{}) {
|
||||||
|
return [](const void *arg) -> void * {
|
||||||
|
return new T(*reinterpret_cast<const T *>(arg));
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T, typename = enable_if_t<std::is_move_constructible<T>::value>>
|
||||||
|
static auto make_move_constructor(const T *x) -> decltype(new T(std::move(*const_cast<T *>(x))), Constructor{}) {
|
||||||
|
return [](const void *arg) -> void * {
|
||||||
|
return new T(std::move(*const_cast<T *>(reinterpret_cast<const T *>(arg))));
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
static Constructor make_copy_constructor(...) { return nullptr; }
|
||||||
|
static Constructor make_move_constructor(...) { return nullptr; }
|
||||||
|
};
|
||||||
|
|
||||||
|
PYBIND11_NAMESPACE_END(detail)
|
||||||
|
PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)
|
@ -41,6 +41,7 @@ detail_headers = {
|
|||||||
"include/pybind11/detail/descr.h",
|
"include/pybind11/detail/descr.h",
|
||||||
"include/pybind11/detail/init.h",
|
"include/pybind11/detail/init.h",
|
||||||
"include/pybind11/detail/internals.h",
|
"include/pybind11/detail/internals.h",
|
||||||
|
"include/pybind11/detail/type_caster_base.h",
|
||||||
"include/pybind11/detail/typeid.h",
|
"include/pybind11/detail/typeid.h",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user