From f9c0defed7a764b1b1cfc02bce6c742d56e2664f Mon Sep 17 00:00:00 2001 From: Ivan Smirnov Date: Wed, 20 Jul 2016 00:19:24 +0100 Subject: [PATCH] Add numpy wrappers for char[] and std::array --- example/example20.cpp | 37 +++++++++++++++++++++++++++++++++++++ example/example20.py | 11 ++++++++++- example/example20.ref | 9 ++++++++- include/pybind11/numpy.h | 32 +++++++++++++++++++++++++++++--- 4 files changed, 84 insertions(+), 5 deletions(-) diff --git a/example/example20.cpp b/example/example20.cpp index 8b18c05d..07849a09 100644 --- a/example/example20.cpp +++ b/example/example20.cpp @@ -65,6 +65,19 @@ struct PartialNestedStruct { struct UnboundStruct { }; +struct StringStruct { + char a[3]; + std::array b; +}; + +std::ostream& operator<<(std::ostream& os, const StringStruct& v) { + os << "a='"; + for (size_t i = 0; i < 3 && v.a[i]; i++) os << v.a[i]; + os << "',b='"; + for (size_t i = 0; i < 3 && v.b[i]; i++) os << v.b[i]; + return os << "'"; +} + template py::array mkarray_via_buffer(size_t n) { return py::array(py::buffer_info(nullptr, sizeof(T), @@ -108,6 +121,25 @@ py::array_t create_partial_nested(size_t n) { return arr; } +py::array_t create_string_array(bool non_empty) { + auto arr = mkarray_via_buffer(non_empty ? 4 : 0); + if (non_empty) { + auto req = arr.request(); + auto ptr = static_cast(req.ptr); + for (size_t i = 0; i < req.size * req.itemsize; i++) + static_cast(req.ptr)[i] = 0; + ptr[1].a[0] = 'a'; ptr[1].b[0] = 'a'; + ptr[2].a[0] = 'a'; ptr[2].b[0] = 'a'; + ptr[3].a[0] = 'a'; ptr[3].b[0] = 'a'; + + ptr[2].a[1] = 'b'; ptr[2].b[1] = 'b'; + ptr[3].a[1] = 'b'; ptr[3].b[1] = 'b'; + + ptr[3].a[2] = 'c'; ptr[3].b[2] = 'c'; + } + return arr; +} + template void print_recarray(py::array_t arr) { auto req = arr.request(); @@ -122,6 +154,7 @@ void print_format_descriptors() { std::cout << py::format_descriptor::format() << std::endl; std::cout << py::format_descriptor::format() << std::endl; std::cout << py::format_descriptor::format() << std::endl; + std::cout << py::format_descriptor::format() << std::endl; } void print_dtypes() { @@ -133,6 +166,7 @@ void print_dtypes() { std::cout << to_str(py::dtype_of()) << std::endl; std::cout << to_str(py::dtype_of()) << std::endl; std::cout << to_str(py::dtype_of()) << std::endl; + std::cout << to_str(py::dtype_of()) << std::endl; } void init_ex20(py::module &m) { @@ -141,6 +175,7 @@ void init_ex20(py::module &m) { PYBIND11_NUMPY_DTYPE(NestedStruct, a, b); PYBIND11_NUMPY_DTYPE(PartialStruct, x, y, z); PYBIND11_NUMPY_DTYPE(PartialNestedStruct, a); + PYBIND11_NUMPY_DTYPE(StringStruct, a, b); m.def("create_rec_simple", &create_recarray); m.def("create_rec_packed", &create_recarray); @@ -153,6 +188,8 @@ void init_ex20(py::module &m) { m.def("print_rec_nested", &print_recarray); m.def("print_dtypes", &print_dtypes); m.def("get_format_unbound", &get_format_unbound); + m.def("create_string_array", &create_string_array); + m.def("print_string_array", &print_recarray); } #undef PYBIND11_PACKED diff --git a/example/example20.py b/example/example20.py index bb57590c..34dfd833 100644 --- a/example/example20.py +++ b/example/example20.py @@ -6,7 +6,7 @@ import numpy as np from example import ( create_rec_simple, create_rec_packed, create_rec_nested, print_format_descriptors, print_rec_simple, print_rec_packed, print_rec_nested, print_dtypes, get_format_unbound, - create_rec_partial, create_rec_partial_nested + create_rec_partial, create_rec_partial_nested, create_string_array, print_string_array ) @@ -72,3 +72,12 @@ check_eq(arr, [((False, 0, 0.0), (True, 1, 1.5)), print_rec_nested(arr) assert create_rec_nested.__doc__.strip().endswith('numpy.ndarray[dtype=NestedStruct]') + +arr = create_string_array(True) +print(arr.dtype) +print_string_array(arr) +dtype = arr.dtype +assert arr['a'].tolist() == [b'', b'a', b'ab', b'abc'] +assert arr['b'].tolist() == [b'', b'a', b'ab', b'abc'] +arr = create_string_array(False) +assert dtype == arr.dtype diff --git a/example/example20.ref b/example/example20.ref index 72a6c185..4f07ce44 100644 --- a/example/example20.ref +++ b/example/example20.ref @@ -3,11 +3,13 @@ T{=?:x:=I:y:=f:z:} T{=T{=?:x:3x=I:y:=f:z:}:a:=T{=?:x:=I:y:=f:z:}:b:} T{=?:x:3x=I:y:=f:z:12x} T{8x=T{=?:x:3x=I:y:=f:z:12x}:a:8x} +T{=3s:a:=3s:b:} {'names':['x','y','z'], 'formats':['?',' #include +#include #include #include #include @@ -27,10 +28,14 @@ NAMESPACE_BEGIN(pybind11) namespace detail { template struct npy_format_descriptor { }; +template struct is_std_array : std::false_type { }; +template struct is_std_array> : std::true_type { }; template struct is_pod_struct { enum { value = std::is_pod::value && // offsetof only works correctly for POD types + !std::is_array::value && + !is_std_array::value && !std::is_integral::value && !std::is_same::value && !std::is_same::value && @@ -221,9 +226,14 @@ public: template struct format_descriptor::value>::type> { - static const char *format() { - return detail::npy_format_descriptor::format(); - } + static const char *format() { return detail::npy_format_descriptor::format(); } +}; + +template struct format_descriptor { + static const char *format() { PYBIND11_DESCR s = detail::_() + detail::_("s"); return s.text(); } +}; +template struct format_descriptor> { + static const char *format() { PYBIND11_DESCR s = detail::_() + detail::_("s"); return s.text(); } }; template @@ -268,6 +278,22 @@ DECL_FMT(std::complex, NPY_CFLOAT_, "complex64"); DECL_FMT(std::complex, NPY_CDOUBLE_, "complex128"); #undef DECL_FMT +#define DECL_CHAR_FMT \ + static PYBIND11_DESCR name() { return _("S") + _(); } \ + static object dtype() { \ + auto& api = array::lookup_api(); \ + PyObject *descr = nullptr; \ + PYBIND11_DESCR fmt = _("S") + _(); \ + pybind11::str py_fmt(fmt.text()); \ + if (!api.PyArray_DescrConverter_(py_fmt.release().ptr(), &descr) || !descr) \ + pybind11_fail("NumPy: failed to create string dtype"); \ + return object(descr, false); \ + } \ + static const char *format() { PYBIND11_DESCR s = _() + _("s"); return s.text(); } +template struct npy_format_descriptor { DECL_CHAR_FMT }; +template struct npy_format_descriptor> { DECL_CHAR_FMT }; +#undef DECL_CHAR_FMT + struct field_descriptor { const char *name; size_t offset;