Merge pull request #52 from tmiasko/const-correctness
Make handle and related classes const correct.
diff --git a/docs/reference.rst b/docs/reference.rst
index 2af84da..ab5c11b 100644
--- a/docs/reference.rst
+++ b/docs/reference.rst
@@ -167,6 +167,12 @@
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()
Destructor, which automatically calls :func:`handle::dec_ref()`.
diff --git a/include/pybind11/cast.h b/include/pybind11/cast.h
index 54ef8c7..ebdc841 100644
--- a/include/pybind11/cast.h
+++ b/include/pybind11/cast.h
@@ -154,8 +154,9 @@
}
auto it = internals.registered_types.find(type_info);
if (it == internals.registered_types.end()) {
- std::string msg = std::string("Unregistered type : ") + type_info->name();
- detail::clean_type_id(msg);
+ std::string tname = type_info->name();
+ detail::clean_type_id(tname);
+ std::string msg = "Unregistered type : " + tname;
PyErr_SetString(PyExc_TypeError, msg.c_str());
return nullptr;
}
@@ -397,16 +398,15 @@
}
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;
}
@@ -501,25 +501,19 @@
/* 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:
@@ -599,26 +593,20 @@
template <typename... Args> inline object handle::call(Args&&... args_) const {
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);
diff --git a/include/pybind11/pybind11.h b/include/pybind11/pybind11.h
index c159b11..4f7d589 100644
--- a/include/pybind11/pybind11.h
+++ b/include/pybind11/pybind11.h
@@ -24,6 +24,7 @@
#endif
#include "cast.h"
+#include <iostream>
NAMESPACE_BEGIN(pybind11)
@@ -97,16 +98,17 @@
(void) unused;
}
- template <typename... T> static void process_extras(const std::tuple<T...> &args,
+ template <typename... T> static int process_extras(const std::tuple<T...> &args,
PyObject *pyArgs, PyObject *kwargs, bool is_method) {
- process_extras(args, pyArgs, kwargs, is_method, typename detail::make_index_sequence<sizeof...(T)>::type());
+ return process_extras(args, pyArgs, kwargs, is_method, typename detail::make_index_sequence<sizeof...(T)>::type());
}
- template <typename... T, size_t... Index> static void process_extras(const std::tuple<T...> &args,
+ template <typename... T, size_t... Index> static int process_extras(const std::tuple<T...> &args,
PyObject *pyArgs, PyObject *kwargs, bool is_method, detail::index_sequence<Index...>) {
- int index = is_method ? 1 : 0;
- int unused[] = { 0, (process_extra(std::get<Index>(args), index, pyArgs, kwargs), 0)... };
+ int index = is_method ? 1 : 0, kwarg_refs = 0;
+ int unused[] = { 0, (process_extra(std::get<Index>(args), index, kwarg_refs, pyArgs, kwargs), 0)... };
(void) unused; (void) index;
+ return kwarg_refs;
}
static void process_extra(const char *doc, function_entry *entry, const char **, const char **) { entry->doc = doc; }
@@ -133,8 +135,8 @@
static void process_extra(const pybind11::return_value_policy p, function_entry *entry, const char **, const char **) { entry->policy = p; }
static void process_extra(pybind11::sibling s, function_entry *entry, const char **, const char **) { entry->sibling = s.value; }
- template <typename T> static void process_extra(T, int &, PyObject *, PyObject *) { }
- static void process_extra(const pybind11::arg &a, int &index, PyObject *args, PyObject *kwargs) {
+ template <typename T> static void process_extra(T, int &, int&, PyObject *, PyObject *) { }
+ static void process_extra(const pybind11::arg &a, int &index, int &kwarg_refs, PyObject *args, PyObject *kwargs) {
if (kwargs) {
if (PyTuple_GET_ITEM(args, index) != nullptr) {
index++;
@@ -144,12 +146,13 @@
if (value) {
Py_INCREF(value);
PyTuple_SetItem(args, index, value);
+ kwarg_refs++;
}
}
index++;
}
template <typename T>
- static void process_extra(const pybind11::arg_t<T> &a, int &index, PyObject *args, PyObject *kwargs) {
+ static void process_extra(const pybind11::arg_t<T> &a, int &index, int &kwarg_refs, PyObject *args, PyObject *kwargs) {
if (PyTuple_GET_ITEM(args, index) != nullptr) {
index++;
return;
@@ -158,6 +161,7 @@
if (kwargs)
value = PyDict_GetItemString(kwargs, a.name);
if (value) {
+ kwarg_refs++;
Py_INCREF(value);
} else {
value = detail::type_caster<typename detail::decay<T>::type>::cast(
@@ -185,9 +189,9 @@
m_entry->impl = [](function_entry *entry, PyObject *pyArgs, PyObject *kwargs, PyObject *parent) -> PyObject * {
capture *data = (capture *) entry->data;
- process_extras(data->extras, pyArgs, kwargs, entry->is_method);
+ int kwarg_refs = process_extras(data->extras, pyArgs, kwargs, entry->is_method);
cast_in args;
- if (!args.load(pyArgs, true))
+ if (kwarg_refs != (kwargs ? PyDict_Size(kwargs) : 0) || !args.load(pyArgs, true))
return (PyObject *) 1; /* Special return code: try next overload */
return cast_out::cast(args.template call<Return>(data->f), entry->policy, parent);
};
@@ -248,9 +252,9 @@
m_entry->impl = [](function_entry *entry, PyObject *pyArgs, PyObject *kwargs, PyObject *parent) -> PyObject *{
capture *data = (capture *) entry->data;
- process_extras(data->extras, pyArgs, kwargs, entry->is_method);
+ int kwarg_refs = process_extras(data->extras, pyArgs, kwargs, entry->is_method);
cast_in args;
- if (!args.load(pyArgs, true))
+ if (kwarg_refs != (kwargs ? PyDict_Size(kwargs) : 0) || !args.load(pyArgs, true))
return (PyObject *) 1; /* Special return code: try next overload */
return cast_out::cast(args.template call<Return>(data->f), entry->policy, parent);
};
diff --git a/include/pybind11/pytypes.h b/include/pybind11/pytypes.h
index 3c85f7a..8d84afa 100644
--- a/include/pybind11/pytypes.h
+++ b/include/pybind11/pytypes.h
@@ -59,6 +59,12 @@
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);
diff --git a/include/pybind11/stl.h b/include/pybind11/stl.h
index cee5be7..c4f4b19 100644
--- a/include/pybind11/stl.h
+++ b/include/pybind11/stl.h
@@ -43,17 +43,17 @@
}
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 @@
}
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 @@
}
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(">"));