| 976 | } |
| 977 | |
| 978 | dtype strip_padding(ssize_t itemsize) { |
| 979 | // Recursively strip all void fields with empty names that are generated for |
| 980 | // padding fields (as of NumPy v1.11). |
| 981 | if (!has_fields()) { |
| 982 | return *this; |
| 983 | } |
| 984 | |
| 985 | struct field_descr { |
| 986 | pybind11::str name; |
| 987 | object format; |
| 988 | pybind11::int_ offset; |
| 989 | field_descr(pybind11::str &&name, object &&format, pybind11::int_ &&offset) |
| 990 | : name{std::move(name)}, format{std::move(format)}, offset{std::move(offset)} {}; |
| 991 | }; |
| 992 | auto field_dict = attr("fields").cast<dict>(); |
| 993 | std::vector<field_descr> field_descriptors; |
| 994 | field_descriptors.reserve(field_dict.size()); |
| 995 | |
| 996 | for (auto field : field_dict.attr("items")()) { |
| 997 | auto spec = field.cast<tuple>(); |
| 998 | auto name = spec[0].cast<pybind11::str>(); |
| 999 | auto spec_fo = spec[1].cast<tuple>(); |
| 1000 | auto format = spec_fo[0].cast<dtype>(); |
| 1001 | auto offset = spec_fo[1].cast<pybind11::int_>(); |
| 1002 | if ((len(name) == 0u) && format.kind() == 'V') { |
| 1003 | continue; |
| 1004 | } |
| 1005 | field_descriptors.emplace_back( |
| 1006 | std::move(name), format.strip_padding(format.itemsize()), std::move(offset)); |
| 1007 | } |
| 1008 | |
| 1009 | std::sort(field_descriptors.begin(), |
| 1010 | field_descriptors.end(), |
| 1011 | [](const field_descr &a, const field_descr &b) { |
| 1012 | return a.offset.cast<int>() < b.offset.cast<int>(); |
| 1013 | }); |
| 1014 | |
| 1015 | list names, formats, offsets; |
| 1016 | for (auto &descr : field_descriptors) { |
| 1017 | names.append(std::move(descr.name)); |
| 1018 | formats.append(std::move(descr.format)); |
| 1019 | offsets.append(std::move(descr.offset)); |
| 1020 | } |
| 1021 | return dtype(std::move(names), std::move(formats), std::move(offsets), itemsize); |
| 1022 | } |
| 1023 | }; |
| 1024 | |
| 1025 | class array : public buffer { |