From 875df5528dd9e71bd3d3ea982ca16d1e30c420bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Mi=C4=85sko?= Date: Mon, 28 Dec 2015 08:11:16 +0100 Subject: [PATCH] Make handle and related classes const correct. This gives handle classes a typical pointer semantics with respects to constness. --- docs/reference.rst | 22 ++++++++-------- include/pybind11/cast.h | 2 +- include/pybind11/numpy.h | 2 +- include/pybind11/pytypes.h | 52 ++++++++++++++++++-------------------- 4 files changed, 38 insertions(+), 40 deletions(-) diff --git a/docs/reference.rst b/docs/reference.rst index bf7a8e276..2af84dae1 100644 --- a/docs/reference.rst +++ b/docs/reference.rst @@ -59,31 +59,31 @@ 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`. -.. function:: void handle::inc_ref() +.. function:: void handle::inc_ref() const Manually increase the reference count of the Python object. Usually, it is preferable to use the :class:`object` class which derives from :class:`handle` and calls this function automatically. -.. function:: void handle::dec_ref() +.. function:: void handle::dec_ref() const Manually decrease the reference count of the Python object. Usually, it is preferable to use the :class:`object` class which derives from :class:`handle` and calls this function automatically. -.. function:: void handle::ref_count() +.. function:: void handle::ref_count() const Return the object's current reference count -.. function:: handle handle::get_type() +.. function:: handle handle::get_type() const Return a handle to the Python type object underlying the instance -.. function detail::accessor handle::operator[](handle key) +.. function detail::accessor handle::operator[](handle key) const Return an internal functor to invoke the object's sequence protocol. Casting the returned ``detail::accessor`` instance to a :class:`handle` or @@ -91,12 +91,12 @@ Without reference counting Assigning a :class:`handle` or :class:`object` subclass causes a call to ``__setitem__``. -.. function detail::accessor handle::operator[](const char *key) +.. function detail::accessor handle::operator[](const char *key) const See the above function (the only difference is that they key is provided as a string literal). -.. function detail::accessor handle::attr(handle key) +.. function detail::accessor handle::attr(handle key) const Return an internal functor to access the object's attributes. Casting the returned ``detail::accessor`` instance to a :class:`handle` or @@ -104,7 +104,7 @@ Without reference counting Assigning a :class:`handle` or :class:`object` subclass causes a call to ``__setattr``. -.. function detail::accessor handle::attr(const char *key) +.. function detail::accessor handle::attr(const char *key) const See the above function (the only difference is that they key is provided as a string literal). @@ -123,7 +123,7 @@ Without reference counting Attempt to cast the Python object into the given C++ type. A :class:`cast_error` will be throw upon failure. -.. function:: template object handle::call(Args&&... args) +.. function:: template object handle::call(Args&&... args) const Assuming the Python object is a function or implements the ``__call__`` protocol, ``call()`` invokes the underlying function, passing an arbitrary @@ -169,7 +169,7 @@ With reference counting .. function:: object::~object() - Constructor, which automatically calls :func:`handle::dec_ref()`. + Destructor, which automatically calls :func:`handle::dec_ref()`. Convenience classes for specific Python types ============================================= diff --git a/include/pybind11/cast.h b/include/pybind11/cast.h index ecbf3843e..54ef8c70d 100644 --- a/include/pybind11/cast.h +++ b/include/pybind11/cast.h @@ -597,7 +597,7 @@ template inline object cast(const T &value, return_value_policy pol template inline T handle::cast() const { return pybind11::cast(m_ptr); } template <> inline void handle::cast() const { return; } -template inline object handle::call(Args&&... args_) { +template inline object handle::call(Args&&... args_) const { const size_t size = sizeof...(Args); std::array args{ { detail::type_caster::type>::cast( diff --git a/include/pybind11/numpy.h b/include/pybind11/numpy.h index d1196e074..add52decd 100644 --- a/include/pybind11/numpy.h +++ b/include/pybind11/numpy.h @@ -129,7 +129,7 @@ public: PYBIND11_OBJECT_CVT(array_t, array, is_non_null, m_ptr = ensure(m_ptr)); array_t() : array() { } static bool is_non_null(PyObject *ptr) { return ptr != nullptr; } - PyObject *ensure(PyObject *ptr) { + static PyObject *ensure(PyObject *ptr) { if (ptr == nullptr) return nullptr; API &api = lookup_api(); diff --git a/include/pybind11/pytypes.h b/include/pybind11/pytypes.h index c0bb47b0b..3c85f7a9a 100644 --- a/include/pybind11/pytypes.h +++ b/include/pybind11/pytypes.h @@ -29,21 +29,20 @@ 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); } - handle get_type() { return (PyObject *) Py_TYPE(m_ptr); } - inline iterator begin(); - inline iterator end(); - inline detail::accessor operator[](handle key); - inline detail::accessor operator[](const char *key); - inline detail::accessor attr(handle key); - inline detail::accessor attr(const char *key); + handle get_type() const { return (PyObject *) Py_TYPE(m_ptr); } + inline iterator begin() const; + inline iterator end() const; + inline detail::accessor operator[](handle key) const; + inline detail::accessor operator[](const char *key) const; + inline detail::accessor attr(handle key) const; + inline detail::accessor attr(const char *key) const; inline pybind11::str str() const; template T cast() const; - template object call(Args&&... args_); + template object call(Args&&... args_) const; operator bool() const { return m_ptr != nullptr; } bool check() const { return m_ptr != nullptr; } protected: @@ -88,7 +87,6 @@ public: } bool operator==(const iterator &it) const { return *it == **this; } bool operator!=(const iterator &it) const { return *it != **this; } - object operator*() { return value; } const object &operator*() const { return value; } bool check() const { return PyIter_Check(ptr()); } private: @@ -201,7 +199,7 @@ public: pos = -1; return *this; } - std::pair operator*() { + std::pair operator*() const { return std::make_pair(object(key, true), object(value, true)); } bool operator==(const dict_iterator &it) const { return it.pos == pos; } @@ -237,12 +235,12 @@ inline bool PyLong_Check_(PyObject *o) { NAMESPACE_END(detail) -inline detail::accessor handle::operator[](handle key) { return detail::accessor(ptr(), key.ptr(), false); } -inline detail::accessor handle::operator[](const char *key) { return detail::accessor(ptr(), key, false); } -inline detail::accessor handle::attr(handle key) { return detail::accessor(ptr(), key.ptr(), true); } -inline detail::accessor handle::attr(const char *key) { return detail::accessor(ptr(), key, true); } -inline iterator handle::begin() { return iterator(PyObject_GetIter(ptr())); } -inline iterator handle::end() { return iterator(nullptr); } +inline detail::accessor handle::operator[](handle key) const { return detail::accessor(ptr(), key.ptr(), false); } +inline detail::accessor handle::operator[](const char *key) const { return detail::accessor(ptr(), key, false); } +inline detail::accessor handle::attr(handle key) const { return detail::accessor(ptr(), key.ptr(), true); } +inline detail::accessor handle::attr(const char *key) const { return detail::accessor(ptr(), key, true); } +inline iterator handle::begin() const { return iterator(PyObject_GetIter(ptr())); } +inline iterator handle::end() const { return iterator(nullptr); } #define PYBIND11_OBJECT_CVT(Name, Parent, CheckFun, CvtStmt) \ Name(const handle &h, bool borrowed) : Parent(h, borrowed) { CvtStmt; } \ @@ -375,7 +373,7 @@ public: PYBIND11_OBJECT(tuple, object, PyTuple_Check) tuple(size_t size = 0) : object(PyTuple_New((Py_ssize_t) size), false) { } size_t size() const { return (size_t) PyTuple_Size(m_ptr); } - detail::tuple_accessor operator[](size_t index) { return detail::tuple_accessor(ptr(), index); } + detail::tuple_accessor operator[](size_t index) const { return detail::tuple_accessor(ptr(), index); } }; class dict : public object { @@ -383,9 +381,9 @@ public: PYBIND11_OBJECT(dict, object, PyDict_Check) dict() : object(PyDict_New(), false) { } size_t size() const { return (size_t) PyDict_Size(m_ptr); } - detail::dict_iterator begin() { return (++detail::dict_iterator(ptr(), 0)); } - detail::dict_iterator end() { return detail::dict_iterator(); } - void clear() { PyDict_Clear(ptr()); } + detail::dict_iterator begin() const { return (++detail::dict_iterator(ptr(), 0)); } + detail::dict_iterator end() const { return detail::dict_iterator(); } + void clear() const { PyDict_Clear(ptr()); } }; class list : public object { @@ -393,8 +391,8 @@ public: PYBIND11_OBJECT(list, object, PyList_Check) list(size_t size = 0) : object(PyList_New((ssize_t) size), false) { } size_t size() const { return (size_t) PyList_Size(m_ptr); } - detail::list_accessor operator[](size_t index) { return detail::list_accessor(ptr(), index); } - void append(const object &object) { PyList_Append(m_ptr, (PyObject *) object.ptr()); } + detail::list_accessor operator[](size_t index) const { return detail::list_accessor(ptr(), index); } + void append(const object &object) const { PyList_Append(m_ptr, (PyObject *) object.ptr()); } }; class set : public object { @@ -402,15 +400,15 @@ public: PYBIND11_OBJECT(set, object, PySet_Check) set() : object(PySet_New(nullptr), false) { } size_t size() const { return (size_t) PySet_Size(m_ptr); } - void add(const object &object) { PySet_Add(m_ptr, (PyObject *) object.ptr()); } - void clear() { PySet_Clear(ptr()); } + void add(const object &object) const { PySet_Add(m_ptr, (PyObject *) object.ptr()); } + void clear() const { PySet_Clear(ptr()); } }; class function : public object { public: PYBIND11_OBJECT_DEFAULT(function, object, PyFunction_Check) - bool is_cpp_function() { + bool is_cpp_function() const { PyObject *ptr = detail::get_function(m_ptr); return ptr != nullptr && PyCFunction_Check(ptr); }