mirror of
https://github.com/pybind/pybind11.git
synced 2024-11-22 13:15:12 +00:00
Use object class to hold partially converted python objects.
Using object class to hold converted object automatically deallocates object if an exception is thrown or scope is left before constructing complete Python object. Additionally added method object::release() that allows to release ownership of python object without decreasing its reference count.
This commit is contained in:
parent
e9dc824866
commit
ca77130be8
@ -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()`.
|
||||||
|
@ -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)
|
|
||||||
success = false;
|
|
||||||
if (success) {
|
|
||||||
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;
|
||||||
}
|
PyObject *tuple = PyTuple_New(size);
|
||||||
|
if (!tuple)
|
||||||
|
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);
|
||||||
|
@ -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);
|
||||||
|
@ -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.release();
|
||||||
}
|
|
||||||
return list;
|
|
||||||
}
|
}
|
||||||
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.release();
|
||||||
}
|
|
||||||
return set;
|
|
||||||
}
|
}
|
||||||
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);
|
return dict.release();
|
||||||
Py_DECREF(value);
|
|
||||||
}
|
|
||||||
return dict;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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(">"));
|
||||||
|
Loading…
Reference in New Issue
Block a user