mirror of
https://github.com/pybind/pybind11.git
synced 2024-11-22 05:05:11 +00:00
Merge pull request #57 from tmiasko/conversion
Use object class to hold partially converted python objects.
This commit is contained in:
commit
deadbbb671
@ -59,7 +59,7 @@ Without reference counting
|
||||
|
||||
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`.
|
||||
|
||||
@ -167,6 +167,12 @@ With reference counting
|
||||
Move constructor; steals the object from ``other`` and preserves its
|
||||
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()
|
||||
|
||||
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) {
|
||||
PyObject *o1 = type_caster<typename decay<T1>::type>::cast(src.first, policy, parent);
|
||||
PyObject *o2 = type_caster<typename decay<T2>::type>::cast(src.second, policy, parent);
|
||||
if (!o1 || !o2) {
|
||||
Py_XDECREF(o1);
|
||||
Py_XDECREF(o2);
|
||||
object o1(type_caster<typename decay<T1>::type>::cast(src.first, policy, parent), false);
|
||||
object o2(type_caster<typename decay<T2>::type>::cast(src.second, policy, parent), false);
|
||||
if (!o1 || !o2)
|
||||
return nullptr;
|
||||
}
|
||||
PyObject *tuple = PyTuple_New(2);
|
||||
PyTuple_SetItem(tuple, 0, o1);
|
||||
PyTuple_SetItem(tuple, 1, o2);
|
||||
if (!tuple)
|
||||
return nullptr;
|
||||
PyTuple_SetItem(tuple, 0, o1.release());
|
||||
PyTuple_SetItem(tuple, 1, o2.release());
|
||||
return tuple;
|
||||
}
|
||||
|
||||
@ -502,25 +501,19 @@ protected:
|
||||
|
||||
/* 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...>) {
|
||||
std::array<PyObject *, size> results {{
|
||||
type_caster<typename decay<Tuple>::type>::cast(std::get<Indices>(src), policy, parent)...
|
||||
std::array<object, size> results {{
|
||||
object(type_caster<typename decay<Tuple>::type>::cast(std::get<Indices>(src), policy, parent), false)...
|
||||
}};
|
||||
bool success = true;
|
||||
for (auto result : results)
|
||||
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);
|
||||
}
|
||||
for (const auto & result : results)
|
||||
if (!result)
|
||||
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:
|
||||
@ -600,26 +593,20 @@ template <> inline void handle::cast() const { return; }
|
||||
|
||||
template <typename... Args> inline object handle::call(Args&&... args_) {
|
||||
const size_t size = sizeof...(Args);
|
||||
std::array<PyObject *, size> args{
|
||||
{ detail::type_caster<typename detail::decay<Args>::type>::cast(
|
||||
std::forward<Args>(args_), return_value_policy::reference, nullptr)... }
|
||||
std::array<object, size> args{
|
||||
{ object(detail::type_caster<typename detail::decay<Args>::type>::cast(
|
||||
std::forward<Args>(args_), return_value_policy::reference, nullptr), false)... }
|
||||
};
|
||||
bool fail = false;
|
||||
for (auto result : args)
|
||||
if (result == nullptr)
|
||||
fail = true;
|
||||
if (fail) {
|
||||
for (auto result : args) {
|
||||
Py_XDECREF(result);
|
||||
}
|
||||
for (const auto & result : args)
|
||||
if (!result)
|
||||
throw cast_error("handle::call(): unable to convert input arguments to Python objects");
|
||||
object tuple(PyTuple_New(size), false);
|
||||
if (!tuple)
|
||||
throw cast_error("handle::call(): unable to convert input arguments to Python objects");
|
||||
}
|
||||
PyObject *tuple = PyTuple_New(size);
|
||||
int counter = 0;
|
||||
for (auto result : args)
|
||||
PyTuple_SetItem(tuple, counter++, result);
|
||||
PyObject *result = PyObject_CallObject(m_ptr, tuple);
|
||||
Py_DECREF(tuple);
|
||||
for (auto & result : args)
|
||||
PyTuple_SetItem(tuple.ptr(), counter++, result.release());
|
||||
PyObject *result = PyObject_CallObject(m_ptr, tuple.ptr());
|
||||
if (result == nullptr && PyErr_Occurred())
|
||||
throw error_already_set();
|
||||
return object(result, false);
|
||||
|
@ -29,8 +29,7 @@ public:
|
||||
handle() : m_ptr(nullptr) { }
|
||||
handle(const handle &other) : m_ptr(other.m_ptr) { }
|
||||
handle(PyObject *ptr) : m_ptr(ptr) { }
|
||||
PyObject *ptr() { return m_ptr; }
|
||||
const PyObject *ptr() const { return m_ptr; }
|
||||
PyObject *ptr() const { return m_ptr; }
|
||||
void inc_ref() const { Py_XINCREF(m_ptr); }
|
||||
void dec_ref() const { Py_XDECREF(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() { dec_ref(); }
|
||||
|
||||
PyObject * release() {
|
||||
PyObject *tmp = m_ptr;
|
||||
m_ptr = nullptr;
|
||||
return tmp;
|
||||
}
|
||||
|
||||
object& operator=(object &other) {
|
||||
Py_XINCREF(other.m_ptr);
|
||||
Py_XDECREF(m_ptr);
|
||||
|
@ -43,17 +43,17 @@ public:
|
||||
}
|
||||
|
||||
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;
|
||||
for (auto const &value: src) {
|
||||
PyObject *value_ = value_conv::cast(value, policy, parent);
|
||||
if (!value_) {
|
||||
Py_DECREF(list);
|
||||
object value_ (value_conv::cast(value, policy, parent), false);
|
||||
if (!value_)
|
||||
return nullptr;
|
||||
}
|
||||
PyList_SET_ITEM(list, index++, value_); // steals a reference
|
||||
PyList_SET_ITEM(list.ptr(), index++, value_.release()); // steals a reference
|
||||
}
|
||||
return list;
|
||||
return list.release();
|
||||
}
|
||||
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) {
|
||||
PyObject *set = PySet_New(nullptr);
|
||||
object set(PySet_New(nullptr), false);
|
||||
if (!set)
|
||||
return nullptr;
|
||||
for (auto const &value: src) {
|
||||
PyObject *value_ = value_conv::cast(value, policy, parent);
|
||||
if (!value_ || PySet_Add(set, value_) != 0) {
|
||||
Py_XDECREF(value_);
|
||||
Py_DECREF(set);
|
||||
object value_(value_conv::cast(value, policy, parent), false);
|
||||
if (!value_ || PySet_Add(set.ptr(), value_.ptr()) != 0)
|
||||
return nullptr;
|
||||
}
|
||||
Py_DECREF(value_);
|
||||
}
|
||||
return set;
|
||||
return set.release();
|
||||
}
|
||||
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) {
|
||||
PyObject *dict = PyDict_New();
|
||||
object dict(PyDict_New(), false);
|
||||
if (!dict)
|
||||
return nullptr;
|
||||
for (auto const &kv: src) {
|
||||
PyObject *key = key_conv::cast(kv.first, policy, parent);
|
||||
PyObject *value = value_conv::cast(kv.second, policy, parent);
|
||||
if (!key || !value || PyDict_SetItem(dict, key, value) != 0) {
|
||||
Py_XDECREF(key);
|
||||
Py_XDECREF(value);
|
||||
Py_DECREF(dict);
|
||||
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)
|
||||
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(">"));
|
||||
|
Loading…
Reference in New Issue
Block a user