Move common object functions into object_api mixin

This commit is contained in:
Dean Moldovan 2016-09-08 16:36:01 +02:00
parent 2d9220f09d
commit 37e22e436e
3 changed files with 89 additions and 58 deletions

View File

@ -276,7 +276,7 @@ template <> struct process_attribute<arg_v> : process_attribute_default<arg_v> {
/// Process a parent class attribute
template <typename T>
struct process_attribute<T, enable_if_t<std::is_base_of<handle, T>::value>> : process_attribute_default<handle> {
struct process_attribute<T, enable_if_t<is_pyobject<T>::value>> : process_attribute_default<handle> {
static void init(const handle &h, type_record *r) { r->bases.append(h); }
};

View File

@ -908,7 +908,7 @@ template <> struct handle_type_name<args> { static PYBIND11_DESCR name() { retur
template <> struct handle_type_name<kwargs> { static PYBIND11_DESCR name() { return _("**kwargs"); } };
template <typename type>
struct type_caster<type, enable_if_t<std::is_base_of<handle, type>::value>> {
struct type_caster<type, enable_if_t<is_pyobject<type>::value>> {
public:
template <typename T = type, enable_if_t<!std::is_base_of<object, T>::value, int> = 0>
bool load(handle src, bool /* convert */) { value = type(src); return value.check(); }
@ -1296,18 +1296,20 @@ unpacking_collector<policy> collect_arguments(Args &&...args) {
return { std::forward<Args>(args)... };
}
NAMESPACE_END(detail)
template <typename Derived>
template <return_value_policy policy, typename... Args>
object handle::operator()(Args &&...args) const {
return detail::collect_arguments<policy>(std::forward<Args>(args)...).call(m_ptr);
object object_api<Derived>::operator()(Args &&...args) const {
return detail::collect_arguments<policy>(std::forward<Args>(args)...).call(derived().ptr());
}
template <return_value_policy policy,
typename... Args> object handle::call(Args &&... args) const {
template <typename Derived>
template <return_value_policy policy, typename... Args>
object object_api<Derived>::call(Args &&...args) const {
return operator()<policy>(std::forward<Args>(args)...);
}
NAMESPACE_END(detail)
#define PYBIND11_MAKE_OPAQUE(Type) \
namespace pybind11 { namespace detail { \
template<> class type_caster<Type> : public type_caster_base<Type> { }; \

View File

@ -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 <typename T> using is_pyobject = std::is_base_of<pyobject_tag, T>;
/// Mixin which adds common functions to handle, object and various accessors.
/// The only requirement for `Derived` is to implement `PyObject *Derived::ptr() const`.
template <typename Derived>
class object_api : public pyobject_tag {
const Derived &derived() const { return static_cast<const Derived &>(*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 <return_value_policy policy = return_value_policy::automatic_reference, typename... Args>
object operator()(Args &&...args) const;
template <return_value_policy policy = return_value_policy::automatic_reference, typename... Args>
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<int>(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<handle> {
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 <typename T> T cast() const;
template <return_value_policy policy = return_value_policy::automatic_reference, typename ... Args>
PYBIND11_DEPRECATED("call(...) was deprecated in favor of operator()(...)")
object call(Args&&... args) const;
template <return_value_policy policy = return_value_policy::automatic_reference, typename ... Args>
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 <typename D> iterator object_api<D>::begin() const { return {PyObject_GetIter(derived().ptr()), false}; }
template <typename D> iterator object_api<D>::end() const { return {nullptr, false}; }
template <typename D> accessor object_api<D>::operator[](handle key) const { return {derived(), key, false}; }
template <typename D> accessor object_api<D>::operator[](const char *key) const { return {derived(), key, false}; }
template <typename D> accessor object_api<D>::attr(handle key) const { return {derived(), key, true}; }
template <typename D> accessor object_api<D>::attr(const char *key) const { return {derived(), key, true}; }
template <typename D> args_proxy object_api<D>::operator*() const { return {derived().ptr()}; }
template <typename D>
pybind11::str object_api<D>::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 <typename D>
pybind11::str object_api<D>::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 <typename D>
handle object_api<D>::get_type() const { return (PyObject *) Py_TYPE(derived().ptr()); }
NAMESPACE_END(detail)
NAMESPACE_END(pybind11)