mirror of
https://github.com/RYDE-WORK/pybind11.git
synced 2026-02-03 22:14:33 +08:00
redesigned format_descriptor<> and npy_format_descriptor<>
This somewhat heavyweight solution will avoid size_t/long long/long/int mismatches on various platforms once and for all. The previous template overloads could e.g. not handle size_t on Darwin. One gotcha: the 'format_descriptor<T>::value()' syntax changed to just 'format_descriptor<T>::value'
This commit is contained in:
parent
c62360d994
commit
876eeab4ca
@ -825,12 +825,12 @@ completely avoid copy operations with Python expressions like
|
|||||||
py::class_<Matrix>(m, "Matrix")
|
py::class_<Matrix>(m, "Matrix")
|
||||||
.def_buffer([](Matrix &m) -> py::buffer_info {
|
.def_buffer([](Matrix &m) -> py::buffer_info {
|
||||||
return py::buffer_info(
|
return py::buffer_info(
|
||||||
m.data(), /* Pointer to buffer */
|
m.data(), /* Pointer to buffer */
|
||||||
sizeof(float), /* Size of one scalar */
|
sizeof(float), /* Size of one scalar */
|
||||||
py::format_descriptor<float>::value(), /* Python struct-style format descriptor */
|
py::format_descriptor<float>::value, /* Python struct-style format descriptor */
|
||||||
2, /* Number of dimensions */
|
2, /* Number of dimensions */
|
||||||
{ m.rows(), m.cols() }, /* Buffer dimensions */
|
{ m.rows(), m.cols() }, /* Buffer dimensions */
|
||||||
{ sizeof(float) * m.rows(), /* Strides (in bytes) for each index */
|
{ sizeof(float) * m.rows(), /* Strides (in bytes) for each index */
|
||||||
sizeof(float) }
|
sizeof(float) }
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
@ -867,7 +867,7 @@ objects (e.g. a NumPy matrix).
|
|||||||
py::buffer_info info = b.request();
|
py::buffer_info info = b.request();
|
||||||
|
|
||||||
/* Some sanity checks ... */
|
/* Some sanity checks ... */
|
||||||
if (info.format != py::format_descriptor<double>::value())
|
if (info.format != py::format_descriptor<double>::value)
|
||||||
throw std::runtime_error("Incompatible format: expected a double array!");
|
throw std::runtime_error("Incompatible format: expected a double array!");
|
||||||
|
|
||||||
if (info.ndim != 2)
|
if (info.ndim != 2)
|
||||||
@ -994,7 +994,7 @@ simply using ``vectorize``).
|
|||||||
auto result = py::array(py::buffer_info(
|
auto result = py::array(py::buffer_info(
|
||||||
nullptr, /* Pointer to data (nullptr -> ask NumPy to allocate!) */
|
nullptr, /* Pointer to data (nullptr -> ask NumPy to allocate!) */
|
||||||
sizeof(double), /* Size of one item */
|
sizeof(double), /* Size of one item */
|
||||||
py::format_descriptor<double>::value(), /* Buffer format */
|
py::format_descriptor<double>::value, /* Buffer format */
|
||||||
buf1.ndim, /* How many dimensions? */
|
buf1.ndim, /* How many dimensions? */
|
||||||
{ buf1.shape[0] }, /* Number of elements for each dimension */
|
{ buf1.shape[0] }, /* Number of elements for each dimension */
|
||||||
{ sizeof(double) } /* Strides for each dimension */
|
{ sizeof(double) } /* Strides for each dimension */
|
||||||
|
|||||||
@ -80,7 +80,7 @@ void init_ex7(py::module &m) {
|
|||||||
/// Construct from a buffer
|
/// Construct from a buffer
|
||||||
.def("__init__", [](Matrix &v, py::buffer b) {
|
.def("__init__", [](Matrix &v, py::buffer b) {
|
||||||
py::buffer_info info = b.request();
|
py::buffer_info info = b.request();
|
||||||
if (info.format != py::format_descriptor<float>::value() || info.ndim != 2)
|
if (info.format != py::format_descriptor<float>::value || info.ndim != 2)
|
||||||
throw std::runtime_error("Incompatible buffer format!");
|
throw std::runtime_error("Incompatible buffer format!");
|
||||||
new (&v) Matrix(info.shape[0], info.shape[1]);
|
new (&v) Matrix(info.shape[0], info.shape[1]);
|
||||||
memcpy(v.data(), info.ptr, sizeof(float) * v.rows() * v.cols());
|
memcpy(v.data(), info.ptr, sizeof(float) * v.rows() * v.cols());
|
||||||
@ -103,12 +103,12 @@ void init_ex7(py::module &m) {
|
|||||||
/// Provide buffer access
|
/// Provide buffer access
|
||||||
.def_buffer([](Matrix &m) -> py::buffer_info {
|
.def_buffer([](Matrix &m) -> py::buffer_info {
|
||||||
return py::buffer_info(
|
return py::buffer_info(
|
||||||
m.data(), /* Pointer to buffer */
|
m.data(), /* Pointer to buffer */
|
||||||
sizeof(float), /* Size of one scalar */
|
sizeof(float), /* Size of one scalar */
|
||||||
py::format_descriptor<float>::value(), /* Python struct-style format descriptor */
|
py::format_descriptor<float>::value, /* Python struct-style format descriptor */
|
||||||
2, /* Number of dimensions */
|
2, /* Number of dimensions */
|
||||||
{ m.rows(), m.cols() }, /* Buffer dimensions */
|
{ m.rows(), m.cols() }, /* Buffer dimensions */
|
||||||
{ sizeof(float) * m.rows(), /* Strides (in bytes) for each index */
|
{ sizeof(float) * m.rows(), /* Strides (in bytes) for each index */
|
||||||
sizeof(float) }
|
sizeof(float) }
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|||||||
@ -191,13 +191,6 @@ enum class return_value_policy : int {
|
|||||||
reference_internal
|
reference_internal
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Format strings for basic number types
|
|
||||||
template <typename type> struct format_descriptor { };
|
|
||||||
#define PYBIND11_DECL_FMT(t, n) template<> struct format_descriptor<t> { 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
|
/// Information record describing a Python buffer object
|
||||||
struct buffer_info {
|
struct buffer_info {
|
||||||
void *ptr; // Pointer to the underlying storage
|
void *ptr; // Pointer to the underlying storage
|
||||||
@ -234,6 +227,8 @@ private:
|
|||||||
|
|
||||||
NAMESPACE_BEGIN(detail)
|
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();
|
inline std::string error_string();
|
||||||
|
|
||||||
/// Core part of the 'instance' type which POD (needed to be able to use 'offsetof')
|
/// Core part of the 'instance' type which POD (needed to be able to use 'offsetof')
|
||||||
@ -296,13 +291,6 @@ template <typename T, size_t N> struct intrinsic_type<T[N]> { typedef type
|
|||||||
/// Helper type to replace 'void' in some expressions
|
/// Helper type to replace 'void' in some expressions
|
||||||
struct void_type { };
|
struct void_type { };
|
||||||
|
|
||||||
/// to_string variant which also accepts strings
|
|
||||||
template <typename T> inline typename std::enable_if<!std::is_enum<T>::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 <typename T> inline typename std::enable_if<std::is_enum<T>::value, std::string>::type
|
|
||||||
to_string(T value) { return std::to_string((int) value); }
|
|
||||||
|
|
||||||
NAMESPACE_END(detail)
|
NAMESPACE_END(detail)
|
||||||
|
|
||||||
#define PYBIND11_RUNTIME_EXCEPTION(name) \
|
#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 char *reason) { throw std::runtime_error(reason); }
|
||||||
[[noreturn]] PYBIND11_NOINLINE inline void pybind11_fail(const std::string &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<t> { static constexpr const char *value = v; }
|
||||||
|
template <typename T, typename SFINAE = void> struct format_descriptor { };
|
||||||
|
template <typename T> struct format_descriptor<T, typename std::enable_if<std::is_integral<T>::value>::type> {
|
||||||
|
static constexpr const char value[2] =
|
||||||
|
{ "bBhHiIqQ"[detail::log2(sizeof(T))*2 + (std::is_unsigned<T>::value ? 1 : 0)], '\0' };
|
||||||
|
};
|
||||||
|
template <typename T> constexpr const char format_descriptor<
|
||||||
|
T, typename std::enable_if<std::is_integral<T>::value>::type>::value[2];
|
||||||
|
PYBIND11_DECL_FMT(float, "f"); PYBIND11_DECL_FMT(double, "d"); PYBIND11_DECL_FMT(bool, "?");
|
||||||
|
|
||||||
NAMESPACE_END(pybind11)
|
NAMESPACE_END(pybind11)
|
||||||
|
|||||||
@ -21,7 +21,7 @@
|
|||||||
|
|
||||||
NAMESPACE_BEGIN(pybind11)
|
NAMESPACE_BEGIN(pybind11)
|
||||||
|
|
||||||
template <typename type> struct npy_format_descriptor { };
|
template <typename type, typename SFINAE = void> struct npy_format_descriptor { };
|
||||||
|
|
||||||
class array : public buffer {
|
class array : public buffer {
|
||||||
public:
|
public:
|
||||||
@ -138,12 +138,20 @@ public:
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template <typename T> struct npy_format_descriptor<T, typename std::enable_if<std::is_integral<T>::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<T>::value ? 1 : 0)] };
|
||||||
|
};
|
||||||
|
template <typename T> constexpr const int npy_format_descriptor<
|
||||||
|
T, typename std::enable_if<std::is_integral<T>::value>::type>::values[8];
|
||||||
|
|
||||||
#define DECL_FMT(t, n) template<> struct npy_format_descriptor<t> { enum { value = array::API::n }; }
|
#define DECL_FMT(t, n) template<> struct npy_format_descriptor<t> { 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(float, NPY_FLOAT_); DECL_FMT(double, NPY_DOUBLE_); DECL_FMT(bool, NPY_BOOL_);
|
||||||
DECL_FMT(uint16_t, NPY_USHORT_); DECL_FMT(int32_t, NPY_INT_); DECL_FMT(uint32_t, NPY_UINT_);
|
DECL_FMT(std::complex<float>, NPY_CFLOAT_); DECL_FMT(std::complex<double>, NPY_CDOUBLE_);
|
||||||
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<float>, NPY_CFLOAT_);
|
|
||||||
DECL_FMT(std::complex<double>, NPY_CDOUBLE_);
|
|
||||||
#undef DECL_FMT
|
#undef DECL_FMT
|
||||||
|
|
||||||
NAMESPACE_BEGIN(detail)
|
NAMESPACE_BEGIN(detail)
|
||||||
@ -328,7 +336,7 @@ struct vectorize_helper {
|
|||||||
return cast(f(*((Args *) buffers[Index].ptr)...));
|
return cast(f(*((Args *) buffers[Index].ptr)...));
|
||||||
|
|
||||||
array result(buffer_info(nullptr, sizeof(Return),
|
array result(buffer_info(nullptr, sizeof(Return),
|
||||||
format_descriptor<Return>::value(),
|
format_descriptor<Return>::value,
|
||||||
ndim, shape, strides));
|
ndim, shape, strides));
|
||||||
|
|
||||||
buffer_info buf = result.request();
|
buffer_info buf = result.request();
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user