Merge pull request #57 from tmiasko/conversion

Use object class to hold partially converted python objects.
This commit is contained in:
Wenzel Jakob 2016-01-07 00:08:38 +01:00
commit deadbbb671
4 changed files with 63 additions and 71 deletions

View File

@ -59,7 +59,7 @@ Without reference counting
Creates a :class:`handle` from the given raw Python object pointer. Creates a :class:`handle` from the given raw Python object pointer.
.. function:: PyObject * handle::ptr() .. function:: PyObject * handle::ptr() const
Return the ``PyObject *`` underlying a :class:`handle`. Return the ``PyObject *`` underlying a :class:`handle`.
@ -167,6 +167,12 @@ With reference counting
Move constructor; steals the object from ``other`` and preserves its Move constructor; steals the object from ``other`` and preserves its
reference count. reference count.
.. function:: PyObject* object::release()
Release ownership of underlying ``PyObject *``. Returns raw Python object
pointer without decreasing its reference count and resets handle to
``nullptr``-valued pointer.
.. function:: object::~object() .. function:: object::~object()
Constructor, which automatically calls :func:`handle::dec_ref()`. Constructor, which automatically calls :func:`handle::dec_ref()`.

View File

@ -398,16 +398,15 @@ public:
} }
static PyObject *cast(const type &src, return_value_policy policy, PyObject *parent) { static PyObject *cast(const type &src, return_value_policy policy, PyObject *parent) {
PyObject *o1 = type_caster<typename decay<T1>::type>::cast(src.first, policy, parent); object o1(type_caster<typename decay<T1>::type>::cast(src.first, policy, parent), false);
PyObject *o2 = type_caster<typename decay<T2>::type>::cast(src.second, policy, parent); object o2(type_caster<typename decay<T2>::type>::cast(src.second, policy, parent), false);
if (!o1 || !o2) { if (!o1 || !o2)
Py_XDECREF(o1);
Py_XDECREF(o2);
return nullptr; return nullptr;
}
PyObject *tuple = PyTuple_New(2); PyObject *tuple = PyTuple_New(2);
PyTuple_SetItem(tuple, 0, o1); if (!tuple)
PyTuple_SetItem(tuple, 1, o2); return nullptr;
PyTuple_SetItem(tuple, 0, o1.release());
PyTuple_SetItem(tuple, 1, o2.release());
return tuple; return tuple;
} }
@ -502,25 +501,19 @@ protected:
/* Implementation: Convert a C++ tuple into a Python tuple */ /* Implementation: Convert a C++ tuple into a Python tuple */
template <size_t ... Indices> static PyObject *cast(const type &src, return_value_policy policy, PyObject *parent, index_sequence<Indices...>) { template <size_t ... Indices> static PyObject *cast(const type &src, return_value_policy policy, PyObject *parent, index_sequence<Indices...>) {
std::array<PyObject *, size> results {{ std::array<object, size> results {{
type_caster<typename decay<Tuple>::type>::cast(std::get<Indices>(src), policy, parent)... object(type_caster<typename decay<Tuple>::type>::cast(std::get<Indices>(src), policy, parent), false)...
}}; }};
bool success = true; for (const auto & result : results)
for (auto result : results) if (!result)
if (result == nullptr) return nullptr;
success = false; PyObject *tuple = PyTuple_New(size);
if (success) { if (!tuple)
PyObject *tuple = PyTuple_New(size);
int counter = 0;
for (auto result : results)
PyTuple_SetItem(tuple, counter++, result);
return tuple;
} else {
for (auto result : results) {
Py_XDECREF(result);
}
return nullptr; return nullptr;
} int counter = 0;
for (auto & result : results)
PyTuple_SetItem(tuple, counter++, result.release());
return tuple;
} }
protected: protected:
@ -600,26 +593,20 @@ template <> inline void handle::cast() const { return; }
template <typename... Args> inline object handle::call(Args&&... args_) { template <typename... Args> inline object handle::call(Args&&... args_) {
const size_t size = sizeof...(Args); const size_t size = sizeof...(Args);
std::array<PyObject *, size> args{ std::array<object, size> args{
{ detail::type_caster<typename detail::decay<Args>::type>::cast( { object(detail::type_caster<typename detail::decay<Args>::type>::cast(
std::forward<Args>(args_), return_value_policy::reference, nullptr)... } std::forward<Args>(args_), return_value_policy::reference, nullptr), false)... }
}; };
bool fail = false; for (const auto & result : args)
for (auto result : args) if (!result)
if (result == nullptr) throw cast_error("handle::call(): unable to convert input arguments to Python objects");
fail = true; object tuple(PyTuple_New(size), false);
if (fail) { if (!tuple)
for (auto result : args) {
Py_XDECREF(result);
}
throw cast_error("handle::call(): unable to convert input arguments to Python objects"); throw cast_error("handle::call(): unable to convert input arguments to Python objects");
}
PyObject *tuple = PyTuple_New(size);
int counter = 0; int counter = 0;
for (auto result : args) for (auto & result : args)
PyTuple_SetItem(tuple, counter++, result); PyTuple_SetItem(tuple.ptr(), counter++, result.release());
PyObject *result = PyObject_CallObject(m_ptr, tuple); PyObject *result = PyObject_CallObject(m_ptr, tuple.ptr());
Py_DECREF(tuple);
if (result == nullptr && PyErr_Occurred()) if (result == nullptr && PyErr_Occurred())
throw error_already_set(); throw error_already_set();
return object(result, false); return object(result, false);

View File

@ -29,8 +29,7 @@ public:
handle() : m_ptr(nullptr) { } handle() : m_ptr(nullptr) { }
handle(const handle &other) : m_ptr(other.m_ptr) { } handle(const handle &other) : m_ptr(other.m_ptr) { }
handle(PyObject *ptr) : m_ptr(ptr) { } handle(PyObject *ptr) : m_ptr(ptr) { }
PyObject *ptr() { return m_ptr; } PyObject *ptr() const { return m_ptr; }
const PyObject *ptr() const { return m_ptr; }
void inc_ref() const { Py_XINCREF(m_ptr); } void inc_ref() const { Py_XINCREF(m_ptr); }
void dec_ref() const { Py_XDECREF(m_ptr); } void dec_ref() const { Py_XDECREF(m_ptr); }
int ref_count() const { return (int) Py_REFCNT(m_ptr); } int ref_count() const { return (int) Py_REFCNT(m_ptr); }
@ -60,6 +59,12 @@ public:
object(object &&other) { m_ptr = other.m_ptr; other.m_ptr = nullptr; } object(object &&other) { m_ptr = other.m_ptr; other.m_ptr = nullptr; }
~object() { dec_ref(); } ~object() { dec_ref(); }
PyObject * release() {
PyObject *tmp = m_ptr;
m_ptr = nullptr;
return tmp;
}
object& operator=(object &other) { object& operator=(object &other) {
Py_XINCREF(other.m_ptr); Py_XINCREF(other.m_ptr);
Py_XDECREF(m_ptr); Py_XDECREF(m_ptr);

View File

@ -43,17 +43,17 @@ public:
} }
static PyObject *cast(const type &src, return_value_policy policy, PyObject *parent) { static PyObject *cast(const type &src, return_value_policy policy, PyObject *parent) {
PyObject *list = PyList_New(src.size()); object list(PyList_New(src.size()), false);
if (!list)
return nullptr;
size_t index = 0; size_t index = 0;
for (auto const &value: src) { for (auto const &value: src) {
PyObject *value_ = value_conv::cast(value, policy, parent); object value_ (value_conv::cast(value, policy, parent), false);
if (!value_) { if (!value_)
Py_DECREF(list);
return nullptr; return nullptr;
} PyList_SET_ITEM(list.ptr(), index++, value_.release()); // steals a reference
PyList_SET_ITEM(list, index++, value_); // steals a reference
} }
return list; return list.release();
} }
PYBIND11_TYPE_CASTER(type, detail::descr("list<") + value_conv::name() + detail::descr(">")); PYBIND11_TYPE_CASTER(type, detail::descr("list<") + value_conv::name() + detail::descr(">"));
}; };
@ -77,17 +77,15 @@ public:
} }
static PyObject *cast(const type &src, return_value_policy policy, PyObject *parent) { static PyObject *cast(const type &src, return_value_policy policy, PyObject *parent) {
PyObject *set = PySet_New(nullptr); object set(PySet_New(nullptr), false);
if (!set)
return nullptr;
for (auto const &value: src) { for (auto const &value: src) {
PyObject *value_ = value_conv::cast(value, policy, parent); object value_(value_conv::cast(value, policy, parent), false);
if (!value_ || PySet_Add(set, value_) != 0) { if (!value_ || PySet_Add(set.ptr(), value_.ptr()) != 0)
Py_XDECREF(value_);
Py_DECREF(set);
return nullptr; return nullptr;
}
Py_DECREF(value_);
} }
return set; return set.release();
} }
PYBIND11_TYPE_CASTER(type, detail::descr("set<") + value_conv::name() + detail::descr(">")); PYBIND11_TYPE_CASTER(type, detail::descr("set<") + value_conv::name() + detail::descr(">"));
}; };
@ -116,20 +114,16 @@ public:
} }
static PyObject *cast(const type &src, return_value_policy policy, PyObject *parent) { static PyObject *cast(const type &src, return_value_policy policy, PyObject *parent) {
PyObject *dict = PyDict_New(); object dict(PyDict_New(), false);
if (!dict)
return nullptr;
for (auto const &kv: src) { for (auto const &kv: src) {
PyObject *key = key_conv::cast(kv.first, policy, parent); object key(key_conv::cast(kv.first, policy, parent), false);
PyObject *value = value_conv::cast(kv.second, policy, parent); object value(value_conv::cast(kv.second, policy, parent), false);
if (!key || !value || PyDict_SetItem(dict, key, value) != 0) { if (!key || !value || PyDict_SetItem(dict.ptr(), key.ptr(), value.ptr()) != 0)
Py_XDECREF(key);
Py_XDECREF(value);
Py_DECREF(dict);
return nullptr; return nullptr;
}
Py_DECREF(key);
Py_DECREF(value);
} }
return dict; return dict.release();
} }
PYBIND11_TYPE_CASTER(type, detail::descr("dict<") + key_conv::name() + detail::descr(", ") + value_conv::name() + detail::descr(">")); PYBIND11_TYPE_CASTER(type, detail::descr("dict<") + key_conv::name() + detail::descr(", ") + value_conv::name() + detail::descr(">"));