From e8b50360fe2523e8d490d40dc9a06b36b7e8516a Mon Sep 17 00:00:00 2001 From: Ivan Smirnov Date: Tue, 1 Nov 2016 13:27:35 +0000 Subject: [PATCH 1/2] Add dtype binding macro that allows setting names PYBIND11_NUMPY_DTYPE_EX(Type, F1, "N1", F2, "N2", ...) --- include/pybind11/numpy.h | 36 ++++++++++++++++++++++++++++++------ 1 file changed, 30 insertions(+), 6 deletions(-) diff --git a/include/pybind11/numpy.h b/include/pybind11/numpy.h index 4ae3de88..da04c62a 100644 --- a/include/pybind11/numpy.h +++ b/include/pybind11/numpy.h @@ -20,6 +20,7 @@ #include #include #include +#include #if defined(_MSC_VER) # pragma warning(push) @@ -748,14 +749,16 @@ std::string npy_format_descriptor::value>>::form template PyObject* npy_format_descriptor::value>>::dtype_ptr = nullptr; -// Extract name, offset and format descriptor for a struct field -#define PYBIND11_FIELD_DESCRIPTOR(Type, Field) \ - ::pybind11::detail::field_descriptor { \ - #Field, offsetof(Type, Field), sizeof(decltype(static_cast(0)->Field)), \ - ::pybind11::format_descriptor(0)->Field)>::format(), \ - ::pybind11::detail::npy_format_descriptor(0)->Field)>::dtype() \ +#define PYBIND11_FIELD_DESCRIPTOR_EX(T, Field, Name) \ + ::pybind11::detail::field_descriptor { \ + Name, offsetof(T, Field), sizeof(decltype(std::declval().Field)), \ + ::pybind11::format_descriptor().Field)>::format(), \ + ::pybind11::detail::npy_format_descriptor().Field)>::dtype() \ } +// Extract name, offset and format descriptor for a struct field +#define PYBIND11_FIELD_DESCRIPTOR(T, Field) PYBIND11_FIELD_DESCRIPTOR_EX(T, Field, #Field) + // The main idea of this macro is borrowed from https://github.com/swansontec/map-macro // (C) William Swanson, Paul Fultz #define PYBIND11_EVAL0(...) __VA_ARGS__ @@ -792,6 +795,27 @@ PyObject* npy_format_descriptor::value>>::dtype_ ::pybind11::detail::npy_format_descriptor::register_dtype \ ({PYBIND11_MAP_LIST (PYBIND11_FIELD_DESCRIPTOR, Type, __VA_ARGS__)}) +#ifdef _MSC_VER +#define PYBIND11_MAP2_LIST_NEXT1(test, next) \ + PYBIND11_EVAL0 (PYBIND11_MAP_NEXT0 (test, PYBIND11_MAP_COMMA next, 0)) +#else +#define PYBIND11_MAP2_LIST_NEXT1(test, next) \ + PYBIND11_MAP_NEXT0 (test, PYBIND11_MAP_COMMA next, 0) +#endif +#define PYBIND11_MAP2_LIST_NEXT(test, next) \ + PYBIND11_MAP2_LIST_NEXT1 (PYBIND11_MAP_GET_END test, next) +#define PYBIND11_MAP2_LIST0(f, t, x1, x2, peek, ...) \ + f(t, x1, x2) PYBIND11_MAP2_LIST_NEXT (peek, PYBIND11_MAP2_LIST1) (f, t, peek, __VA_ARGS__) +#define PYBIND11_MAP2_LIST1(f, t, x1, x2, peek, ...) \ + f(t, x1, x2) PYBIND11_MAP2_LIST_NEXT (peek, PYBIND11_MAP2_LIST0) (f, t, peek, __VA_ARGS__) +// PYBIND11_MAP2_LIST(f, t, a1, a2, ...) expands to f(t, a1, a2), f(t, a3, a4), ... +#define PYBIND11_MAP2_LIST(f, t, ...) \ + PYBIND11_EVAL (PYBIND11_MAP2_LIST1 (f, t, __VA_ARGS__, (), 0)) + +#define PYBIND11_NUMPY_DTYPE_EX(Type, ...) \ + ::pybind11::detail::npy_format_descriptor::register_dtype \ + ({PYBIND11_MAP2_LIST (PYBIND11_FIELD_DESCRIPTOR_EX, Type, __VA_ARGS__)}) + template using array_iterator = typename std::add_pointer::type; From abd3429ce9ae884974c11d2dc79a190f0ca8f742 Mon Sep 17 00:00:00 2001 From: Ivan Smirnov Date: Tue, 1 Nov 2016 13:29:32 +0000 Subject: [PATCH 2/2] Add a test for numpy dtypes with custom names --- tests/test_numpy_dtypes.cpp | 10 +++++++++- tests/test_numpy_dtypes.py | 3 ++- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/tests/test_numpy_dtypes.cpp b/tests/test_numpy_dtypes.cpp index 40aca0c3..8f680c07 100644 --- a/tests/test_numpy_dtypes.cpp +++ b/tests/test_numpy_dtypes.cpp @@ -67,6 +67,11 @@ struct StringStruct { std::array b; }; +PYBIND11_PACKED(struct StructWithUglyNames { + int8_t __x__; + uint64_t __y__; +}); + enum class E1 : int64_t { A = -1, B = 1 }; enum E2 : uint8_t { X = 1, Y = 2 }; @@ -197,7 +202,8 @@ py::list print_dtypes() { py::dtype::of().str(), py::dtype::of().str(), py::dtype::of().str(), - py::dtype::of().str() + py::dtype::of().str(), + py::dtype::of().str() }; auto l = py::list(); for (const auto &s : dtypes) { @@ -312,6 +318,8 @@ test_initializer numpy_dtypes([](py::module &m) { // ... or after py::class_(m, "PackedStruct"); + PYBIND11_NUMPY_DTYPE_EX(StructWithUglyNames, __x__, "x", __y__, "y"); + m.def("create_rec_simple", &create_recarray); m.def("create_rec_packed", &create_recarray); m.def("create_rec_nested", &create_nested); diff --git a/tests/test_numpy_dtypes.py b/tests/test_numpy_dtypes.py index 47d7c3bd..b4e6d71f 100644 --- a/tests/test_numpy_dtypes.py +++ b/tests/test_numpy_dtypes.py @@ -42,7 +42,8 @@ def test_dtype(): "{'names':['x','y','z'], 'formats':['?','