example-numpy-dtypes.cpp 7.15 KB
Newer Older
1
/*
2
  example/example-numpy-dtypes.cpp -- Structured and compound NumPy dtypes
3
4
5
6
7
8
9
10
11
12
13
14
15

  Copyright (c) 2016 Ivan Smirnov

  All rights reserved. Use of this source code is governed by a
  BSD-style license that can be found in the LICENSE file.
*/

#include "example.h"

#include <pybind11/numpy.h>
#include <cstdint>
#include <iostream>

16
17
18
19
20
21
#ifdef __GNUC__
#define PYBIND11_PACKED(cls) cls __attribute__((__packed__))
#else
#define PYBIND11_PACKED(cls) __pragma(pack(push, 1)) cls __pragma(pack(pop))
#endif

22
23
namespace py = pybind11;

24
struct SimpleStruct {
25
26
27
28
29
    bool x;
    uint32_t y;
    float z;
};

30
31
std::ostream& operator<<(std::ostream& os, const SimpleStruct& v) {
    return os << "s:" << v.x << "," << v.y << "," << v.z;
32
33
}

34
PYBIND11_PACKED(struct PackedStruct {
35
36
37
    bool x;
    uint32_t y;
    float z;
38
});
39

40
std::ostream& operator<<(std::ostream& os, const PackedStruct& v) {
41
    return os << "p:" << v.x << "," << v.y << "," << v.z;
42
43
}

44
PYBIND11_PACKED(struct NestedStruct {
45
    SimpleStruct a;
46
    PackedStruct b;
47
});
Ivan Smirnov's avatar
Ivan Smirnov committed
48

49
std::ostream& operator<<(std::ostream& os, const NestedStruct& v) {
50
    return os << "n:a=" << v.a << ";b=" << v.b;
51
52
}

53
54
55
56
57
58
59
60
61
62
63
64
65
struct PartialStruct {
    bool x;
    uint32_t y;
    float z;
    long dummy2;
};

struct PartialNestedStruct {
    long dummy1;
    PartialStruct a;
    long dummy2;
};

66
67
struct UnboundStruct { };

68
69
70
71
72
73
74
75
76
77
78
79
80
struct StringStruct {
    char a[3];
    std::array<char, 3> 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 << "'";
}

Ivan Smirnov's avatar
Ivan Smirnov committed
81
82
83
template <typename T>
py::array mkarray_via_buffer(size_t n) {
    return py::array(py::buffer_info(nullptr, sizeof(T),
84
                                     py::format_descriptor<T>::format(),
Ivan Smirnov's avatar
Ivan Smirnov committed
85
86
                                     1, { n }, { sizeof(T) }));
}
87
88

template <typename S>
89
py::array_t<S, 0> create_recarray(size_t n) {
Ivan Smirnov's avatar
Ivan Smirnov committed
90
    auto arr = mkarray_via_buffer<S>(n);
91
92
    auto req = arr.request();
    auto ptr = static_cast<S*>(req.ptr);
Ivan Smirnov's avatar
Ivan Smirnov committed
93
94
95
96
97
98
    for (size_t i = 0; i < n; i++) {
        ptr[i].x = i % 2; ptr[i].y = (uint32_t) i; ptr[i].z = (float) i * 1.5f;
    }
    return arr;
}

99
100
101
102
std::string get_format_unbound() {
    return py::format_descriptor<UnboundStruct>::format();
}

103
py::array_t<NestedStruct, 0> create_nested(size_t n) {
Ivan Smirnov's avatar
Ivan Smirnov committed
104
    auto arr = mkarray_via_buffer<NestedStruct>(n);
105
106
    auto req = arr.request();
    auto ptr = static_cast<NestedStruct*>(req.ptr);
107
    for (size_t i = 0; i < n; i++) {
Ivan Smirnov's avatar
Ivan Smirnov committed
108
109
        ptr[i].a.x = i % 2; ptr[i].a.y = (uint32_t) i; ptr[i].a.z = (float) i * 1.5f;
        ptr[i].b.x = (i + 1) % 2; ptr[i].b.y = (uint32_t) (i + 1); ptr[i].b.z = (float) (i + 1) * 1.5f;
110
111
    }
    return arr;
112
113
}

114
115
py::array_t<PartialNestedStruct, 0> create_partial_nested(size_t n) {
    auto arr = mkarray_via_buffer<PartialNestedStruct>(n);
116
117
    auto req = arr.request();
    auto ptr = static_cast<PartialNestedStruct*>(req.ptr);
118
119
120
121
122
123
    for (size_t i = 0; i < n; i++) {
        ptr[i].a.x = i % 2; ptr[i].a.y = (uint32_t) i; ptr[i].a.z = (float) i * 1.5f;
    }
    return arr;
}

