factored out some common functionality to a non-templated parent class

This commit is contained in:
Wenzel Jakob 2015-10-19 23:50:51 +02:00
parent fab881caf4
commit 0fb8528edf
3 changed files with 70 additions and 71 deletions

View File

@ -220,7 +220,7 @@ different kinds of input arguments:
Attempting to bind ``Pet::set`` will cause an error since the compiler does not Attempting to bind ``Pet::set`` will cause an error since the compiler does not
know which method the user intended to select. We can disambiguate by casting know which method the user intended to select. We can disambiguate by casting
them to function pointers. Binding multiple functions to the same Python name them to function pointers. Binding multiple functions to the same Python name
automatically creates a chain of fucnction overloads that will be tried in automatically creates a chain of function overloads that will be tried in
sequence. sequence.
.. code-block:: cpp .. code-block:: cpp

View File

@ -18,12 +18,6 @@
NAMESPACE_BEGIN(pybind11) NAMESPACE_BEGIN(pybind11)
NAMESPACE_BEGIN(detail) NAMESPACE_BEGIN(detail)
#if defined(_MSC_VER)
#define NOINLINE __declspec(noinline)
#else
#define NOINLINE __attribute__ ((noinline))
#endif
#if PY_MAJOR_VERSION >= 3 #if PY_MAJOR_VERSION >= 3
#define PYBIND11_AS_STRING PyBytes_AsString #define PYBIND11_AS_STRING PyBytes_AsString
#else #else
@ -44,35 +38,35 @@ public:
descr() { } descr() { }
descr(descr &&d) : first(d.first), last(d.last) { d.first = d.last = nullptr; } descr(descr &&d) : first(d.first), last(d.last) { d.first = d.last = nullptr; }
NOINLINE descr(const char *str) { first = last = new entry { str }; } PYBIND11_NOINLINE descr(const char *str) { first = last = new entry { str }; }
NOINLINE descr(const std::type_info &type) { first = last = new entry { &type }; } PYBIND11_NOINLINE descr(const std::type_info &type) { first = last = new entry { &type }; }
NOINLINE void operator+(const char *str) { PYBIND11_NOINLINE void operator+(const char *str) {
entry *next = new entry { str }; entry *next = new entry { str };
last->next = next; last->next = next;
last = next; last = next;
} }
NOINLINE void operator+(const std::type_info *type) { PYBIND11_NOINLINE void operator+(const std::type_info *type) {
entry *next = new entry { type }; entry *next = new entry { type };
last->next = next; last->next = next;
last = next; last = next;
} }
NOINLINE void operator+=(descr &&other) { PYBIND11_NOINLINE void operator+=(descr &&other) {
last->next = other.first; last->next = other.first;
while (last->next) while (last->next)
last = last->next; last = last->next;
other.first = other.last = nullptr; other.first = other.last = nullptr;
} }
NOINLINE friend descr operator+(descr &&l, descr &&r) { PYBIND11_NOINLINE friend descr operator+(descr &&l, descr &&r) {
descr result(std::move(l)); descr result(std::move(l));
result += std::move(r); result += std::move(r);
return result; return result;
} }
NOINLINE std::string str() const { PYBIND11_NOINLINE std::string str() const {
std::string result; std::string result;
auto const& registered_types = get_internals().registered_types; auto const& registered_types = get_internals().registered_types;
for (entry *it = first; it != nullptr; it = it->next) { for (entry *it = first; it != nullptr; it = it->next) {
@ -92,7 +86,7 @@ public:
return result; return result;
} }
NOINLINE ~descr() { PYBIND11_NOINLINE ~descr() {
while (first) { while (first) {
entry *tmp = first->next; entry *tmp = first->next;
delete first; delete first;
@ -104,27 +98,20 @@ public:
entry *last = nullptr; entry *last = nullptr;
}; };
#undef NOINLINE class type_caster_custom {
/// Generic type caster for objects stored on the heap
template <typename type> class type_caster {
public: public:
typedef instance<type> instance_type; PYBIND11_NOINLINE type_caster_custom(const std::type_info *type_info) {
static descr name() { return typeid(type); }
type_caster() {
auto const& registered_types = get_internals().registered_types; auto const& registered_types = get_internals().registered_types;
auto it = registered_types.find(&typeid(type)); auto it = registered_types.find(type_info);
if (it != registered_types.end()) if (it != registered_types.end())
typeinfo = &it->second; typeinfo = &it->second;
} }
bool load(PyObject *src, bool convert) { PYBIND11_NOINLINE bool load(PyObject *src, bool convert) {
if (src == nullptr || typeinfo == nullptr) if (src == nullptr || typeinfo == nullptr)
return false; return false;
if (PyType_IsSubtype(Py_TYPE(src), typeinfo->type)) { if (PyType_IsSubtype(Py_TYPE(src), typeinfo->type)) {
value = ((instance_type *) src)->value; value = ((instance<void> *) src)->value;
return true; return true;
} }
if (convert) { if (convert) {
@ -137,14 +124,9 @@ public:
return false; return false;
} }
static PyObject *cast(const type &src, return_value_policy policy, PyObject *parent) { PYBIND11_NOINLINE static PyObject *cast(const void *_src, return_value_policy policy, PyObject *parent,
if (policy == return_value_policy::automatic) const std::type_info *type_info, void *(*copy_constructor)(const void *)) {
policy = return_value_policy::copy; void *src = const_cast<void *>(_src);
return cast(&src, policy, parent);
}
static PyObject *cast(const type *_src, return_value_policy policy, PyObject *parent) {
type *src = const_cast<type *>(_src);
if (src == nullptr) { if (src == nullptr) {
Py_INCREF(Py_None); Py_INCREF(Py_None);
return Py_None; return Py_None;
@ -159,61 +141,72 @@ public:
Py_INCREF(inst); Py_INCREF(inst);
return inst; return inst;
} }
auto it = internals.registered_types.find(&typeid(type)); auto it = internals.registered_types.find(type_info);
if (it == internals.registered_types.end()) { if (it == internals.registered_types.end()) {
std::string msg = std::string("Unregistered type : ") + type_id<type>(); std::string msg = std::string("Unregistered type : ") + type_info->name();
detail::clean_type_id(msg);
PyErr_SetString(PyExc_TypeError, msg.c_str()); PyErr_SetString(PyExc_TypeError, msg.c_str());
return nullptr; return nullptr;
} }
auto &type_info = it->second; auto &reg_type = it->second;
instance_type *inst = (instance_type *) PyType_GenericAlloc(type_info.type, 0); instance<void> *inst = (instance<void> *) PyType_GenericAlloc(reg_type.type, 0);
inst->value = src; inst->value = src;
inst->owned = true; inst->owned = true;
inst->parent = nullptr; inst->parent = nullptr;
if (policy == return_value_policy::automatic) if (policy == return_value_policy::automatic)
policy = return_value_policy::take_ownership; policy = return_value_policy::take_ownership;
handle_return_value_policy<type>(inst, policy, parent); if (policy == return_value_policy::copy) {
inst->value = copy_constructor(inst->value);
if (inst->value == nullptr)
throw cast_error("return_value_policy = copy, but the object is non-copyable!");
} else if (policy == return_value_policy::reference) {
inst->owned = false;
} else if (policy == return_value_policy::reference_internal) {
inst->owned = false;
inst->parent = parent;
Py_XINCREF(parent);
}
PyObject *inst_pyobj = (PyObject *) inst; PyObject *inst_pyobj = (PyObject *) inst;
type_info.init_holder(inst_pyobj); reg_type.init_holder(inst_pyobj);
if (!dont_cache) if (!dont_cache)
internals.registered_instances[inst->value] = inst_pyobj; internals.registered_instances[inst->value] = inst_pyobj;
return inst_pyobj; return inst_pyobj;
} }
template <class T, typename std::enable_if<std::is_copy_constructible<T>::value, int>::type = 0>
static void handle_return_value_policy(instance<T> *inst, return_value_policy policy, PyObject *parent) {
if (policy == return_value_policy::copy) {
inst->value = new T(*(inst->value));
} else if (policy == return_value_policy::reference) {
inst->owned = false;
} else if (policy == return_value_policy::reference_internal) {
inst->owned = false;
inst->parent = parent;
Py_XINCREF(parent);
}
}
template <class T, typename std::enable_if<!std::is_copy_constructible<T>::value, int>::type = 0>
static void handle_return_value_policy(instance<T> *inst, return_value_policy policy, PyObject *parent) {
if (policy == return_value_policy::copy) {
throw cast_error("return_value_policy = copy, but the object is non-copyable!");
} else if (policy == return_value_policy::reference) {
inst->owned = false;
} else if (policy == return_value_policy::reference_internal) {
inst->owned = false;
inst->parent = parent;
Py_XINCREF(parent);
}
}
operator type*() { return value; }
operator type&() { return *value; }
protected: protected:
type *value = nullptr;
const type_info *typeinfo = nullptr; const type_info *typeinfo = nullptr;
void *value = nullptr;
object temp; object temp;
}; };
/// Generic type caster for objects stored on the heap
template <typename type> class type_caster : public type_caster_custom {
public:
static descr name() { return typeid(type); }
type_caster() : type_caster_custom(&typeid(type)) { }
static PyObject *cast(const type &src, return_value_policy policy, PyObject *parent) {
if (policy == return_value_policy::automatic)
policy = return_value_policy::copy;
return type_caster_custom::cast(&src, policy, parent, &typeid(type), &copy_constructor);
}
static PyObject *cast(const type *src, return_value_policy policy, PyObject *parent) {
return type_caster_custom::cast(src, policy, parent, &typeid(type), &copy_constructor);
}
operator type*() { return (type *) value; }
operator type&() { return (type &) *value; }
protected:
template <typename T = type, typename std::enable_if<std::is_copy_constructible<T>::value, int>::type = 0>
static void *copy_constructor(const void *arg) {
return new type((const type &)*arg);
}
template <typename T = type, typename std::enable_if<!std::is_copy_constructible<T>::value, int>::type = 0>
static void *copy_constructor(const void *) { return nullptr; }
};
#define PYBIND11_TYPE_CASTER(type, py_name) \ #define PYBIND11_TYPE_CASTER(type, py_name) \
protected: \ protected: \
type value; \ type value; \
@ -516,7 +509,7 @@ public:
bool load(PyObject *src, bool convert) { bool load(PyObject *src, bool convert) {
if (!parent::load(src, convert)) if (!parent::load(src, convert))
return false; return false;
holder = holder_type(parent::value); holder = holder_type((type *) parent::value);
return true; return true;
} }
explicit operator type*() { return this->value; } explicit operator type*() { return this->value; }

View File

@ -23,6 +23,12 @@
#define PYBIND11_EXPORT __attribute__ ((visibility("default"))) #define PYBIND11_EXPORT __attribute__ ((visibility("default")))
#endif #endif
#endif #endif
#if defined(_MSC_VER)
#define PYBIND11_NOINLINE __declspec(noinline)
#else
#define PYBIND11_NOINLINE __attribute__ ((noinline))
#endif
#include <vector> #include <vector>
#include <string> #include <string>