@@ -167,6 +167,125 @@ TEST_SUBMODULE(buffers, m) {
167
167
sizeof (float )});
168
168
});
169
169
170
+ // A matrix that uses Fortran storage order.
171
+ class FortranMatrix : public Matrix {
172
+ public:
173
+ FortranMatrix (py::ssize_t rows, py::ssize_t cols) : Matrix(cols, rows) {
174
+ print_created (this , std::to_string (rows) + " x" + std::to_string (cols) + " Fortran matrix" );
175
+ }
176
+
177
+ float operator ()(py::ssize_t i, py::ssize_t j) const {
178
+ return Matrix::operator ()(j, i);
179
+ }
180
+
181
+ float &operator ()(py::ssize_t i, py::ssize_t j) {
182
+ return Matrix::operator ()(j, i);
183
+ }
184
+
185
+ using Matrix::data;
186
+
187
+ py::ssize_t rows () const { return Matrix::cols (); }
188
+ py::ssize_t cols () const { return Matrix::rows (); }
189
+ };
190
+ py::class_<FortranMatrix, Matrix>(m, " FortranMatrix" , py::buffer_protocol ())
191
+ .def (py::init<py::ssize_t , py::ssize_t >())
192
+
193
+ .def (" rows" , &FortranMatrix::rows)
194
+ .def (" cols" , &FortranMatrix::cols)
195
+
196
+ // / Bare bones interface
197
+ .def (" __getitem__" ,
198
+ [](const FortranMatrix &m, std::pair<py::ssize_t , py::ssize_t > i) {
199
+ if (i.first >= m.rows () || i.second >= m.cols ()) {
200
+ throw py::index_error ();
201
+ }
202
+ return m (i.first , i.second );
203
+ })
204
+ .def (" __setitem__" ,
205
+ [](FortranMatrix &m, std::pair<py::ssize_t , py::ssize_t > i, float v) {
206
+ if (i.first >= m.rows () || i.second >= m.cols ()) {
207
+ throw py::index_error ();
208
+ }
209
+ m (i.first , i.second ) = v;
210
+ })
211
+ // / Provide buffer access
212
+ .def_buffer ([](FortranMatrix &m) -> py::buffer_info {
213
+ return py::buffer_info (
214
+ m.data (), /* Pointer to buffer */
215
+ {m.rows (), m.cols ()}, /* Buffer dimensions */
216
+ /* Strides (in bytes) for each index */
217
+ {sizeof (float ), sizeof (float ) * size_t (m.rows ())});
218
+ });
219
+
220
+ // A matrix that uses a discontiguous underlying memory block.
221
+ class DiscontiguousMatrix : public Matrix {
222
+ public:
223
+ DiscontiguousMatrix (py::ssize_t rows, py::ssize_t cols,
224
+ py::ssize_t row_factor, py::ssize_t col_factor)
225
+ : Matrix(rows * row_factor, cols * col_factor),
226
+ m_row_factor (row_factor), m_col_factor(col_factor)
227
+ {
228
+ print_created (this ,
229
+ std::to_string (rows) + " (*" + std::to_string (row_factor) + " )x" +
230
+ std::to_string (cols) + " (*" + std::to_string (col_factor) + " ) matrix" );
231
+ }
232
+
233
+ ~DiscontiguousMatrix () {
234
+ print_destroyed (this ,
235
+ std::to_string (rows () / m_row_factor) + " (*" + std::to_string (m_row_factor) + " )x" +
236
+ std::to_string (cols () / m_col_factor) + " (*" + std::to_string (m_col_factor) + " ) matrix" );
237
+ }
238
+
239
+ float operator ()(py::ssize_t i, py::ssize_t j) const {
240
+ return Matrix::operator ()(i * m_row_factor, j * m_col_factor);
241
+ }
242
+
243
+ float &operator ()(py::ssize_t i, py::ssize_t j) {
244
+ return Matrix::operator ()(i * m_row_factor, j * m_col_factor);
245
+ }
246
+
247
+ using Matrix::data;
248
+
249
+ py::ssize_t rows () const { return Matrix::rows () / m_row_factor; }
250
+ py::ssize_t cols () const { return Matrix::cols () / m_col_factor; }
251
+ py::ssize_t row_factor () const { return m_row_factor; }
252
+ py::ssize_t col_factor () const { return m_col_factor; }
253
+
254
+ private:
255
+ py::ssize_t m_row_factor;
256
+ py::ssize_t m_col_factor;
257
+ };
258
+ py::class_<DiscontiguousMatrix, Matrix>(m, " DiscontiguousMatrix" , py::buffer_protocol ())
259
+ .def (py::init<py::ssize_t , py::ssize_t , py::ssize_t , py::ssize_t >())
260
+
261
+ .def (" rows" , &DiscontiguousMatrix::rows)
262
+ .def (" cols" , &DiscontiguousMatrix::cols)
263
+
264
+ // / Bare bones interface
265
+ .def (" __getitem__" ,
266
+ [](const DiscontiguousMatrix &m, std::pair<py::ssize_t , py::ssize_t > i) {
267
+ if (i.first >= m.rows () || i.second >= m.cols ()) {
268
+ throw py::index_error ();
269
+ }
270
+ return m (i.first , i.second );
271
+ })
272
+ .def (" __setitem__" ,
273
+ [](DiscontiguousMatrix &m, std::pair<py::ssize_t , py::ssize_t > i, float v) {
274
+ if (i.first >= m.rows () || i.second >= m.cols ()) {
275
+ throw py::index_error ();
276
+ }
277
+ m (i.first , i.second ) = v;
278
+ })
279
+ // / Provide buffer access
280
+ .def_buffer ([](DiscontiguousMatrix &m) -> py::buffer_info {
281
+ return py::buffer_info (
282
+ m.data (), /* Pointer to buffer */
283
+ {m.rows (), m.cols ()}, /* Buffer dimensions */
284
+ /* Strides (in bytes) for each index */
285
+ {size_t (m.col_factor ()) * sizeof (float ) * size_t (m.cols ()) * size_t (m.row_factor ()),
286
+ size_t (m.col_factor ()) * sizeof (float )});
287
+ });
288
+
170
289
class BrokenMatrix : public Matrix {
171
290
public:
172
291
BrokenMatrix (py::ssize_t rows, py::ssize_t cols) : Matrix(rows, cols) {}
@@ -274,6 +393,9 @@ TEST_SUBMODULE(buffers, m) {
274
393
m.attr (" PyBUF_ND" ) = PyBUF_ND;
275
394
m.attr (" PyBUF_STRIDES" ) = PyBUF_STRIDES;
276
395
m.attr (" PyBUF_INDIRECT" ) = PyBUF_INDIRECT;
396
+ m.attr (" PyBUF_C_CONTIGUOUS" ) = PyBUF_C_CONTIGUOUS;
397
+ m.attr (" PyBUF_F_CONTIGUOUS" ) = PyBUF_F_CONTIGUOUS;
398
+ m.attr (" PyBUF_ANY_CONTIGUOUS" ) = PyBUF_ANY_CONTIGUOUS;
277
399
278
400
m.def (" get_py_buffer" , [](const py::object &object, int flags) {
279
401
Py_buffer buffer;
0 commit comments