diff --git a/docs/advanced.rst b/docs/advanced.rst index e8ce71f1..ec09534d 100644 --- a/docs/advanced.rst +++ b/docs/advanced.rst @@ -825,12 +825,12 @@ completely avoid copy operations with Python expressions like py::class_(m, "Matrix") .def_buffer([](Matrix &m) -> py::buffer_info { return py::buffer_info( - m.data(), /* Pointer to buffer */ - sizeof(float), /* Size of one scalar */ - py::format_descriptor::value(), /* Python struct-style format descriptor */ - 2, /* Number of dimensions */ - { m.rows(), m.cols() }, /* Buffer dimensions */ - { sizeof(float) * m.rows(), /* Strides (in bytes) for each index */ + m.data(), /* Pointer to buffer */ + sizeof(float), /* Size of one scalar */ + py::format_descriptor::value, /* Python struct-style format descriptor */ + 2, /* Number of dimensions */ + { m.rows(), m.cols() }, /* Buffer dimensions */ + { sizeof(float) * m.rows(), /* Strides (in bytes) for each index */ sizeof(float) } ); }); @@ -867,7 +867,7 @@ objects (e.g. a NumPy matrix). py::buffer_info info = b.request(); /* Some sanity checks ... */ - if (info.format != py::format_descriptor::value()) + if (info.format != py::format_descriptor::value) throw std::runtime_error("Incompatible format: expected a double array!"); if (info.ndim != 2) @@ -994,7 +994,7 @@ simply using ``vectorize``). auto result = py::array(py::buffer_info( nullptr, /* Pointer to data (nullptr -> ask NumPy to allocate!) */ sizeof(double), /* Size of one item */ - py::format_descriptor::value(), /* Buffer format */ + py::format_descriptor::value, /* Buffer format */ buf1.ndim, /* How many dimensions? */ { buf1.shape[0] }, /* Number of elements for each dimension */ { sizeof(double) } /* Strides for each dimension */ diff --git a/example/example7.cpp b/example/example7.cpp index 415b0978..6aabf1c1 100644 --- a/example/example7.cpp +++ b/example/example7.cpp @@ -80,7 +80,7 @@ void init_ex7(py::module &m) { /// Construct from a buffer .def("__init__", [](Matrix &v, py::buffer b) { py::buffer_info info = b.request(); - if (info.format != py::format_descriptor::value() || info.ndim != 2) + if (info.format != py::format_descriptor::value || info.ndim != 2) throw std::runtime_error("Incompatible buffer format!"); new (&v) Matrix(info.shape[0], info.shape[1]); memcpy(v.data(), info.ptr, sizeof(float) * v.rows() * v.cols()); @@ -103,12 +103,12 @@ void init_ex7(py::module &m) { /// Provide buffer access .def_buffer([](Matrix &m) -> py::buffer_info { return py::buffer_info( - m.data(), /* Pointer to buffer */ - sizeof(float), /* Size of one scalar */ - py::format_descriptor::value(), /* Python struct-style format descriptor */ - 2, /* Number of dimensions */ - { m.rows(), m.cols() }, /* Buffer dimensions */ - { sizeof(float) * m.rows(), /* Strides (in bytes) for each index */ + m.data(), /* Pointer to buffer */ + sizeof(float), /* Size of one scalar */ + py::format_descriptor::value, /* Python struct-style format descriptor */ + 2, /* Number of dimensions */ + { m.rows(), m.cols() }, /* Buffer dimensions */ + { sizeof(float) * m.rows(), /* Strides (in bytes) for each index */ sizeof(float) } ); }); diff --git a/include/pybind11/common.h b/include/pybind11/common.h index abf764af..1ca0d1db 100644 --- a/include/pybind11/common.h +++ b/include/pybind11/common.h @@ -191,13 +191,6 @@ enum class return_value_policy : int { reference_internal }; -/// Format strings for basic number types -template struct format_descriptor { }; -#define PYBIND11_DECL_FMT(t, n) template<> struct format_descriptor { static std::string value() { return n; }; } -PYBIND11_DECL_FMT(int8_t, "b"); PYBIND11_DECL_FMT(uint8_t, "B"); PYBIND11_DECL_FMT(int16_t, "h"); PYBIND11_DECL_FMT(uint16_t, "H"); -PYBIND11_DECL_FMT(int32_t, "i"); PYBIND11_DECL_FMT(uint32_t, "I"); PYBIND11_DECL_FMT(int64_t, "q"); PYBIND11_DECL_FMT(uint64_t, "Q"); -PYBIND11_DECL_FMT(float, "f"); PYBIND11_DECL_FMT(double, "d"); PYBIND11_DECL_FMT(bool, "?"); - /// Information record describing a Python buffer object struct buffer_info { void *ptr; // Pointer to the underlying storage @@ -234,6 +227,8 @@ private: NAMESPACE_BEGIN(detail) +static constexpr int log2(size_t n, int k = 0) { return (n <= 1) ? k : log2(n >> 1, k + 1); } + inline std::string error_string(); /// Core part of the 'instance' type which POD (needed to be able to use 'offsetof') @@ -296,13 +291,6 @@ template struct intrinsic_type { typedef type /// Helper type to replace 'void' in some expressions struct void_type { }; -/// to_string variant which also accepts strings -template inline typename std::enable_if::value, std::string>::type -to_string(const T &value) { return std::to_string(value); } -template <> inline std::string to_string(const std::string &value) { return value; } -template inline typename std::enable_if::value, std::string>::type -to_string(T value) { return std::to_string((int) value); } - NAMESPACE_END(detail) #define PYBIND11_RUNTIME_EXCEPTION(name) \ @@ -321,4 +309,15 @@ PYBIND11_RUNTIME_EXCEPTION(cast_error) /// Thrown when pybind11::cast or handle: [[noreturn]] PYBIND11_NOINLINE inline void pybind11_fail(const char *reason) { throw std::runtime_error(reason); } [[noreturn]] PYBIND11_NOINLINE inline void pybind11_fail(const std::string &reason) { throw std::runtime_error(reason); } +/// Format strings for basic number types +#define PYBIND11_DECL_FMT(t, v) template<> struct format_descriptor { static constexpr const char *value = v; } +template struct format_descriptor { }; +template struct format_descriptor::value>::type> { + static constexpr const char value[2] = + { "bBhHiIqQ"[detail::log2(sizeof(T))*2 + (std::is_unsigned::value ? 1 : 0)], '\0' }; +}; +template constexpr const char format_descriptor< + T, typename std::enable_if::value>::type>::value[2]; +PYBIND11_DECL_FMT(float, "f"); PYBIND11_DECL_FMT(double, "d"); PYBIND11_DECL_FMT(bool, "?"); + NAMESPACE_END(pybind11) diff --git a/include/pybind11/numpy.h b/include/pybind11/numpy.h index 38d30bfb..cf46c337 100644 --- a/include/pybind11/numpy.h +++ b/include/pybind11/numpy.h @@ -21,7 +21,7 @@ NAMESPACE_BEGIN(pybind11) -template struct npy_format_descriptor { }; +template struct npy_format_descriptor { }; class array : public buffer { public: @@ -138,12 +138,20 @@ public: } }; +template struct npy_format_descriptor::value>::type> { +private: + constexpr static const int values[] = { + array::API::NPY_BYTE_, array::API::NPY_UBYTE_, array::API::NPY_SHORT_, array::API::NPY_USHORT_, + array::API::NPY_INT_, array::API::NPY_UINT_, array::API::NPY_LONGLONG_, array::API::NPY_ULONGLONG_ }; +public: + enum { value = values[detail::log2(sizeof(T)) * 2 + (std::is_unsigned::value ? 1 : 0)] }; +}; +template constexpr const int npy_format_descriptor< + T, typename std::enable_if::value>::type>::values[8]; + #define DECL_FMT(t, n) template<> struct npy_format_descriptor { enum { value = array::API::n }; } -DECL_FMT(int8_t, NPY_BYTE_); DECL_FMT(uint8_t, NPY_UBYTE_); DECL_FMT(int16_t, NPY_SHORT_); -DECL_FMT(uint16_t, NPY_USHORT_); DECL_FMT(int32_t, NPY_INT_); DECL_FMT(uint32_t, NPY_UINT_); -DECL_FMT(int64_t, NPY_LONGLONG_); DECL_FMT(uint64_t, NPY_ULONGLONG_); DECL_FMT(float, NPY_FLOAT_); -DECL_FMT(double, NPY_DOUBLE_); DECL_FMT(bool, NPY_BOOL_); DECL_FMT(std::complex, NPY_CFLOAT_); -DECL_FMT(std::complex, NPY_CDOUBLE_); +DECL_FMT(float, NPY_FLOAT_); DECL_FMT(double, NPY_DOUBLE_); DECL_FMT(bool, NPY_BOOL_); +DECL_FMT(std::complex, NPY_CFLOAT_); DECL_FMT(std::complex, NPY_CDOUBLE_); #undef DECL_FMT NAMESPACE_BEGIN(detail) @@ -328,7 +336,7 @@ struct vectorize_helper { return cast(f(*((Args *) buffers[Index].ptr)...)); array result(buffer_info(nullptr, sizeof(Return), - format_descriptor::value(), + format_descriptor::value, ndim, shape, strides)); buffer_info buf = result.request();