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(">"));