From d1db2ccfdf7e9c365fc34177f79ad742cf8e0d7c Mon Sep 17 00:00:00 2001 From: Ivan Smirnov Date: Wed, 27 Dec 2017 15:00:27 +0000 Subject: [PATCH] Make register_dtype() accept any field containers (#1225) * Make register_dtype() accept any field containers * Add a test for programmatic dtype registration --- include/pybind11/numpy.h | 18 ++++++++++-------- tests/test_numpy_dtypes.cpp | 12 ++++++++++++ 2 files changed, 22 insertions(+), 8 deletions(-) diff --git a/include/pybind11/numpy.h b/include/pybind11/numpy.h index 6fd8fdf37..f64084e8f 100644 --- a/include/pybind11/numpy.h +++ b/include/pybind11/numpy.h @@ -18,9 +18,9 @@ #include #include #include -#include #include #include +#include #include #if defined(_MSC_VER) @@ -1057,7 +1057,7 @@ struct field_descriptor { }; inline PYBIND11_NOINLINE void register_structured_dtype( - const std::initializer_list& fields, + any_container fields, const std::type_info& tinfo, ssize_t itemsize, bool (*direct_converter)(PyObject *, void *&)) { @@ -1066,7 +1066,7 @@ inline PYBIND11_NOINLINE void register_structured_dtype( pybind11_fail("NumPy: dtype is already registered"); list names, formats, offsets; - for (auto field : fields) { + for (auto field : *fields) { if (!field.descr) pybind11_fail(std::string("NumPy: unsupported field dtype: `") + field.name + "` @ " + tinfo.name()); @@ -1083,7 +1083,7 @@ inline PYBIND11_NOINLINE void register_structured_dtype( // - https://github.com/numpy/numpy/pull/7798 // Because of this, we won't use numpy's logic to generate buffer format // strings and will just do it ourselves. - std::vector ordered_fields(fields); + std::vector ordered_fields(std::move(fields)); std::sort(ordered_fields.begin(), ordered_fields.end(), [](const field_descriptor &a, const field_descriptor &b) { return a.offset < b.offset; }); ssize_t offset = 0; @@ -1130,8 +1130,8 @@ template struct npy_format_descriptor { return format_str; } - static void register_dtype(const std::initializer_list& fields) { - register_structured_dtype(fields, typeid(typename std::remove_cv::type), + static void register_dtype(any_container fields) { + register_structured_dtype(std::move(fields), typeid(typename std::remove_cv::type), sizeof(T), &direct_converter); } @@ -1204,7 +1204,8 @@ private: #define PYBIND11_NUMPY_DTYPE(Type, ...) \ ::pybind11::detail::npy_format_descriptor::register_dtype \ - ({PYBIND11_MAP_LIST (PYBIND11_FIELD_DESCRIPTOR, Type, __VA_ARGS__)}) + (::std::vector<::pybind11::detail::field_descriptor> \ + {PYBIND11_MAP_LIST (PYBIND11_FIELD_DESCRIPTOR, Type, __VA_ARGS__)}) #ifdef _MSC_VER #define PYBIND11_MAP2_LIST_NEXT1(test, next) \ @@ -1225,7 +1226,8 @@ private: #define PYBIND11_NUMPY_DTYPE_EX(Type, ...) \ ::pybind11::detail::npy_format_descriptor::register_dtype \ - ({PYBIND11_MAP2_LIST (PYBIND11_FIELD_DESCRIPTOR_EX, Type, __VA_ARGS__)}) + (::std::vector<::pybind11::detail::field_descriptor> \ + {PYBIND11_MAP2_LIST (PYBIND11_FIELD_DESCRIPTOR_EX, Type, __VA_ARGS__)}) #endif // __CLION_IDE__ diff --git a/tests/test_numpy_dtypes.cpp b/tests/test_numpy_dtypes.cpp index 266b1fe7d..6e3dc6ba2 100644 --- a/tests/test_numpy_dtypes.cpp +++ b/tests/test_numpy_dtypes.cpp @@ -244,6 +244,9 @@ py::list test_dtype_ctors() { return list; } +struct A {}; +struct B {}; + TEST_SUBMODULE(numpy_dtypes, m) { try { py::module::import("numpy"); } catch (...) { return; } @@ -271,6 +274,15 @@ TEST_SUBMODULE(numpy_dtypes, m) { // struct NotPOD { std::string v; NotPOD() : v("hi") {}; }; // PYBIND11_NUMPY_DTYPE(NotPOD, v); + // Check that dtypes can be registered programmatically, both from + // initializer lists of field descriptors and from other containers. + py::detail::npy_format_descriptor::register_dtype( + {} + ); + py::detail::npy_format_descriptor::register_dtype( + std::vector{} + ); + // test_recarray, test_scalar_conversion m.def("create_rec_simple", &create_recarray); m.def("create_rec_packed", &create_recarray);