diff --git a/src/python/corrade/test/test_containers.py b/src/python/corrade/test/test_containers.py index 9d701d9..200299d 100644 --- a/src/python/corrade/test/test_containers.py +++ b/src/python/corrade/test/test_containers.py @@ -902,6 +902,35 @@ class StridedArrayViewCustomType(unittest.TestCase): # mutable_vector3d and mutable_long_float tested in test_containers_numpy # as memoryview can't handle their types +class StridedArrayViewCustomDynamicType(unittest.TestCase): + def test_float(self): + a = test_stridedarrayview.MutableContainerDynamicType('f') + self.assertEqual(a.view.size, (2, 3)) + self.assertEqual(a.view.stride, (12, 4)) + self.assertEqual(a.view.format, 'f') + a.view[0][1] = 15.0 + a.view[1][0] = -22.0 + self.assertEqual(a.view[0][0], 0.0) + self.assertEqual(a.view[0][1], 15.0) + self.assertEqual(a.view[0][2], 0.0) + self.assertEqual(a.view[1][0], -22.0) + self.assertEqual(a.view[1][1], 0.0) + self.assertEqual(a.view[1][2], 0.0) + + def test_int(self): + a = test_stridedarrayview.MutableContainerDynamicType('i') + self.assertEqual(a.view.size, (2, 3)) + self.assertEqual(a.view.stride, (12, 4)) + self.assertEqual(a.view.format, 'i') + a.view[0][2] = 15 + a.view[1][1] = -773 + self.assertEqual(a.view[0][0], 0) + self.assertEqual(a.view[0][1], 0) + self.assertEqual(a.view[0][2], 15) + self.assertEqual(a.view[1][0], 0) + self.assertEqual(a.view[1][1], -773) + self.assertEqual(a.view[1][2], 0) + class TestOptional(unittest.TestCase): def test_simple(self): self.assertIsNone(test_optional.simple_type(False)) diff --git a/src/python/corrade/test/test_containers_numpy.py b/src/python/corrade/test/test_containers_numpy.py index 7bd57c2..af07558 100644 --- a/src/python/corrade/test/test_containers_numpy.py +++ b/src/python/corrade/test/test_containers_numpy.py @@ -130,3 +130,28 @@ class StridedArrayViewCustomType(unittest.TestCase): (1001, 1.125), (4666025, -7.5) ]) + +class StridedArrayViewCustomDynamicType(unittest.TestCase): + def test_short_short(self): + a = test_stridedarrayview.MutableContainerDynamicType('hh') + self.assertEqual(a.view.size, (2, 3)) + self.assertEqual(a.view.stride, (12, 4)) + self.assertEqual(a.view.format, 'hh') + + # Test that numpy understands the type and has changes reflected + av = np.array(a.view, copy=False) + av[1][0] = (22563, -17665) + a.view[0][1] = (15, 34) + a.view[1][1] = (-22, 18) + # Converting to a tuple, otherwise numpy always compares to False + self.assertEqual(tuple(av[0][1]), (15, 34)) + self.assertEqual(tuple(av[1][0]), (22563, -17665)) + self.assertEqual(tuple(av[1][1]), (-22, 18)) + + # And the other way around as well + self.assertEqual(a.view[0][0], (0, 0)) + self.assertEqual(a.view[0][1], (15, 34)) + self.assertEqual(a.view[0][2], (0, 0)) + self.assertEqual(a.view[1][0], (22563, -17665)) + self.assertEqual(a.view[1][1], (-22, 18)) + self.assertEqual(a.view[1][2], (0, 0)) diff --git a/src/python/corrade/test/test_stridedarrayview.cpp b/src/python/corrade/test/test_stridedarrayview.cpp index 383793f..bd6cf04 100644 --- a/src/python/corrade/test/test_stridedarrayview.cpp +++ b/src/python/corrade/test/test_stridedarrayview.cpp @@ -57,6 +57,17 @@ template struct Container { T data[3*2]{}; }; +struct MutableContainerDynamicType { + explicit MutableContainerDynamicType(const std::string& format): format{format} {} + + Containers::StridedArrayView2D view() { + return {Containers::arrayView(data), {2, 3}, {12, 4}}; + } + + std::string format; + char data[3*2*4]{}; +}; + template void container(py::class_>& c) { c .def(py::init()) @@ -81,6 +92,41 @@ PYBIND11_MODULE(test_stridedarrayview, m) { container(mutableContainer3d); container(mutableContainerlf); + py::class_{m, "MutableContainerDynamicType"} + .def(py::init()) + .def_property_readonly("view", [](MutableContainerDynamicType & self) { + std::size_t itemsize; + py::object(*getitem)(const char*); + void(*setitem)(char*, py::handle); + if(self.format == "f") { + itemsize = 4; + getitem = [](const char* item) { + return py::cast(*reinterpret_cast(item)); + }; + setitem = [](char* item, py::handle object) { + *reinterpret_cast(item) = py::cast(object); + }; + } else if(self.format == "i") { + itemsize = 4; + getitem = [](const char* item) { + return py::cast(*reinterpret_cast(item)); + }; + setitem = [](char* item, py::handle object) { + *reinterpret_cast(item) = py::cast(object); + }; + } else if(self.format == "hh") { + itemsize = 4; + getitem = [](const char* item) { + return py::cast(*reinterpret_cast*>(item)); + }; + setitem = [](char* item, py::handle object) { + *reinterpret_cast*>(item) = py::cast>(object); + }; + } else throw py::attribute_error{}; + + return Containers::pyArrayViewHolder(Containers::PyStridedArrayView<2, char>{Containers::arrayCast(self.view()), self.format.data(), itemsize, getitem, setitem}, py::cast(self)); + }); + m.def("get_containers", []() { return Container{3, -17565, 5}; });