do more work with classes from pytypes.h (especially for STL container casting)

This commit is contained in:
Wenzel Jakob
2016-01-17 22:36:41 +01:00
parent d561cb010c
commit 678d787ca4
10 changed files with 128 additions and 105 deletions

View File

@@ -225,8 +225,8 @@ struct argument_entry {
/// Internal data struture used to track registered instances and types
struct internals {
std::unordered_map<const void *, void*> registered_types_cpp; // std::type_info* -> type_info
std::unordered_map<const void *, void*> registered_types_py; // PyTypeObject* -> type_info
std::unordered_map<const void *, void*> registered_instances; // void * -> PyObject*
std::unordered_map<const void *, void*> registered_types_py; // PyTypeObject* -> type_info
std::unordered_map<const void *, void*> registered_instances; // void * -> PyObject*
std::unordered_set<std::pair<const PyObject *, const char *>, overload_hash> inactive_overload_cache;
};
@@ -271,4 +271,7 @@ struct error_already_set : public std::runtime_error { public: error_already_set
/// Thrown when pybind11::cast or handle::call fail due to a type casting error
struct cast_error : public std::runtime_error { public: cast_error(const std::string &w = "") : std::runtime_error(w) {} };
PYBIND11_NOINLINE inline void pybind11_fail(const char *reason) { throw std::runtime_error(reason); }
PYBIND11_NOINLINE inline void pybind11_fail(const std::string &reason) { throw std::runtime_error(reason); }
NAMESPACE_END(pybind11)

View File

@@ -24,7 +24,6 @@
#endif
#include "cast.h"
#include <iostream>
NAMESPACE_BEGIN(pybind11)
@@ -196,9 +195,9 @@ protected:
a.value, return_value_policy::automatic, nullptr);
if (obj == nullptr)
throw std::runtime_error("arg(): could not convert default keyword "
"argument into a Python object (type not "
"registered yet?)");
pybind11_fail("arg(): could not convert default keyword "
"argument into a Python object (type not "
"registered yet?)");
entry->args.emplace_back(a.name, a.descr, obj);
}
@@ -490,7 +489,7 @@ protected:
} else if (c == '%') {
const std::type_info *t = types[type_index++];
if (!t)
throw std::runtime_error("Internal error while parsing type signature (1)");
pybind11_fail("Internal error while parsing type signature (1)");
auto it = registered_types.find(t);
if (it != registered_types.end()) {
signature += ((const detail::type_info *) it->second)->type->tp_name;
@@ -504,7 +503,7 @@ protected:
}
}
if (type_depth != 0 || types[type_index] != nullptr)
throw std::runtime_error("Internal error while parsing type signature (2)");
pybind11_fail("Internal error while parsing type signature (2)");
#if !defined(PYBIND11_CPP14)
delete[] types;
@@ -519,7 +518,7 @@ protected:
#endif
if (!m_entry->args.empty() && (int) m_entry->args.size() != args)
throw std::runtime_error(
pybind11_fail(
"cpp_function(): function \"" + std::string(m_entry->name) + "\" takes " +
std::to_string(args) + " arguments, but " + std::to_string(m_entry->args.size()) +
" pybind11::arg entries were specified!");
@@ -555,7 +554,7 @@ protected:
});
m_ptr = PyCFunction_New(m_entry->def, entry_capsule.ptr());
if (!m_ptr)
throw std::runtime_error("cpp_function::cpp_function(): Could not allocate function object");
pybind11_fail("cpp_function::cpp_function(): Could not allocate function object");
} else {
/* Append at the end of the overload chain */
m_ptr = m_entry->sibling;
@@ -597,7 +596,7 @@ protected:
m_ptr = PyMethod_New(m_ptr, nullptr, entry->class_);
#endif
if (!m_ptr)
throw std::runtime_error("cpp_function::cpp_function(): Could not allocate instance method object");
pybind11_fail("cpp_function::cpp_function(): Could not allocate instance method object");
Py_DECREF(func);
}
}
@@ -621,7 +620,7 @@ public:
m_ptr = Py_InitModule3(name, nullptr, doc);
#endif
if (m_ptr == nullptr)
throw std::runtime_error("Internal error in module::module()");
pybind11_fail("Internal error in module::module()");
inc_ref();
}
@@ -647,7 +646,7 @@ public:
static module import(const char *name) {
PyObject *obj = PyImport_ImportModule(name);
if (!obj)
throw std::runtime_error("Module \"" + std::string(name) + "\" not found!");
pybind11_fail("Module \"" + std::string(name) + "\" not found!");
return module(obj, false);
}
};
@@ -668,7 +667,7 @@ public:
auto type = (PyHeapTypeObject*) type_holder.ptr();
if (!type_holder || !name)
throw std::runtime_error("generic_type: unable to create type object!");
pybind11_fail("generic_type: unable to create type object!");
/* Register supplemental type information in C++ dict */
auto &internals = get_internals();
@@ -732,7 +731,7 @@ public:
}
if (PyType_Ready(&type->ht_type) < 0)
throw std::runtime_error("generic_type: PyType_Ready failed!");
pybind11_fail("generic_type: PyType_Ready failed!");
m_ptr = type_holder.ptr();
@@ -756,7 +755,7 @@ protected:
object type_holder(PyType_Type.tp_alloc(&PyType_Type, 0), false);
object name(PYBIND11_FROM_STRING(name_.c_str()), false);
if (!type_holder || !name)
throw std::runtime_error("generic_type::metaclass(): unable to create type object!");
pybind11_fail("generic_type::metaclass(): unable to create type object!");
auto type = (PyHeapTypeObject*) type_holder.ptr();
type->ht_name = name.release();
@@ -767,7 +766,7 @@ protected:
~Py_TPFLAGS_HAVE_GC;
if (PyType_Ready(&type->ht_type) < 0)
throw std::runtime_error("generic_type::metaclass(): PyType_Ready failed!");
pybind11_fail("generic_type::metaclass(): PyType_Ready failed!");
ob_type = (PyTypeObject *) type_holder.release();
}
@@ -798,7 +797,7 @@ protected:
auto &registered_instances = detail::get_internals().registered_instances;
auto it = registered_instances.find(self->value);
if (it == registered_instances.end())
throw std::runtime_error("generic_type::dealloc(): Tried to deallocate unregistered instance!");
pybind11_fail("generic_type::dealloc(): Tried to deallocate unregistered instance!");
registered_instances.erase(it);
}
Py_XDECREF(self->parent);
@@ -1096,14 +1095,12 @@ PYBIND11_NOINLINE inline void keep_alive_impl(int Nurse, int Patient, PyObject *
handle patient(Patient > 0 ? PyTuple_GetItem(arg, Patient - 1) : ret);
if (!nurse || !patient)
throw std::runtime_error("Could not activate keep_alive!");
pybind11_fail("Could not activate keep_alive!");
cpp_function disable_lifesupport(
[patient](handle weakref) { patient.dec_ref(); weakref.dec_ref(); });
weakref wr(nurse, disable_lifesupport);
if (!wr)
throw std::runtime_error("Could not allocate weak reference!");
patient.inc_ref(); /* reference patient and leak the weak reference */
(void) wr.release();
@@ -1138,7 +1135,7 @@ template <typename InputType, typename OutputType> void implicitly_convertible()
auto & registered_types = detail::get_internals().registered_types_cpp;
auto it = registered_types.find(&typeid(OutputType));
if (it == registered_types.end())
throw std::runtime_error("implicitly_convertible: Unable to find type " + type_id<OutputType>());
pybind11_fail("implicitly_convertible: Unable to find type " + type_id<OutputType>());
((detail::type_info *) it->second)->implicit_conversions.push_back(implicit_caster);
}
@@ -1196,7 +1193,7 @@ inline function get_overload(const void *this_ptr, const char *name) {
#define PYBIND11_OVERLOAD_PURE(ret_type, class_name, name, ...) \
PYBIND11_OVERLOAD_INT(ret_type, class_name, name, __VA_ARGS__) \
throw std::runtime_error("Tried to call pure virtual function \"" #name "\"");
pybind11::pybind11_fail("Tried to call pure virtual function \"" #name "\"");
NAMESPACE_END(pybind11)

View File

@@ -88,12 +88,12 @@ public:
iterator(PyObject *obj, bool borrowed = false) : object(obj, borrowed) { ++*this; }
iterator& operator++() {
if (ptr())
value = object(PyIter_Next(ptr()), false);
value = object(PyIter_Next(m_ptr), false);
return *this;
}
bool operator==(const iterator &it) const { return *it == **this; }
bool operator!=(const iterator &it) const { return *it != **this; }
const object &operator*() const { return value; }
const handle &operator*() const { return value; }
bool check() const { return PyIter_Check(ptr()); }
private:
object value;
@@ -127,10 +127,10 @@ public:
void operator=(const handle &h) {
if (attr) {
if (PyObject_SetAttr(obj, key, (PyObject *) h.ptr()) < 0)
throw std::runtime_error("Unable to set object attribute");
pybind11_fail("Unable to set object attribute");
} else {
if (PyObject_SetItem(obj, key, (PyObject *) h.ptr()) < 0)
throw std::runtime_error("Unable to set object item");
pybind11_fail("Unable to set object item");
}
}
@@ -164,12 +164,12 @@ public:
void operator=(const handle &o) {
o.inc_ref(); // PyList_SetItem steals a reference
if (PyList_SetItem(list, (ssize_t) index, (PyObject *) o.ptr()) < 0)
throw std::runtime_error("Unable to assign value in Python list!");
pybind11_fail("Unable to assign value in Python list!");
}
operator object() const {
PyObject *result = PyList_GetItem(list, (ssize_t) index);
if (!result)
throw std::runtime_error("Unable to retrieve value from Python list!");
pybind11_fail("Unable to retrieve value from Python list!");
return object(result, true);
}
private:
@@ -184,12 +184,12 @@ public:
void operator=(const handle &o) {
o.inc_ref(); // PyTuple_SetItem steals a reference
if (PyTuple_SetItem(tuple, (ssize_t) index, (PyObject *) o.ptr()) < 0)
throw std::runtime_error("Unable to assign value in Python tuple!");
pybind11_fail("Unable to assign value in Python tuple!");
}
operator object() const {
PyObject *result = PyTuple_GetItem(tuple, (ssize_t) index);
if (!result)
throw std::runtime_error("Unable to retrieve value from Python tuple!");
pybind11_fail("Unable to retrieve value from Python tuple!");
return object(result, true);
}
private:
@@ -205,8 +205,8 @@ public:
pos = -1;
return *this;
}
std::pair<object, object> operator*() const {
return std::make_pair(object(key, true), object(value, true));
std::pair<handle, handle> operator*() const {
return std::make_pair(key, value);
}
bool operator==(const dict_iterator &it) const { return it.pos == pos; }
bool operator!=(const dict_iterator &it) const { return it.pos != pos; }
@@ -242,7 +242,10 @@ inline iterator handle::end() const { return iterator(nullptr); }
class str : public object {
public:
PYBIND11_OBJECT_DEFAULT(str, object, PyUnicode_Check)
str(const std::string &s) : object(PyUnicode_FromStringAndSize(s.c_str(), s.length()), false) { }
str(const std::string &s)
: object(PyUnicode_FromStringAndSize(s.c_str(), s.length()), false) {
if (!m_ptr) pybind11_fail("Could not allocate string object!");
}
operator std::string() const {
#if PY_MAJOR_VERSION >= 3
@@ -250,7 +253,7 @@ public:
#else
object temp(PyUnicode_AsUTF8String(m_ptr), false);
if (temp.ptr() == nullptr)
throw std::runtime_error("Unable to extract string contents!");
pybind11_fail("Unable to extract string contents!");
return PyString_AsString(temp.ptr());
#endif
}
@@ -270,14 +273,16 @@ public:
PYBIND11_OBJECT_DEFAULT(bytes, object, PYBIND11_BYTES_CHECK)
bytes(const std::string &s)
: object(PYBIND11_BYTES_FROM_STRING_AND_SIZE(s.data(), s.size()), false) { }
: object(PYBIND11_BYTES_FROM_STRING_AND_SIZE(s.data(), s.size()), false) {
if (!m_ptr) pybind11_fail("Could not allocate bytes object!");
}
operator std::string() const {
char *buffer;
ssize_t length;
int err = PYBIND11_BYTES_AS_STRING_AND_SIZE(m_ptr, &buffer, &length);
if (err == -1)
throw std::runtime_error("Unable to extract bytes contents!");
pybind11_fail("Unable to extract bytes contents!");
return std::string(buffer, length);
}
};
@@ -306,6 +311,7 @@ public:
else
m_ptr = PyLong_FromUnsignedLongLong((unsigned long long) value);
}
if (!m_ptr) pybind11_fail("Could not allocate int object!");
}
template <typename T,
@@ -328,8 +334,12 @@ public:
class float_ : public object {
public:
PYBIND11_OBJECT_DEFAULT(float_, object, PyFloat_Check)
float_(float value) : object(PyFloat_FromDouble((double) value), false) { }
float_(double value) : object(PyFloat_FromDouble((double) value), false) { }
float_(float value) : object(PyFloat_FromDouble((double) value), false) {
if (!m_ptr) pybind11_fail("Could not allocate float object!");
}
float_(double value) : object(PyFloat_FromDouble((double) value), false) {
if (!m_ptr) pybind11_fail("Could not allocate float object!");
}
operator float() const { return (float) PyFloat_AsDouble(m_ptr); }
operator double() const { return (double) PyFloat_AsDouble(m_ptr); }
};
@@ -337,7 +347,9 @@ public:
class weakref : public object {
public:
PYBIND11_OBJECT_DEFAULT(weakref, object, PyWeakref_Check)
weakref(handle obj, handle callback = handle()) : object(PyWeakref_NewRef(obj.ptr(), callback.ptr()), false) { }
weakref(handle obj, handle callback = handle()) : object(PyWeakref_NewRef(obj.ptr(), callback.ptr()), false) {
if (!m_ptr) pybind11_fail("Could not allocate weak reference!");
}
};
class slice : public object {
@@ -346,6 +358,7 @@ public:
slice(ssize_t start_, ssize_t stop_, ssize_t step_) {
int_ start(start_), stop(stop_), step(step_);
m_ptr = PySlice_New(start.ptr(), stop.ptr(), step.ptr());
if (!m_ptr) pybind11_fail("Could not allocate slice object!");
}
bool compute(ssize_t length, ssize_t *start, ssize_t *stop, ssize_t *step, ssize_t *slicelength) const {
return PySlice_GetIndicesEx((PYBIND11_SLICE_OBJECT *) m_ptr, length,
@@ -357,10 +370,13 @@ class capsule : public object {
public:
PYBIND11_OBJECT_DEFAULT(capsule, object, PyCapsule_CheckExact)
capsule(PyObject *obj, bool borrowed) : object(obj, borrowed) { }
capsule(void *value, void (*destruct)(PyObject *) = nullptr) : object(PyCapsule_New(value, nullptr, destruct), false) { }
capsule(void *value, void (*destruct)(PyObject *) = nullptr)
: object(PyCapsule_New(value, nullptr, destruct), false) {
if (!m_ptr) pybind11_fail("Could not allocate capsule object!");
}
template <typename T> operator T *() const {
T * result = static_cast<T *>(PyCapsule_GetPointer(m_ptr, nullptr));
if (!result) throw std::runtime_error("Unable to extract capsule contents!");
if (!result) pybind11_fail("Unable to extract capsule contents!");
return result;
}
};
@@ -368,7 +384,9 @@ public:
class tuple : public object {
public:
PYBIND11_OBJECT(tuple, object, PyTuple_Check)
tuple(size_t size = 0) : object(PyTuple_New((ssize_t) size), false) { }
tuple(size_t size = 0) : object(PyTuple_New((ssize_t) size), false) {
if (!m_ptr) pybind11_fail("Could not allocate tuple object!");
}
size_t size() const { return (size_t) PyTuple_Size(m_ptr); }
detail::tuple_accessor operator[](size_t index) const { return detail::tuple_accessor(ptr(), index); }
};
@@ -376,7 +394,9 @@ public:
class dict : public object {
public:
PYBIND11_OBJECT(dict, object, PyDict_Check)
dict() : object(PyDict_New(), false) { }
dict() : object(PyDict_New(), false) {
if (!m_ptr) pybind11_fail("Could not allocate dict object!");
}
size_t size() const { return (size_t) PyDict_Size(m_ptr); }
detail::dict_iterator begin() const { return (++detail::dict_iterator(ptr(), 0)); }
detail::dict_iterator end() const { return detail::dict_iterator(); }
@@ -386,7 +406,9 @@ public:
class list : public object {
public:
PYBIND11_OBJECT(list, object, PyList_Check)
list(size_t size = 0) : object(PyList_New((ssize_t) size), false) { }
list(size_t size = 0) : object(PyList_New((ssize_t) size), false) {
if (!m_ptr) pybind11_fail("Could not allocate list object!");
}
size_t size() const { return (size_t) PyList_Size(m_ptr); }
detail::list_accessor operator[](size_t index) const { return detail::list_accessor(ptr(), index); }
void append(const object &object) const { PyList_Append(m_ptr, (PyObject *) object.ptr()); }
@@ -395,10 +417,12 @@ public:
class set : public object {
public:
PYBIND11_OBJECT(set, object, PySet_Check)
set() : object(PySet_New(nullptr), false) { }
set() : object(PySet_New(nullptr), false) {
if (!m_ptr) pybind11_fail("Could not allocate set object!");
}
size_t size() const { return (size_t) PySet_Size(m_ptr); }
void add(const object &object) const { PySet_Add(m_ptr, (PyObject *) object.ptr()); }
void clear() const { PySet_Clear(ptr()); }
bool add(const object &object) const { return PySet_Add(m_ptr, (PyObject *) object.ptr()) == 0; }
void clear() const { PySet_Clear(m_ptr); }
};
class function : public object {
@@ -448,7 +472,7 @@ PYBIND11_NOINLINE inline detail::type_info* get_type_info(PyTypeObject *type) {
return (detail::type_info *) it->second;
type = type->tp_base;
if (type == nullptr)
throw std::runtime_error("pybind11::detail::get_type_info: unable to find type object!");
pybind11_fail("pybind11::detail::get_type_info: unable to find type object!");
} while (true);
}

View File

@@ -14,7 +14,6 @@
#include <set>
#include <iostream>
#if defined(_MSC_VER)
#pragma warning(push)
#pragma warning(disable: 4127) // warning C4127: Conditional expression is constant
@@ -28,14 +27,14 @@ template <typename Value, typename Alloc> struct type_caster<std::vector<Value,
typedef type_caster<Value> value_conv;
public:
bool load(PyObject *src, bool convert) {
if (!PyList_Check(src))
list l(src, true);
if (!l.check())
return false;
size_t size = (size_t) PyList_GET_SIZE(src);
value.reserve(size);
value.reserve(l.size());
value.clear();
value_conv conv;
for (size_t i=0; i<size; ++i) {
if (!conv.load(PyList_GetItem(src, (ssize_t) i), convert))
for (auto it : l) {
if (!conv.load(it.ptr(), convert))
return false;
value.push_back((Value) conv);
}
@@ -43,17 +42,15 @@ public:
}
static PyObject *cast(const type &src, return_value_policy policy, PyObject *parent) {
object list(PyList_New(src.size()), false);
if (!list)
return nullptr;
list l(src.size());
size_t index = 0;
for (auto const &value: src) {
object value_ (value_conv::cast(value, policy, parent), false);
object value_(value_conv::cast(value, policy, parent), false);
if (!value_)
return nullptr;
PyList_SET_ITEM(list.ptr(), index++, value_.release()); // steals a reference
PyList_SET_ITEM(l.ptr(), index++, value_.release()); // steals a reference
}
return list.release();
return l.release();
}
PYBIND11_TYPE_CASTER(type, _("list<") + value_conv::name() + _(">"));
};
@@ -68,8 +65,8 @@ public:
return false;
value.clear();
key_conv conv;
for (const object &o: s) {
if (!conv.load((PyObject *) o.ptr(), convert))
for (auto entry : s) {
if (!conv.load(entry.ptr(), convert))
return false;
value.insert((Key) conv);
}
@@ -77,15 +74,13 @@ public:
}
static PyObject *cast(const type &src, return_value_policy policy, PyObject *parent) {
object set(PySet_New(nullptr), false);
if (!set)
return nullptr;
pybind11::set s;
for (auto const &value: src) {
object value_(key_conv::cast(value, policy, parent), false);
if (!value_ || PySet_Add(set.ptr(), value_.ptr()) != 0)
if (!value_ || !s.add(value))
return nullptr;
}
return set.release();
return s.release();
}
PYBIND11_TYPE_CASTER(type, _("set<") + key_conv::name() + _(">"));
};
@@ -97,16 +92,15 @@ public:
typedef type_caster<Value> value_conv;
bool load(PyObject *src, bool convert) {
if (!PyDict_Check(src))
dict d(src, true);
if (!d.check())
return false;
value.clear();
PyObject *key_, *value_;
ssize_t pos = 0;
key_conv kconv;
value_conv vconv;
while (PyDict_Next(src, &pos, &key_, &value_)) {
if (!kconv.load(key_, convert) || !vconv.load(value_, convert))
value.clear();
for (auto it : d) {
if (!kconv.load(it.first.ptr(), convert) ||
!vconv.load(it.second.ptr(), convert))
return false;
value[(Key) kconv] = (Value) vconv;
}
@@ -114,16 +108,15 @@ public:
}
static PyObject *cast(const type &src, return_value_policy policy, PyObject *parent) {
object dict(PyDict_New(), false);
if (!dict)
return nullptr;
dict d;
for (auto const &kv: src) {
object key(key_conv::cast(kv.first, policy, parent), false);
object value(value_conv::cast(kv.second, policy, parent), false);
if (!key || !value || PyDict_SetItem(dict.ptr(), key.ptr(), value.ptr()) != 0)
if (!key || !value)
return nullptr;
d[key] = value;
}
return dict.release();
return d.release();
}
PYBIND11_TYPE_CASTER(type, _("dict<") + key_conv::name() + _(", ") + value_conv::name() + _(">"));
@@ -131,7 +124,10 @@ public:
NAMESPACE_END(detail)
inline std::ostream &operator<<(std::ostream &os, const object &obj) { os << (std::string) obj.str(); return os; }
inline std::ostream &operator<<(std::ostream &os, const handle &obj) {
os << (std::string) obj.str();
return os;
}
NAMESPACE_END(pybind11)

View File

@@ -11,6 +11,7 @@
#include <cstdio>
#include <cstdlib>
#if defined(__GNUG__)
#include <cxxabi.h>
#endif
@@ -26,7 +27,7 @@ inline void erase_all(std::string &string, const std::string &search) {
}
}
inline void clean_type_id(std::string &name) {
PYBIND11_NOINLINE inline void clean_type_id(std::string &name) {
#if defined(__GNUG__)
int status = 0;
std::unique_ptr<char, void (*)(void *)> res {