From 60c36db1c95438009f0f3fb2ec2281bdbc11bbba Mon Sep 17 00:00:00 2001 From: Wenzel Jakob Date: Mon, 30 Nov 2015 12:30:28 +0100 Subject: [PATCH] generic integer type handling --- example/example11.ref | 20 +++---- example/example2.ref | 96 ++++++++++++++++----------------- include/pybind11/cast.h | 107 +++++++++++++++++++++++-------------- include/pybind11/pytypes.h | 65 ++++++++++++---------- 4 files changed, 161 insertions(+), 127 deletions(-) diff --git a/example/example11.ref b/example/example11.ref index cfcfe419..728e804d 100644 --- a/example/example11.ref +++ b/example/example11.ref @@ -1,13 +1,3 @@ -Help on built-in function kw_func - -kkww__ffuunncc(...) - Signature : (x : int32_t, y : int32_t) -> None - -Help on built-in function kw_func2 - -kkww__ffuunncc22(...) - Signature : (x : int32_t = 100, y : int32_t = 200) -> None - kw_func(x=5, y=10) kw_func(x=5, y=10) kw_func(x=5, y=10) @@ -17,3 +7,13 @@ kw_func(x=5, y=200) kw_func(x=100, y=10) kw_func(x=5, y=10) kw_func(x=5, y=10) +Help on built-in function kw_func + +kkww__ffuunncc(...) method of builtins.PyCapsule instance + Signature : (x : int, y : int) -> None + +Help on built-in function kw_func2 + +kkww__ffuunncc22(...) method of builtins.PyCapsule instance + Signature : (x : int = 100, y : int = 200) -> None + diff --git a/example/example2.ref b/example/example2.ref index 64d2afa8..a63c3cd8 100644 --- a/example/example2.ref +++ b/example/example2.ref @@ -1,14 +1,10 @@ -15 -5 -Example2: No constructor defined! -can't set attribute -key: key2, value=value2 key: key, value=value +key: key2, value=value2 key: key, value=value key: key2, value=value2 key: key3 -key: key2 key: key1 +key: key2 key: key1 key: key2 key: key3 @@ -17,105 +13,107 @@ list item 0: overwritten list item 1: value2 list item 0: value list item 1: value2 +15 +5 +example.Example2: No constructor defined! +can't set attribute This exception was intentionally thrown. -(u'test', True) -(5L, u'test', True) +('test', True) +(5, 'test', True) Help on class Example2 in module example -class EExxaammppllee22(__builtin__.object) +class EExxaammppllee22(builtins.object) | Example 2 documentation | | Methods defined here: | - | ____iinniitt____(...) - | x.__init__(...) initializes x; see help(type(x)) for signature + | ____iinniitt____(self, /, *args, **kwargs) + | Initialize self. See help(type(self)) for accurate signature. | - | ggeett__ddiicctt(...) - | Signature : (Example2) -> dict + | ____nneeww____ = + | ggeett__ddiicctt(...) from builtins.PyCapsule + | Signature : (example.Example2) -> dict | | Return a Python dictionary | - | ggeett__ddiicctt__22(...) - | Signature : (Example2) -> dict + | ggeett__ddiicctt__22(...) from builtins.PyCapsule + | Signature : (example.Example2) -> dict | | Return a C++ dictionary | - | ggeett__lliisstt(...) - | Signature : (Example2) -> list + | ggeett__lliisstt(...) from builtins.PyCapsule + | Signature : (example.Example2) -> list | | Return a Python list | - | ggeett__lliisstt__22(...) - | Signature : (Example2) -> list + | ggeett__lliisstt__22(...) from builtins.PyCapsule + | Signature : (example.Example2) -> list | | Return a C++ list | - | ggeett__sseett(...) - | Signature : (Example2) -> set + | ggeett__sseett(...) from builtins.PyCapsule + | Signature : (example.Example2) -> set | | Return a Python set | - | ggeett__sseett22(...) - | Signature : (Example2) -> set + | ggeett__sseett22(...) from builtins.PyCapsule + | Signature : (example.Example2) -> set | | Return a C++ set | - | ppaaiirr__ppaasssstthhrroouugghh(...) - | Signature : (Example2, (bool, str)) -> (str, bool) + | nneeww__iinnssttaannccee(...) from builtins.PyCapsule + | Signature : () -> example.Example2 + | + | Return an instance + | + | ppaaiirr__ppaasssstthhrroouugghh(...) from builtins.PyCapsule + | Signature : (example.Example2, (bool, str)) -> (str, bool) | | Return a pair in reversed order | - | pprriinntt__ddiicctt(...) - | Signature : (Example2, dict) -> None + | pprriinntt__ddiicctt(...) from builtins.PyCapsule + | Signature : (example.Example2, dict) -> None | | Print entries of a Python dictionary | - | pprriinntt__ddiicctt__22(...) - | Signature : (Example2, dict) -> None + | pprriinntt__ddiicctt__22(...) from builtins.PyCapsule + | Signature : (example.Example2, dict) -> None | | Print entries of a C++ dictionary | - | pprriinntt__lliisstt(...) - | Signature : (Example2, list) -> None + | pprriinntt__lliisstt(...) from builtins.PyCapsule + | Signature : (example.Example2, list) -> None | | Print entries of a Python list | - | pprriinntt__lliisstt__22(...) - | Signature : (Example2, list) -> None + | pprriinntt__lliisstt__22(...) from builtins.PyCapsule + | Signature : (example.Example2, list) -> None | | Print entries of a C++ list | - | pprriinntt__sseett(...) - | Signature : (Example2, set) -> None + | pprriinntt__sseett(...) from builtins.PyCapsule + | Signature : (example.Example2, set) -> None | | Print entries of a Python set | - | pprriinntt__sseett__22(...) - | Signature : (Example2, set) -> None + | pprriinntt__sseett__22(...) from builtins.PyCapsule + | Signature : (example.Example2, set) -> None | | Print entries of a C++ set | - | tthhrrooww__eexxcceeppttiioonn(...) - | Signature : (Example2) -> None + | tthhrrooww__eexxcceeppttiioonn(...) from builtins.PyCapsule + | Signature : (example.Example2) -> None | | Throw an exception | - | ttuuppllee__ppaasssstthhrroouugghh(...) - | Signature : (Example2, (bool, str, int32_t)) -> (int32_t, str, bool) + | ttuuppllee__ppaasssstthhrroouugghh(...) from builtins.PyCapsule + | Signature : (example.Example2, (bool, str, int)) -> (int, str, bool) | | Return a triple in reversed order | | ---------------------------------------------------------------------- | Data and other attributes defined here: | - | ____nneeww____ = - | T.__new__(S, ...) -> a new object with type S, a subtype of T - | | ____ppyybbiinndd1111____ = - | - | nneeww__iinnssttaannccee = - | Signature : () -> Example2 - | - | Return an instance Destructing Example2 diff --git a/include/pybind11/cast.h b/include/pybind11/cast.h index 1ed61460..0c7da1ab 100644 --- a/include/pybind11/cast.h +++ b/include/pybind11/cast.h @@ -191,7 +191,7 @@ protected: }; /// Generic type caster for objects stored on the heap -template class type_caster : public type_caster_custom { +template class type_caster : public type_caster_custom { public: static descr name() { return typeid(type); } @@ -229,49 +229,74 @@ protected: operator type*() { return &value; } \ operator type&() { return value; } -#define PYBIND11_TYPE_CASTER_NUMBER(type, py_type, from_type, to_pytype) \ - template <> class type_caster { \ - public: \ - bool load(PyObject *src, bool) { \ - py_type py_value = from_type(src); \ - if ((py_value == (py_type) -1 && PyErr_Occurred()) || \ - (std::numeric_limits::is_integer && \ - sizeof(py_type) != sizeof(type) && \ - (py_value < (py_type) std::numeric_limits::min() || \ - py_value > (py_type) std::numeric_limits::max()))) { \ - PyErr_Clear(); \ - return false; \ - } \ - value = (type) py_value; \ - return true; \ - } \ - static PyObject *cast(type src, return_value_policy /* policy */, PyObject * /* parent */) { \ - return to_pytype((py_type) src); \ - } \ - PYBIND11_TYPE_CASTER(type, #type); \ - }; +template +struct type_caster< + T, typename std::enable_if::value || + std::is_floating_point::value>::type> { + typedef typename std::conditional::type _py_type_0; + typedef typename std::conditional::value, _py_type_0, typename std::make_unsigned<_py_type_0>::type>::type _py_type_1; + typedef typename std::conditional::value, double, _py_type_1>::type py_type; +public: -PYBIND11_TYPE_CASTER_NUMBER(int8_t, long, PyLong_AsLong, PyLong_FromLong) -PYBIND11_TYPE_CASTER_NUMBER(uint8_t, unsigned long, PyLong_AsUnsignedLong, PyLong_FromUnsignedLong) -PYBIND11_TYPE_CASTER_NUMBER(int16_t, long, PyLong_AsLong, PyLong_FromLong) -PYBIND11_TYPE_CASTER_NUMBER(uint16_t, unsigned long, PyLong_AsUnsignedLong, PyLong_FromUnsignedLong) -PYBIND11_TYPE_CASTER_NUMBER(int32_t, long, PyLong_AsLong, PyLong_FromLong) -PYBIND11_TYPE_CASTER_NUMBER(uint32_t, unsigned long, PyLong_AsUnsignedLong, PyLong_FromUnsignedLong) -PYBIND11_TYPE_CASTER_NUMBER(int64_t, PY_LONG_LONG, detail::PyLong_AsLongLong, PyLong_FromLongLong) -PYBIND11_TYPE_CASTER_NUMBER(uint64_t, unsigned PY_LONG_LONG, detail::PyLong_AsUnsignedLongLong, PyLong_FromUnsignedLongLong) + bool load(PyObject *src, bool) { + py_type py_value; -#if defined(__APPLE__) // size_t/ssize_t are separate types on Mac OS X -#if PY_MAJOR_VERSION >= 3 -PYBIND11_TYPE_CASTER_NUMBER(ssize_t, Py_ssize_t, PyLong_AsSsize_t, PyLong_FromSsize_t) -PYBIND11_TYPE_CASTER_NUMBER(size_t, size_t, PyLong_AsSize_t, PyLong_FromSize_t) -#else -PYBIND11_TYPE_CASTER_NUMBER(ssize_t, PY_LONG_LONG, detail::PyLong_AsLongLong, PyLong_FromLongLong) -PYBIND11_TYPE_CASTER_NUMBER(size_t, unsigned PY_LONG_LONG, detail::PyLong_AsUnsignedLongLong, PyLong_FromUnsignedLongLong) -#endif -#endif + if (std::is_floating_point::value) { + py_value = (py_type) PyFloat_AsDouble(src); + } else if (sizeof(T) <= sizeof(long)) { + if (std::is_signed::value) + py_value = (py_type) PyLong_AsLong(src); + else + py_value = (py_type) PyLong_AsUnsignedLong(src); + } else { + if (std::is_signed::value) + py_value = (py_type) detail::PyLong_AsLongLong(src); + else + py_value = (py_type) detail::PyLong_AsUnsignedLongLong(src); + } -PYBIND11_TYPE_CASTER_NUMBER(float, double, PyFloat_AsDouble, PyFloat_FromDouble) -PYBIND11_TYPE_CASTER_NUMBER(double, double, PyFloat_AsDouble, PyFloat_FromDouble) + if ((py_value == (py_type) -1 && PyErr_Occurred()) || + (std::is_integral::value && sizeof(py_type) != sizeof(T) && + (py_value < (py_type) std::numeric_limits::min() || + py_value > (py_type) std::numeric_limits::max()))) { + PyErr_Clear(); + return false; + } + + value = (T) py_value; + return true; + } + + static PyObject *cast(T src, return_value_policy /* policy */, PyObject * /* parent */) { + if (std::is_floating_point::value) { + return PyFloat_FromDouble((double) src); + } else if (sizeof(T) <= sizeof(long)) { + if (std::is_signed::value) + return PyLong_FromLong((long) src); + else + return PyLong_FromUnsignedLong((unsigned long) src); + } else { + if (std::is_signed::value) + return PyLong_FromLongLong((long long) src); + else + return PyLong_FromUnsignedLongLong((unsigned long long) src); + } + } + + static PyObject *cast(const T *src, return_value_policy policy, PyObject *parent) { + return cast(*src, policy, parent); + } + + static descr name() { + return std::is_floating_point::value ? "float" : "int"; + } + + operator T*() { return &value; } + operator T&() { return value; } + +protected: + T value; +}; template <> class type_caster { public: diff --git a/include/pybind11/pytypes.h b/include/pybind11/pytypes.h index 12dc7737..b7f42dc4 100644 --- a/include/pybind11/pytypes.h +++ b/include/pybind11/pytypes.h @@ -11,6 +11,7 @@ #include "common.h" #include +#include NAMESPACE_BEGIN(pybind11) @@ -213,16 +214,16 @@ private: using ::PyLong_AsUnsignedLongLong; using ::PyLong_AsLongLong; #else -inline PY_LONG_LONG PyLong_AsLongLong(PyObject *o) { - if (PyInt_Check(o)) - return (PY_LONG_LONG) PyLong_AsLong(o); +inline long long PyLong_AsLongLong(PyObject *o) { + if (PyInt_Check(o)) /// workaround: PyLong_AsLongLong doesn't accept 'int' on Python 2.x + return (long long) PyLong_AsLong(o); else return ::PyLong_AsLongLong(o); } -inline unsigned PY_LONG_LONG PyLong_AsUnsignedLongLong(PyObject *o) { - if (PyInt_Check(o)) - return (unsigned PY_LONG_LONG) PyLong_AsUnsignedLong(o); +inline unsigned long long PyLong_AsUnsignedLongLong(PyObject *o) { + if (PyInt_Check(o)) /// workaround: PyLong_AsUnsignedLongLong doesn't accept 'int' on Python 2.x + return (unsigned long long) PyLong_AsUnsignedLong(o); else return ::PyLong_AsUnsignedLongLong(o); } @@ -291,27 +292,37 @@ public: class int_ : public object { public: PYBIND11_OBJECT_DEFAULT(int_, object, PyLong_Check) - int_(int32_t value) : object(PyLong_FromLong((long) value), false) { } - int_(int64_t value) : object(PyLong_FromLongLong((long long) value), false) { } - int_(uint32_t value) : object(PyLong_FromUnsignedLong((unsigned long) value), false) { } - int_(uint64_t value) : object(PyLong_FromUnsignedLongLong((unsigned long long) value), false) { } - operator int32_t() const { return (int32_t) PyLong_AsLong(m_ptr); } - operator uint32_t() const { return (uint32_t) PyLong_AsUnsignedLong(m_ptr); } - operator int64_t() const { return (int64_t) detail::PyLong_AsLongLong(m_ptr); } - operator uint64_t() const { return (uint64_t) detail::PyLong_AsUnsignedLongLong(m_ptr); } -#if defined(__APPLE__) // size_t/ssize_t are separate types on Mac OS X -#if PY_MAJOR_VERSION >= 3 - int_(size_t value) : object(PyLong_FromSize_t(value), false) { } - int_(ssize_t value) : object(PyLong_FromSsize_t(value), false) { } - operator size_t() const { return (size_t) PyLong_AsSize_t(m_ptr); } - operator ssize_t() const { return (ssize_t) PyLong_AsSsize_t(m_ptr); } -#else - int_(size_t value) : object(PyLong_FromUnsignedLongLong((unsigned long long) value), false) { } - int_(ssize_t value) : object(PyLong_FromLongLong((long long) value), false) { } - operator size_t() const { return (size_t) detail::PyLong_AsUnsignedLongLong(m_ptr); } - operator ssize_t() const { return (ssize_t) detail::PyLong_AsLongLong(m_ptr); } -#endif -#endif + template ::value, int>::type = 0> + int_(T value) { + if (sizeof(T) <= sizeof(long)) { + if (std::is_signed::value) + m_ptr = PyLong_FromLong((long) value); + else + m_ptr = PyLong_FromUnsignedLong((unsigned long) value); + } else { + if (std::is_signed::value) + m_ptr = PyLong_FromLongLong((long long) value); + else + m_ptr = PyLong_FromUnsignedLongLong((unsigned long long) value); + } + } + + template ::value, int>::type = 0> + operator T() const { + if (sizeof(T) <= sizeof(long)) { + if (std::is_signed::value) + return (T) PyLong_AsLong(m_ptr); + else + return (T) PyLong_AsUnsignedLong(m_ptr); + } else { + if (std::is_signed::value) + return (T) detail::PyLong_AsLongLong(m_ptr); + else + return (T) detail::PyLong_AsUnsignedLongLong(m_ptr); + } + } }; class float_ : public object {