From 37e22e436e012c18acedcce7229e9515cef0db45 Mon Sep 17 00:00:00 2001 From: Dean Moldovan Date: Thu, 8 Sep 2016 16:36:01 +0200 Subject: [PATCH] Move common object functions into object_api mixin --- include/pybind11/attr.h | 2 +- include/pybind11/cast.h | 16 +++-- include/pybind11/pytypes.h | 129 +++++++++++++++++++++++-------------- 3 files changed, 89 insertions(+), 58 deletions(-) diff --git a/include/pybind11/attr.h b/include/pybind11/attr.h index ba297355d..f37e8627e 100644 --- a/include/pybind11/attr.h +++ b/include/pybind11/attr.h @@ -276,7 +276,7 @@ template <> struct process_attribute : process_attribute_default { /// Process a parent class attribute template -struct process_attribute::value>> : process_attribute_default { +struct process_attribute::value>> : process_attribute_default { static void init(const handle &h, type_record *r) { r->bases.append(h); } }; diff --git a/include/pybind11/cast.h b/include/pybind11/cast.h index 780a02efc..1d9740d38 100644 --- a/include/pybind11/cast.h +++ b/include/pybind11/cast.h @@ -908,7 +908,7 @@ template <> struct handle_type_name { static PYBIND11_DESCR name() { retur template <> struct handle_type_name { static PYBIND11_DESCR name() { return _("**kwargs"); } }; template -struct type_caster::value>> { +struct type_caster::value>> { public: template ::value, int> = 0> bool load(handle src, bool /* convert */) { value = type(src); return value.check(); } @@ -1296,18 +1296,20 @@ unpacking_collector collect_arguments(Args &&...args) { return { std::forward(args)... }; } -NAMESPACE_END(detail) - +template template -object handle::operator()(Args &&...args) const { - return detail::collect_arguments(std::forward(args)...).call(m_ptr); +object object_api::operator()(Args &&...args) const { + return detail::collect_arguments(std::forward(args)...).call(derived().ptr()); } -template object handle::call(Args &&... args) const { +template +template +object object_api::call(Args &&...args) const { return operator()(std::forward(args)...); } +NAMESPACE_END(detail) + #define PYBIND11_MAKE_OPAQUE(Type) \ namespace pybind11 { namespace detail { \ template<> class type_caster : public type_caster_base { }; \ diff --git a/include/pybind11/pytypes.h b/include/pybind11/pytypes.h index 8681bbb12..872c90cc9 100644 --- a/include/pybind11/pytypes.h +++ b/include/pybind11/pytypes.h @@ -16,50 +16,72 @@ NAMESPACE_BEGIN(pybind11) /* A few forward declarations */ -class object; class str; class iterator; +class handle; class object; +class str; class iterator; struct arg; struct arg_v; -namespace detail { class accessor; class args_proxy; class kwargs_proxy; } + +NAMESPACE_BEGIN(detail) +class accessor; class args_proxy; + +/// Tag and check to identify a class which implements the Python object API +class pyobject_tag { }; +template using is_pyobject = std::is_base_of; + +/// Mixin which adds common functions to handle, object and various accessors. +/// The only requirement for `Derived` is to implement `PyObject *Derived::ptr() const`. +template +class object_api : public pyobject_tag { + const Derived &derived() const { return static_cast(*this); } + +public: + iterator begin() const; + iterator end() const; + accessor operator[](handle key) const; + accessor operator[](const char *key) const; + accessor attr(handle key) const; + accessor attr(const char *key) const; + args_proxy operator*() const; + + template + object operator()(Args &&...args) const; + template + PYBIND11_DEPRECATED("call(...) was deprecated in favor of operator()(...)") + object call(Args&&... args) const; + + bool is_none() const { return derived().ptr() == Py_None; } + pybind11::str str() const; + pybind11::str repr() const; + + int ref_count() const { return static_cast(Py_REFCNT(derived().ptr())); } + handle get_type() const; +}; + +NAMESPACE_END(detail) /// Holds a reference to a Python object (no reference counting) -class handle { +class handle : public detail::object_api { public: - handle() : m_ptr(nullptr) { } - handle(const handle &other) : m_ptr(other.m_ptr) { } + handle() = default; handle(PyObject *ptr) : m_ptr(ptr) { } + PyObject *ptr() const { return m_ptr; } PyObject *&ptr() { return m_ptr; } const handle& inc_ref() const { Py_XINCREF(m_ptr); return *this; } const handle& dec_ref() const { Py_XDECREF(m_ptr); return *this; } - int ref_count() const { return (int) Py_REFCNT(m_ptr); } - handle get_type() const { return handle((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; - inline pybind11::str repr() const; - bool is_none() const { return m_ptr == Py_None; } + template T cast() const; - template - PYBIND11_DEPRECATED("call(...) was deprecated in favor of operator()(...)") - object call(Args&&... args) const; - template - object operator()(Args&&... args) const; operator bool() const { return m_ptr != nullptr; } bool operator==(const handle &h) const { return m_ptr == h.m_ptr; } bool operator!=(const handle &h) const { return m_ptr != h.m_ptr; } bool check() const { return m_ptr != nullptr; } - inline detail::args_proxy operator*() const; protected: - PyObject *m_ptr; + PyObject *m_ptr = nullptr; }; /// Holds a reference to a Python object (with reference counting) class object : public handle { public: - object() { } + object() = default; object(const object &o) : handle(o) { inc_ref(); } object(const handle &h, bool borrowed) : handle(h) { if (borrowed) inc_ref(); } object(PyObject *ptr, bool borrowed) : handle(ptr) { if (borrowed) inc_ref(); } @@ -347,14 +369,6 @@ public: PYBIND11_OBJECT_DEFAULT(iterable, object, detail::PyIterable_Check) }; -inline detail::accessor handle::operator[](handle key) const { return detail::accessor(*this, key, false); } -inline detail::accessor handle::operator[](const char *key) const { return detail::accessor(*this, key, false); } -inline detail::accessor handle::attr(handle key) const { return detail::accessor(*this, key, true); } -inline detail::accessor handle::attr(const char *key) const { return detail::accessor(*this, key, true); } -inline iterator handle::begin() const { return iterator(PyObject_GetIter(ptr()), false); } -inline iterator handle::end() const { return iterator(nullptr, false); } -inline detail::args_proxy handle::operator*() const { return detail::args_proxy(*this); } - class bytes; class str : public object { @@ -400,24 +414,6 @@ inline namespace literals { inline str operator"" _s(const char *s, size_t size) { return {s, size}; } } -inline pybind11::str handle::str() const { - PyObject *strValue = PyObject_Str(m_ptr); -#if PY_MAJOR_VERSION < 3 - PyObject *unicode = PyUnicode_FromEncodedObject(strValue, "utf-8", nullptr); - Py_XDECREF(strValue); strValue = unicode; -#endif - return pybind11::str(strValue, false); -} - -inline pybind11::str handle::repr() const { - PyObject *strValue = PyObject_Repr(m_ptr); -#if PY_MAJOR_VERSION < 3 - PyObject *unicode = PyUnicode_FromEncodedObject(strValue, "utf-8", nullptr); - Py_XDECREF(strValue); strValue = unicode; -#endif - return pybind11::str(strValue, false); -} - class bytes : public object { public: PYBIND11_OBJECT_DEFAULT(bytes, object, PYBIND11_BYTES_CHECK) @@ -691,4 +687,37 @@ inline size_t len(handle h) { return (size_t) result; } +NAMESPACE_BEGIN(detail) +template iterator object_api::begin() const { return {PyObject_GetIter(derived().ptr()), false}; } +template iterator object_api::end() const { return {nullptr, false}; } +template accessor object_api::operator[](handle key) const { return {derived(), key, false}; } +template accessor object_api::operator[](const char *key) const { return {derived(), key, false}; } +template accessor object_api::attr(handle key) const { return {derived(), key, true}; } +template accessor object_api::attr(const char *key) const { return {derived(), key, true}; } +template args_proxy object_api::operator*() const { return {derived().ptr()}; } + +template +pybind11::str object_api::str() const { + PyObject *str_value = PyObject_Str(derived().ptr()); +#if PY_MAJOR_VERSION < 3 + PyObject *unicode = PyUnicode_FromEncodedObject(str_value, "utf-8", nullptr); + Py_XDECREF(str_value); str_value = unicode; +#endif + return {str_value, false}; +} + +template +pybind11::str object_api::repr() const { + PyObject *str_value = PyObject_Repr(derived().ptr()); +#if PY_MAJOR_VERSION < 3 + PyObject *unicode = PyUnicode_FromEncodedObject(str_value, "utf-8", nullptr); + Py_XDECREF(str_value); str_value = unicode; +#endif + return {str_value, false}; +} + +template +handle object_api::get_type() const { return (PyObject *) Py_TYPE(derived().ptr()); } + +NAMESPACE_END(detail) NAMESPACE_END(pybind11)