124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
py::array_t<StringStruct, 0> create_string_array(bool non_empty) {
    auto arr = mkarray_via_buffer<StringStruct>(non_empty ? 4 : 0);
    if (non_empty) {
        auto req = arr.request();
        auto ptr = static_cast<StringStruct*>(req.ptr);
        for (size_t i = 0; i < req.size * req.itemsize; i++)
            static_cast<char*>(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;
}

143
template <typename S>
144
void print_recarray(py::array_t<S, 0> arr) {
145
146
147
    auto req = arr.request();
    auto ptr = static_cast<S*>(req.ptr);
    for (size_t i = 0; i < req.size; i++)
148
149
        std::cout << ptr[i] << std::endl;
}
Ivan Smirnov's avatar
Ivan Smirnov committed
150

151
void print_format_descriptors() {
152
153
154
    std::cout << py::format_descriptor<SimpleStruct>::format() << std::endl;
    std::cout << py::format_descriptor<PackedStruct>::format() << std::endl;
    std::cout << py::format_descriptor<NestedStruct>::format() << std::endl;
155
156
    std::cout << py::format_descriptor<PartialStruct>::format() << std::endl;
    std::cout << py::format_descriptor<PartialNestedStruct>::format() << std::endl;
157
    std::cout << py::format_descriptor<StringStruct>::format() << std::endl;
158
159
}

160
void print_dtypes() {
161
162
163
164
165
166
    std::cout << (std::string) py::dtype::of<SimpleStruct>().str() << std::endl;
    std::cout << (std::string) py::dtype::of<PackedStruct>().str() << std::endl;
    std::cout << (std::string) py::dtype::of<NestedStruct>().str() << std::endl;
    std::cout << (std::string) py::dtype::of<PartialStruct>().str() << std::endl;
    std::cout << (std::string) py::dtype::of<PartialNestedStruct>().str() << std::endl;
    std::cout << (std::string) py::dtype::of<StringStruct>().str() << std::endl;
167
168
}

169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
py::array_t<int32_t, 0> test_array_ctors(int i) {
    using arr_t = py::array_t<int32_t, 0>;

    std::vector<int32_t> data { 1, 2, 3, 4, 5, 6 };
    std::vector<size_t> shape { 3, 2 };
    std::vector<size_t> strides { 8, 4 };

    auto ptr = data.data();
    auto vptr = (void *) ptr;
    auto dtype = py::dtype("int32");

    py::buffer_info buf_ndim1(vptr, 4, "i", 6);
    py::buffer_info buf_ndim2(vptr, 4, "i", 2, shape, strides);

    switch (i) {
    // shape: (3, 2)
    case 0: return arr_t(shape, ptr, strides);
    case 1: return py::array(shape, ptr, strides);
    case 2: return py::array(dtype, shape, vptr, strides);
    case 3: return arr_t(shape, ptr);
    case 4: return py::array(shape, ptr);
    case 5: return py::array(dtype, shape, vptr);
    case 6: return arr_t(buf_ndim2);
    case 7: return py::array(buf_ndim2);
    // shape: (6, )
    case 8: return arr_t(6, ptr);
    case 9: return py::array(6, ptr);
    case 10: return py::array(dtype, 6, vptr);
    case 11: return arr_t(buf_ndim1);
    case 12: return py::array(buf_ndim1);
    }
    return arr_t();
}

203
void init_ex_numpy_dtypes(py::module &m) {
204
205
206
    PYBIND11_NUMPY_DTYPE(SimpleStruct, x, y, z);
    PYBIND11_NUMPY_DTYPE(PackedStruct, x, y, z);
    PYBIND11_NUMPY_DTYPE(NestedStruct, a, b);
207
208
    PYBIND11_NUMPY_DTYPE(PartialStruct, x, y, z);
    PYBIND11_NUMPY_DTYPE(PartialNestedStruct, a);
209
    PYBIND11_NUMPY_DTYPE(StringStruct, a, b);
210

211
    m.def("create_rec_simple", &create_recarray<SimpleStruct>);
212
    m.def("create_rec_packed", &create_recarray<PackedStruct>);
Ivan Smirnov's avatar
Ivan Smirnov committed
213
    m.def("create_rec_nested", &create_nested);
214
215
    m.def("create_rec_partial", &create_recarray<PartialStruct>);
    m.def("create_rec_partial_nested", &create_partial_nested);
216
    m.def("print_format_descriptors", &print_format_descriptors);
217
    m.def("print_rec_simple", &print_recarray<SimpleStruct>);
218
219
    m.def("print_rec_packed", &print_recarray<PackedStruct>);
    m.def("print_rec_nested", &print_recarray<NestedStruct>);
220
    m.def("print_dtypes", &print_dtypes);
221
    m.def("get_format_unbound", &get_format_unbound);
222
223
    m.def("create_string_array", &create_string_array);
    m.def("print_string_array", &print_recarray<StringStruct>);
224
    m.def("test_array_ctors", &test_array_ctors);
225
}
226
227

#undef PYBIND11_PACKED