@@ -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 ,
175
+ std::to_string (rows) + " x" + std::to_string (cols) + " Fortran matrix" );
176
+ }
177
+
178
+ float operator ()(py::ssize_t i, py::ssize_t j) const { return Matrix::operator ()(j, i); }
179
+
180
+ float &operator ()(py::ssize_t i, py::ssize_t j) { return Matrix::operator ()(j, i); }
181
+
182
+ using Matrix::data;
183
+
184
+ py::ssize_t rows () const { return Matrix::cols (); }
185
+ py::ssize_t cols () const { return Matrix::rows (); }
186
+ };
187
+ py::class_<FortranMatrix, Matrix>(m, " FortranMatrix" , py::buffer_protocol ())
188
+ .def (py::init<py::ssize_t , py::ssize_t >())
189
+
190
+ .def (" rows" , &FortranMatrix::rows)
191
+ .def (" cols" , &FortranMatrix::cols)
192
+
193
+ // / Bare bones interface
194
+ .def (" __getitem__" ,
195
+ [](const FortranMatrix &m, std::pair<py::ssize_t , py::ssize_t > i) {
196
+ if (i.first >= m.rows () || i.second >= m.cols ()) {
197
+ throw py::index_error ();
198
+ }
199
+ return m (i.first , i.second );
200
+ })
201
+ .def (" __setitem__" ,
202
+ [](FortranMatrix &m, std::pair<py::ssize_t , py::ssize_t > i, float v) {
203
+ if (i.first >= m.rows () || i.second >= m.cols ()) {
204
+ throw py::index_error ();
205
+ }
206
+ m (i.first , i.second ) = v;
207
+ })
208
+ // / Provide buffer access
209
+ .def_buffer ([](FortranMatrix &m) -> py::buffer_info {
210
+ return py::buffer_info (m.data (), /* Pointer to buffer */
211
+ {m.rows (), m.cols ()}, /* Buffer dimensions */
212
+ /* Strides (in bytes) for each index */
213
+ {sizeof (float ), sizeof (float ) * size_t (m.rows ())});
214
+ });
215
+
216
+ // A matrix that uses a discontiguous underlying memory block.
217
+ class DiscontiguousMatrix : public Matrix {
218
+ public:
219
+ DiscontiguousMatrix (py::ssize_t rows,
220
+ py::ssize_t cols,
221
+ py::ssize_t row_factor,
222
+ py::ssize_t col_factor)
223
+ : Matrix(rows * row_factor, cols * col_factor), m_row_factor(row_factor),
224
+ m_col_factor (col_factor) {
225
+ print_created (this ,
226
+ std::to_string (rows) + " (*" + std::to_string (row_factor) + " )x"
227
+ + std::to_string (cols) + " (*" + std::to_string (col_factor)
228
+ + " ) matrix" );
229
+ }
230
+
231
+ ~DiscontiguousMatrix () {
232
+ print_destroyed (this ,
233
+ std::to_string (rows () / m_row_factor) + " (*"
234
+ + std::to_string (m_row_factor) + " )x"
235
+ + std::to_string (cols () / m_col_factor) + " (*"
236
+ + 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 (m.data (), /* Pointer to buffer */
282
+ {m.rows (), m.cols ()}, /* Buffer dimensions */
283
+ /* Strides (in bytes) for each index */
284
+ {size_t (m.col_factor ()) * sizeof (float ) * size_t (m.cols ())
285
+ * 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