Browse Source

python: expose the new expanded() API on strided (bit) array views.

Not collapsed() yet, as it has the return type depending on the count
parameter, and I'm not yet decided how to express that here.
next
Vladimír Vondruš 3 years ago
parent
commit
6d8ab441e8
  1. 48
      doc/python/corrade.containers.rst
  2. 4
      src/Corrade/Containers/StridedArrayViewPythonBindings.h
  3. 137
      src/python/corrade/containers.cpp
  4. 146
      src/python/corrade/test/test_containers.py

48
doc/python/corrade.containers.rst

@ -104,6 +104,10 @@
:raise IndexError: if :p:`dimension` is not :py:`0` :raise IndexError: if :p:`dimension` is not :py:`0`
.. py:function:: corrade.containers.StridedArrayView1D.broadcasted .. py:function:: corrade.containers.StridedArrayView1D.broadcasted
:raise IndexError: if :p:`dimension` is not :py:`0` :raise IndexError: if :p:`dimension` is not :py:`0`
.. py:function:: corrade.containers.StridedArrayView1D.expanded
:raise IndexError: if :p:`dimension` is not :py:`0`
:raise ValueError: if product of :p:`size` is not equal to size in
:p:`dimension`
.. py:class:: corrade.containers.MutableStridedArrayView1D .. py:class:: corrade.containers.MutableStridedArrayView1D
@ -114,6 +118,10 @@
:raise IndexError: if :p:`dimension` is not :py:`0` :raise IndexError: if :p:`dimension` is not :py:`0`
.. py:function:: corrade.containers.MutableStridedArrayView1D.broadcasted .. py:function:: corrade.containers.MutableStridedArrayView1D.broadcasted
:raise IndexError: if :p:`dimension` is not :py:`0` :raise IndexError: if :p:`dimension` is not :py:`0`
.. py:function:: corrade.containers.MutableStridedArrayView1D.expanded
:raise IndexError: if :p:`dimension` is not :py:`0`
:raise ValueError: if product of :p:`size` is not equal to size in
:p:`dimension`
.. py:class:: corrade.containers.StridedArrayView2D .. py:class:: corrade.containers.StridedArrayView2D
@ -126,6 +134,10 @@
.. py:function:: corrade.containers.StridedArrayView2D.transposed .. py:function:: corrade.containers.StridedArrayView2D.transposed
:raise IndexError: if :p:`a` or :p:`b` is not :py:`0` or :py:`1` or if :raise IndexError: if :p:`a` or :p:`b` is not :py:`0` or :py:`1` or if
they're the same they're the same
.. py:function:: corrade.containers.StridedArrayView2D.expanded
:raise IndexError: if :p:`dimension` is not :py:`0` or :py:`1`
:raise ValueError: if product of :p:`size` is not equal to size in
:p:`dimension`
.. py:class:: corrade.containers.MutableStridedArrayView2D .. py:class:: corrade.containers.MutableStridedArrayView2D
@ -139,6 +151,10 @@
.. py:function:: corrade.containers.MutableStridedArrayView2D.transposed .. py:function:: corrade.containers.MutableStridedArrayView2D.transposed
:raise IndexError: if :p:`a` or :p:`b` is not :py:`0` or :py:`1` or if :raise IndexError: if :p:`a` or :p:`b` is not :py:`0` or :py:`1` or if
they're the same they're the same
.. py:function:: corrade.containers.MutableStridedArrayView2D.expanded
:raise IndexError: if :p:`dimension` is not :py:`0` or :py:`1`
:raise ValueError: if product of :p:`size` is not equal to size in
:p:`dimension`
.. py:class:: corrade.containers.StridedArrayView3D .. py:class:: corrade.containers.StridedArrayView3D
@ -151,6 +167,10 @@
.. py:function:: corrade.containers.StridedArrayView3D.transposed .. py:function:: corrade.containers.StridedArrayView3D.transposed
:raise IndexError: if :p:`a` or :p:`b` is not :py:`0`, :py:`1` or :py:`2` :raise IndexError: if :p:`a` or :p:`b` is not :py:`0`, :py:`1` or :py:`2`
or if they're the same or if they're the same
.. py:function:: corrade.containers.StridedArrayView3D.expanded
:raise IndexError: if :p:`dimension` is not :py:`0`, :py:`1` or :py:`2`
:raise ValueError: if product of :p:`size` is not equal to size in
:p:`dimension`
.. py:class:: corrade.containers.MutableStridedArrayView3D .. py:class:: corrade.containers.MutableStridedArrayView3D
@ -164,6 +184,10 @@
.. py:function:: corrade.containers.MutableStridedArrayView3D.transposed .. py:function:: corrade.containers.MutableStridedArrayView3D.transposed
:raise IndexError: if :p:`a` or :p:`b` is not :py:`0`, :py:`1` or :py:`2` :raise IndexError: if :p:`a` or :p:`b` is not :py:`0`, :py:`1` or :py:`2`
or if they're the same or if they're the same
.. py:function:: corrade.containers.MutableStridedArrayView3D.expanded
:raise IndexError: if :p:`dimension` is not :py:`0`, :py:`1` or :py:`2`
:raise ValueError: if product of :p:`size` is not equal to size in
:p:`dimension`
.. py:class:: corrade.containers.StridedArrayView4D .. py:class:: corrade.containers.StridedArrayView4D
@ -245,6 +269,10 @@
:raise IndexError: if :p:`dimension` is not :py:`0` :raise IndexError: if :p:`dimension` is not :py:`0`
.. py:function:: corrade.containers.StridedBitArrayView1D.broadcasted .. py:function:: corrade.containers.StridedBitArrayView1D.broadcasted
:raise IndexError: if :p:`dimension` is not :py:`0` :raise IndexError: if :p:`dimension` is not :py:`0`
.. py:function:: corrade.containers.StridedBitArrayView1D.expanded
:raise IndexError: if :p:`dimension` is not :py:`0`
:raise ValueError: if product of :p:`size` is not equal to size in
:p:`dimension`
.. py:class:: corrade.containers.MutableStridedBitArrayView1D .. py:class:: corrade.containers.MutableStridedBitArrayView1D
@ -255,6 +283,10 @@
:raise IndexError: if :p:`dimension` is not :py:`0` :raise IndexError: if :p:`dimension` is not :py:`0`
.. py:function:: corrade.containers.MutableStridedBitArrayView1D.broadcasted .. py:function:: corrade.containers.MutableStridedBitArrayView1D.broadcasted
:raise IndexError: if :p:`dimension` is not :py:`0` :raise IndexError: if :p:`dimension` is not :py:`0`
.. py:function:: corrade.containers.MutableStridedBitArrayView1D.expanded
:raise IndexError: if :p:`dimension` is not :py:`0`
:raise ValueError: if product of :p:`size` is not equal to size in
:p:`dimension`
.. py:class:: corrade.containers.StridedBitArrayView2D .. py:class:: corrade.containers.StridedBitArrayView2D
@ -267,6 +299,10 @@
.. py:function:: corrade.containers.StridedBitArrayView2D.transposed .. py:function:: corrade.containers.StridedBitArrayView2D.transposed
:raise IndexError: if :p:`a` or :p:`b` is not :py:`0` or :py:`1` or if :raise IndexError: if :p:`a` or :p:`b` is not :py:`0` or :py:`1` or if
they're the same they're the same
.. py:function:: corrade.containers.StridedBitArrayView2D.expanded
:raise IndexError: if :p:`dimension` is not :py:`0` or :py:`1`
:raise ValueError: if product of :p:`size` is not equal to size in
:p:`dimension`
.. py:class:: corrade.containers.MutableStridedBitArrayView2D .. py:class:: corrade.containers.MutableStridedBitArrayView2D
@ -280,6 +316,10 @@
.. py:function:: corrade.containers.MutableStridedBitArrayView2D.transposed .. py:function:: corrade.containers.MutableStridedBitArrayView2D.transposed
:raise IndexError: if :p:`a` or :p:`b` is not :py:`0` or :py:`1` or if :raise IndexError: if :p:`a` or :p:`b` is not :py:`0` or :py:`1` or if
they're the same they're the same
.. py:function:: corrade.containers.MutableStridedBitArrayView2D.expanded
:raise IndexError: if :p:`dimension` is not :py:`0` or :py:`1`
:raise ValueError: if product of :p:`size` is not equal to size in
:p:`dimension`
.. py:class:: corrade.containers.StridedBitArrayView3D .. py:class:: corrade.containers.StridedBitArrayView3D
@ -292,6 +332,10 @@
.. py:function:: corrade.containers.StridedBitArrayView3D.transposed .. py:function:: corrade.containers.StridedBitArrayView3D.transposed
:raise IndexError: if :p:`a` or :p:`b` is not :py:`0`, :py:`1` or :py:`2` :raise IndexError: if :p:`a` or :p:`b` is not :py:`0`, :py:`1` or :py:`2`
or if they're the same or if they're the same
.. py:function:: corrade.containers.StridedBitArrayView3D.expanded
:raise IndexError: if :p:`dimension` is not :py:`0`, :py:`1` or :py:`2`
:raise ValueError: if product of :p:`size` is not equal to size in
:p:`dimension`
.. py:class:: corrade.containers.MutableStridedBitArrayView3D .. py:class:: corrade.containers.MutableStridedBitArrayView3D
@ -305,6 +349,10 @@
.. py:function:: corrade.containers.MutableStridedBitArrayView3D.transposed .. py:function:: corrade.containers.MutableStridedBitArrayView3D.transposed
:raise IndexError: if :p:`a` or :p:`b` is not :py:`0`, :py:`1` or :py:`2` :raise IndexError: if :p:`a` or :p:`b` is not :py:`0`, :py:`1` or :py:`2`
or if they're the same or if they're the same
.. py:function:: corrade.containers.MutableStridedBitArrayView3D.expanded
:raise IndexError: if :p:`dimension` is not :py:`0`, :py:`1` or :py:`2`
:raise ValueError: if product of :p:`size` is not equal to size in
:p:`dimension`
.. py:class:: corrade.containers.StridedBitArrayView4D .. py:class:: corrade.containers.StridedBitArrayView4D

4
src/Corrade/Containers/StridedArrayViewPythonBindings.h

@ -133,6 +133,10 @@ template<unsigned dimensions, class T> class PyStridedArrayView: public StridedA
return PyStridedArrayView<dimensions, T>{StridedArrayView<dimensions, T>::template broadcasted<dimension>(size), format, itemsize, getitem, setitem}; return PyStridedArrayView<dimensions, T>{StridedArrayView<dimensions, T>::template broadcasted<dimension>(size), format, itemsize, getitem, setitem};
} }
template<unsigned dimension, unsigned count> PyStridedArrayView<dimensions + count - 1, T> expanded(const Containers::Size<count>& size) const {
return PyStridedArrayView<dimensions + count - 1, T>{StridedArrayView<dimensions, T>::template expanded<dimension>(size), format, itemsize, getitem, setitem};
}
/* has to be public as it's accessed by the bindings directly */ /* has to be public as it's accessed by the bindings directly */
const char* format; const char* format;
std::size_t itemsize; std::size_t itemsize;

137
src/python/corrade/containers.cpp

@ -374,6 +374,23 @@ template<> struct StridedOperation<1> {
PyErr_Format(PyExc_IndexError, "dimension %u out of range for a %iD view", dimension, dimensions); PyErr_Format(PyExc_IndexError, "dimension %u out of range for a %iD view", dimension, dimensions);
throw py::error_already_set{}; throw py::error_already_set{};
} }
template<unsigned count, template<unsigned, class> class View, unsigned dimensions, class T> static View<dimensions + count - 1, T> expanded(const View<dimensions, T>& view, unsigned dimension, const typename DimensionsTuple<count, std::size_t>::Type& size) {
if(dimension == 0) {
Containers::Size<count> iSize{NoInit};
std::size_t totalSize = 1;
for(std::size_t i = 0; i != count; ++i) {
iSize[i] = dimensionsTupleGet<std::size_t>(size, i);
totalSize *= iSize[i];
}
if(totalSize != Containers::Size<dimensions>{view.size()}[0]) {
PyErr_Format(PyExc_ValueError, "total size %zu doesn't match dimension %u with %zu elements", totalSize, dimension, Containers::Size<dimensions>{view.size()}[0]);
throw py::error_already_set{};
}
return view.template expanded<0>(iSize);
}
PyErr_Format(PyExc_IndexError, "dimension %u out of range for a %iD view", dimension, dimensions);
throw py::error_already_set{};
}
}; };
template<> struct StridedOperation<2> { template<> struct StridedOperation<2> {
template<template<unsigned, class> class View, unsigned dimensions, class T> static View<dimensions, T> transposed(const View<dimensions, T>& view, unsigned a, unsigned b) { template<template<unsigned, class> class View, unsigned dimensions, class T> static View<dimensions, T> transposed(const View<dimensions, T>& view, unsigned a, unsigned b) {
@ -398,6 +415,22 @@ template<> struct StridedOperation<2> {
} }
return StridedOperation<1>::broadcasted(view, dimension, size); return StridedOperation<1>::broadcasted(view, dimension, size);
} }
template<unsigned count, template<unsigned, class> class View, unsigned dimensions, class T> static View<dimensions + count - 1, T> expanded(const View<dimensions, T>& view, unsigned dimension, const typename DimensionsTuple<count, std::size_t>::Type& size) {
if(dimension == 1) {
Containers::Size<count> iSize{NoInit};
std::size_t totalSize = 1;
for(std::size_t i = 0; i != count; ++i) {
iSize[i] = dimensionsTupleGet<std::size_t>(size, i);
totalSize *= iSize[i];
}
if(totalSize != view.size()[1]) {
PyErr_Format(PyExc_ValueError, "total size %zu doesn't match dimension %u with %zu elements", totalSize, dimension, view.size()[1]);
throw py::error_already_set{};
}
return view.template expanded<1>(iSize);
}
return StridedOperation<1>::expanded<count>(view, dimension, size);
}
}; };
template<> struct StridedOperation<3> { template<> struct StridedOperation<3> {
template<template<unsigned, class> class View, unsigned dimensions, class T> static View<dimensions, T> transposed(const View<dimensions, T>& view, unsigned a, unsigned b) { template<template<unsigned, class> class View, unsigned dimensions, class T> static View<dimensions, T> transposed(const View<dimensions, T>& view, unsigned a, unsigned b) {
@ -424,6 +457,22 @@ template<> struct StridedOperation<3> {
} }
return StridedOperation<2>::broadcasted(view, dimension, size); return StridedOperation<2>::broadcasted(view, dimension, size);
} }
template<unsigned count, template<unsigned, class> class View, unsigned dimensions, class T> static View<dimensions + count - 1, T> expanded(const View<dimensions, T>& view, unsigned dimension, const typename DimensionsTuple<count, std::size_t>::Type& size) {
if(dimension == 2) {
Containers::Size<count> iSize{NoInit};
std::size_t totalSize = 1;
for(std::size_t i = 0; i != count; ++i) {
iSize[i] = dimensionsTupleGet<std::size_t>(size, i);
totalSize *= iSize[i];
}
if(totalSize != view.size()[2]) {
PyErr_Format(PyExc_ValueError, "total size %zu doesn't match dimension %u with %zu elements", totalSize, dimension, view.size()[2]);
throw py::error_already_set{};
}
return view.template expanded<2>(iSize);
}
return StridedOperation<2>::expanded<count>(view, dimension, size);
}
}; };
template<> struct StridedOperation<4> { template<> struct StridedOperation<4> {
template<template<unsigned, class> class View, unsigned dimensions, class T> static View<dimensions, T> transposed(const View<dimensions, T>& view, unsigned a, unsigned b) { template<template<unsigned, class> class View, unsigned dimensions, class T> static View<dimensions, T> transposed(const View<dimensions, T>& view, unsigned a, unsigned b) {
@ -453,6 +502,22 @@ template<> struct StridedOperation<4> {
} }
return StridedOperation<3>::broadcasted(view, dimension, size); return StridedOperation<3>::broadcasted(view, dimension, size);
} }
template<unsigned count, template<unsigned, class> class View, unsigned dimensions, class T> static View<dimensions + count - 1, T> expanded(const View<dimensions, T>& view, unsigned dimension, const typename DimensionsTuple<count, std::size_t>::Type& size) {
if(dimension == 3) {
Containers::Size<count> iSize{NoInit};
std::size_t totalSize = 1;
for(std::size_t i = 0; i != count; ++i) {
iSize[i] = dimensionsTupleGet<std::size_t>(size, i);
totalSize *= iSize[i];
}
if(totalSize != view.size()[3]) {
PyErr_Format(PyExc_ValueError, "total size %zu doesn't match dimension %u with %zu elements", totalSize, dimension, view.size()[3]);
throw py::error_already_set{};
}
return view.template expanded<3>(iSize);
}
return StridedOperation<3>::expanded<count>(view, dimension, size);
}
}; };
template<unsigned dimensions, template<unsigned> class Steps, class T> Containers::PyArrayViewHolder<T> stridedArrayViewSlice(const T& self, const typename DimensionsTuple<dimensions, py::slice>::Type& slice, py::object owner) { template<unsigned dimensions, template<unsigned> class Steps, class T> Containers::PyArrayViewHolder<T> stridedArrayViewSlice(const T& self, const typename DimensionsTuple<dimensions, py::slice>::Type& slice, py::object owner) {
@ -589,7 +654,37 @@ template<class T> void stridedArrayView1D(py::class_<Containers::PyStridedArrayV
throw py::error_already_set{}; throw py::error_already_set{};
} }
return self.getitem(&self[i]); return self.getitem(&self[i]);
}, "Value at given position", py::arg("i")); }, "Value at given position", py::arg("i"))
/* Fancy operations */
.def("expanded", [](const Containers::PyStridedArrayView<1, T>& self, unsigned dimension, const std::tuple<std::size_t, std::size_t>& size) {
return Containers::pyArrayViewHolder(StridedOperation<1>::expanded<2>(self, dimension, size), pyObjectHolderFor<Containers::PyArrayViewHolder>(self).owner);
}, "Expand a dimension", py::arg("dimension"), py::arg("size"))
.def("expanded", [](const Containers::PyStridedArrayView<1, T>& self, unsigned dimension, const std::tuple<std::size_t, std::size_t, std::size_t>& size) {
return Containers::pyArrayViewHolder(StridedOperation<1>::expanded<3>(self, dimension, size), pyObjectHolderFor<Containers::PyArrayViewHolder>(self).owner);
}, "Expand a dimension", py::arg("dimension"), py::arg("size"))
.def("expanded", [](const Containers::PyStridedArrayView<1, T>& self, unsigned dimension, const std::tuple<std::size_t, std::size_t, std::size_t, std::size_t>& size) {
return Containers::pyArrayViewHolder(StridedOperation<1>::expanded<4>(self, dimension, size), pyObjectHolderFor<Containers::PyArrayViewHolder>(self).owner);
}, "Expand a dimension", py::arg("dimension"), py::arg("size"));
}
template<class T> void stridedArrayView2D(py::class_<Containers::PyStridedArrayView<2, T>, Containers::PyArrayViewHolder<Containers::PyStridedArrayView<2, T>>>& c) {
c
/* Fancy operations */
.def("expanded", [](const Containers::PyStridedArrayView<2, T>& self, unsigned dimension, const std::tuple<std::size_t, std::size_t>& size) {
return Containers::pyArrayViewHolder(StridedOperation<2>::expanded<2>(self, dimension, size), pyObjectHolderFor<Containers::PyArrayViewHolder>(self).owner);
}, "Expand a dimension", py::arg("dimension"), py::arg("size"))
.def("expanded", [](const Containers::PyStridedArrayView<2, T>& self, unsigned dimension, const std::tuple<std::size_t, std::size_t, std::size_t>& size) {
return Containers::pyArrayViewHolder(StridedOperation<2>::expanded<3>(self, dimension, size), pyObjectHolderFor<Containers::PyArrayViewHolder>(self).owner);
}, "Expand a dimension", py::arg("dimension"), py::arg("size"));
}
template<class T> void stridedArrayView3D(py::class_<Containers::PyStridedArrayView<3, T>, Containers::PyArrayViewHolder<Containers::PyStridedArrayView<3, T>>>& c) {
c
/* Fancy operations */
.def("expanded", [](const Containers::PyStridedArrayView<3, T>& self, unsigned dimension, const std::tuple<std::size_t, std::size_t>& size) {
return Containers::pyArrayViewHolder(StridedOperation<3>::expanded<2>(self, dimension, size), pyObjectHolderFor<Containers::PyArrayViewHolder>(self).owner);
}, "Expand a dimension", py::arg("dimension"), py::arg("size"));
} }
template<unsigned dimensions, class T> void stridedArrayViewND(py::class_<Containers::PyStridedArrayView<dimensions, T>, Containers::PyArrayViewHolder<Containers::PyStridedArrayView<dimensions, T>>>& c) { template<unsigned dimensions, class T> void stridedArrayViewND(py::class_<Containers::PyStridedArrayView<dimensions, T>, Containers::PyArrayViewHolder<Containers::PyStridedArrayView<dimensions, T>>>& c) {
@ -695,7 +790,37 @@ template<class T> void stridedBitArrayView1D(py::class_<Containers::BasicStrided
throw py::error_already_set{}; throw py::error_already_set{};
} }
return self[i]; return self[i];
}, "Bit at given position", py::arg("i")); }, "Bit at given position", py::arg("i"))
/* Fancy operations */
.def("expanded", [](const Containers::BasicStridedBitArrayView<1, T>& self, unsigned dimension, const std::tuple<std::size_t, std::size_t>& size) {
return Containers::pyArrayViewHolder(StridedOperation<1>::expanded<2>(self, dimension, size), pyObjectHolderFor<Containers::PyArrayViewHolder>(self).owner);
}, "Expand a dimension", py::arg("dimension"), py::arg("size"))
.def("expanded", [](const Containers::BasicStridedBitArrayView<1, T>& self, unsigned dimension, const std::tuple<std::size_t, std::size_t, std::size_t>& size) {
return Containers::pyArrayViewHolder(StridedOperation<1>::expanded<3>(self, dimension, size), pyObjectHolderFor<Containers::PyArrayViewHolder>(self).owner);
}, "Expand a dimension", py::arg("dimension"), py::arg("size"))
.def("expanded", [](const Containers::BasicStridedBitArrayView<1, T>& self, unsigned dimension, const std::tuple<std::size_t, std::size_t, std::size_t, std::size_t>& size) {
return Containers::pyArrayViewHolder(StridedOperation<1>::expanded<4>(self, dimension, size), pyObjectHolderFor<Containers::PyArrayViewHolder>(self).owner);
}, "Expand a dimension", py::arg("dimension"), py::arg("size"));
}
template<class T> void stridedBitArrayView2D(py::class_<Containers::BasicStridedBitArrayView<2, T>, Containers::PyArrayViewHolder<Containers::BasicStridedBitArrayView<2, T>>>& c) {
c
/* Fancy operations */
.def("expanded", [](const Containers::BasicStridedBitArrayView<2, T>& self, unsigned dimension, const std::tuple<std::size_t, std::size_t>& size) {
return Containers::pyArrayViewHolder(StridedOperation<2>::expanded<2>(self, dimension, size), pyObjectHolderFor<Containers::PyArrayViewHolder>(self).owner);
}, "Expand a dimension", py::arg("dimension"), py::arg("size"))
.def("expanded", [](const Containers::BasicStridedBitArrayView<2, T>& self, unsigned dimension, const std::tuple<std::size_t, std::size_t, std::size_t>& size) {
return Containers::pyArrayViewHolder(StridedOperation<2>::expanded<3>(self, dimension, size), pyObjectHolderFor<Containers::PyArrayViewHolder>(self).owner);
}, "Expand a dimension", py::arg("dimension"), py::arg("size"));
}
template<class T> void stridedBitArrayView3D(py::class_<Containers::BasicStridedBitArrayView<3, T>, Containers::PyArrayViewHolder<Containers::BasicStridedBitArrayView<3, T>>>& c) {
c
/* Fancy operations */
.def("expanded", [](const Containers::BasicStridedBitArrayView<3, T>& self, unsigned dimension, const std::tuple<std::size_t, std::size_t>& size) {
return Containers::pyArrayViewHolder(StridedOperation<3>::expanded<2>(self, dimension, size), pyObjectHolderFor<Containers::PyArrayViewHolder>(self).owner);
}, "Expand a dimension", py::arg("dimension"), py::arg("size"));
} }
template<unsigned dimensions, class T> void stridedBitArrayViewND(py::class_<Containers::BasicStridedBitArrayView<dimensions, T>, Containers::PyArrayViewHolder<Containers::BasicStridedBitArrayView<dimensions, T>>>& c) { template<unsigned dimensions, class T> void stridedBitArrayViewND(py::class_<Containers::BasicStridedBitArrayView<dimensions, T>, Containers::PyArrayViewHolder<Containers::BasicStridedBitArrayView<dimensions, T>>>& c) {
@ -852,8 +977,10 @@ void containers(py::module_& m) {
return pyArrayViewHolder(Containers::StridedBitArrayView1D{other}, pyObjectHolderFor<Containers::PyArrayViewHolder>(other).owner); return pyArrayViewHolder(Containers::StridedBitArrayView1D{other}, pyObjectHolderFor<Containers::PyArrayViewHolder>(other).owner);
}), "Construct from a bit array view", py::arg("view")); }), "Construct from a bit array view", py::arg("view"));
stridedBitArrayView(stridedBitArrayView2D_); stridedBitArrayView(stridedBitArrayView2D_);
stridedBitArrayView2D(stridedBitArrayView2D_);
stridedBitArrayViewND(stridedBitArrayView2D_); stridedBitArrayViewND(stridedBitArrayView2D_);
stridedBitArrayView(stridedBitArrayView3D_); stridedBitArrayView(stridedBitArrayView3D_);
stridedBitArrayView3D(stridedBitArrayView3D_);
stridedBitArrayViewND(stridedBitArrayView3D_); stridedBitArrayViewND(stridedBitArrayView3D_);
stridedBitArrayView(stridedBitArrayView4D_); stridedBitArrayView(stridedBitArrayView4D_);
stridedBitArrayViewND(stridedBitArrayView4D_); stridedBitArrayViewND(stridedBitArrayView4D_);
@ -869,8 +996,10 @@ void containers(py::module_& m) {
stridedBitArrayView(mutableStridedBitArrayView1D_); stridedBitArrayView(mutableStridedBitArrayView1D_);
stridedBitArrayView1D(mutableStridedBitArrayView1D_); stridedBitArrayView1D(mutableStridedBitArrayView1D_);
stridedBitArrayView(mutableStridedBitArrayView2D_); stridedBitArrayView(mutableStridedBitArrayView2D_);
stridedBitArrayView2D(mutableStridedBitArrayView2D_);
stridedBitArrayViewND(mutableStridedBitArrayView2D_); stridedBitArrayViewND(mutableStridedBitArrayView2D_);
stridedBitArrayView(mutableStridedBitArrayView3D_); stridedBitArrayView(mutableStridedBitArrayView3D_);
stridedBitArrayView3D(mutableStridedBitArrayView3D_);
stridedBitArrayViewND(mutableStridedBitArrayView3D_); stridedBitArrayViewND(mutableStridedBitArrayView3D_);
stridedBitArrayView(mutableStridedBitArrayView4D_); stridedBitArrayView(mutableStridedBitArrayView4D_);
stridedBitArrayViewND(mutableStridedBitArrayView4D_); stridedBitArrayViewND(mutableStridedBitArrayView4D_);
@ -897,8 +1026,10 @@ void containers(py::module_& m) {
stridedArrayView(stridedArrayView1D_); stridedArrayView(stridedArrayView1D_);
stridedArrayView1D(stridedArrayView1D_); stridedArrayView1D(stridedArrayView1D_);
stridedArrayView(stridedArrayView2D_); stridedArrayView(stridedArrayView2D_);
stridedArrayView2D(stridedArrayView2D_);
stridedArrayViewND(stridedArrayView2D_); stridedArrayViewND(stridedArrayView2D_);
stridedArrayView(stridedArrayView3D_); stridedArrayView(stridedArrayView3D_);
stridedArrayView3D(stridedArrayView3D_);
stridedArrayViewND(stridedArrayView3D_); stridedArrayViewND(stridedArrayView3D_);
stridedArrayView(stridedArrayView4D_); stridedArrayView(stridedArrayView4D_);
stridedArrayViewND(stridedArrayView4D_); stridedArrayViewND(stridedArrayView4D_);
@ -914,8 +1045,10 @@ void containers(py::module_& m) {
stridedArrayView(mutableStridedArrayView1D_); stridedArrayView(mutableStridedArrayView1D_);
stridedArrayView1D(mutableStridedArrayView1D_); stridedArrayView1D(mutableStridedArrayView1D_);
stridedArrayView(mutableStridedArrayView2D_); stridedArrayView(mutableStridedArrayView2D_);
stridedArrayView2D(mutableStridedArrayView2D_);
stridedArrayViewND(mutableStridedArrayView2D_); stridedArrayViewND(mutableStridedArrayView2D_);
stridedArrayView(mutableStridedArrayView3D_); stridedArrayView(mutableStridedArrayView3D_);
stridedArrayView3D(mutableStridedArrayView3D_);
stridedArrayViewND(mutableStridedArrayView3D_); stridedArrayViewND(mutableStridedArrayView3D_);
stridedArrayView(mutableStridedArrayView4D_); stridedArrayView(mutableStridedArrayView4D_);
stridedArrayViewND(mutableStridedArrayView4D_); stridedArrayViewND(mutableStridedArrayView4D_);

146
src/python/corrade/test/test_containers.py

@ -410,6 +410,24 @@ class StridedArrayView1D(unittest.TestCase):
self.assertEqual(c.stride, (0,)) self.assertEqual(c.stride, (0,))
self.assertEqual(bytes(c), b'33333') self.assertEqual(bytes(c), b'33333')
d2 = containers.StridedArrayView1D(a).expanded(0, (2, 4))
self.assertIsInstance(d2, containers.StridedArrayView2D)
self.assertEqual(d2.size, (2, 4))
self.assertEqual(d2.stride, (4, 1))
self.assertEqual(bytes(d2), b'01234567')
d3 = containers.StridedArrayView1D(a).expanded(0, (2, 2, 2))
self.assertIsInstance(d3, containers.StridedArrayView3D)
self.assertEqual(d3.size, (2, 2, 2))
self.assertEqual(d3.stride, (4, 2, 1))
self.assertEqual(bytes(d3), b'01234567')
d4 = containers.StridedArrayView1D(a).expanded(0, (2, 1, 2, 2))
self.assertIsInstance(d4, containers.StridedArrayView4D)
self.assertEqual(d4.size, (2, 1, 2, 2))
self.assertEqual(d4.stride, (4, 4, 2, 1))
self.assertEqual(bytes(d4), b'01234567')
def test_ops_invalid(self): def test_ops_invalid(self):
a = b'00' a = b'00'
@ -419,8 +437,12 @@ class StridedArrayView1D(unittest.TestCase):
containers.StridedArrayView1D().flipped(1) containers.StridedArrayView1D().flipped(1)
with self.assertRaisesRegex(IndexError, "dimension 1 out of range for a 1D view"): with self.assertRaisesRegex(IndexError, "dimension 1 out of range for a 1D view"):
containers.StridedArrayView1D(a).broadcasted(1, 3) containers.StridedArrayView1D(a).broadcasted(1, 3)
with self.assertRaisesRegex(IndexError, "dimension 1 out of range for a 1D view"):
containers.StridedArrayView1D(a).expanded(1, (1, 2))
with self.assertRaisesRegex(ValueError, "can't broadcast dimension 0 with 2 elements"): with self.assertRaisesRegex(ValueError, "can't broadcast dimension 0 with 2 elements"):
containers.StridedArrayView1D(a).broadcasted(0, 3) containers.StridedArrayView1D(a).broadcasted(0, 3)
with self.assertRaisesRegex(ValueError, "total size 3 doesn't match dimension 0 with 2 elements"):
containers.StridedArrayView1D(a).expanded(0, (1, 3))
def test_convert_memoryview(self): def test_convert_memoryview(self):
a = b'World is hell!' a = b'World is hell!'
@ -722,6 +744,18 @@ class StridedArrayView2D(unittest.TestCase):
self.assertEqual(d.stride, (8, 0)) self.assertEqual(d.stride, (8, 0))
self.assertEqual(bytes(d), b'3377bb') self.assertEqual(bytes(d), b'3377bb')
e3 = containers.StridedArrayView2D(v).expanded(1, (2, 4))
self.assertIsInstance(e3, containers.StridedArrayView3D)
self.assertEqual(e3.size, (3, 2, 4))
self.assertEqual(e3.stride, (8, 4, 1))
self.assertEqual(bytes(e3), b'01234567456789ab89abcdef')
e4 = containers.StridedArrayView2D(v).expanded(0, (1, 3, 1))
self.assertIsInstance(e4, containers.StridedArrayView4D)
self.assertEqual(e4.size, (1, 3, 1, 8))
self.assertEqual(e4.stride, (24, 8, 8, 1))
self.assertEqual(bytes(e4), b'01234567456789ab89abcdef')
def test_ops_invalid(self): def test_ops_invalid(self):
a = b'00' a = b'00'
v = memoryview(a).cast('b', shape=[1, 2]) v = memoryview(a).cast('b', shape=[1, 2])
@ -732,10 +766,16 @@ class StridedArrayView2D(unittest.TestCase):
containers.StridedArrayView2D().flipped(2) containers.StridedArrayView2D().flipped(2)
with self.assertRaisesRegex(IndexError, "dimension 2 out of range for a 2D view"): with self.assertRaisesRegex(IndexError, "dimension 2 out of range for a 2D view"):
containers.StridedArrayView2D(v).broadcasted(2, 3) containers.StridedArrayView2D(v).broadcasted(2, 3)
with self.assertRaisesRegex(IndexError, "dimension 2 out of range for a 2D view"):
containers.StridedArrayView2D(v).expanded(2, (1, 2))
with self.assertRaisesRegex(ValueError, "can't broadcast dimension 1 with 2 elements"): with self.assertRaisesRegex(ValueError, "can't broadcast dimension 1 with 2 elements"):
containers.StridedArrayView2D(v).broadcasted(1, 3) containers.StridedArrayView2D(v).broadcasted(1, 3)
with self.assertRaisesRegex(IndexError, "dimensions 0, 2 can't be transposed in a 2D view"): with self.assertRaisesRegex(IndexError, "dimensions 0, 2 can't be transposed in a 2D view"):
containers.StridedArrayView2D().transposed(0, 2) containers.StridedArrayView2D().transposed(0, 2)
with self.assertRaisesRegex(ValueError, "total size 2 doesn't match dimension 0 with 1 elements"):
containers.StridedArrayView2D(v).expanded(0, (1, 2))
with self.assertRaisesRegex(ValueError, "total size 4 doesn't match dimension 1 with 2 elements"):
containers.StridedArrayView2D(v).expanded(1, (2, 1, 2))
def test_convert_memoryview(self): def test_convert_memoryview(self):
a = memoryview(b'01234567' a = memoryview(b'01234567'
@ -838,6 +878,12 @@ class StridedArrayView3D(unittest.TestCase):
self.assertEqual(f.stride, (24, 8, 0)) self.assertEqual(f.stride, (24, 8, 0))
self.assertEqual(bytes(f), b'000004444488888ccccc0000044444') self.assertEqual(bytes(f), b'000004444488888ccccc0000044444')
g4 = containers.StridedArrayView3D(v).expanded(2, (2, 4))
self.assertIsInstance(g4, containers.StridedArrayView4D)
self.assertEqual(g4.size, (2, 3, 2, 4))
self.assertEqual(g4.stride, (24, 8, 4, 1))
self.assertEqual(bytes(g4), b'01234567456789ab89abcdefcdef012301234567456789ab')
def test_ops_invalid(self): def test_ops_invalid(self):
a = b'00' a = b'00'
v = memoryview(a).cast('b', shape=[1, 1, 2]) v = memoryview(a).cast('b', shape=[1, 1, 2])
@ -848,10 +894,16 @@ class StridedArrayView3D(unittest.TestCase):
containers.StridedArrayView3D().flipped(3) containers.StridedArrayView3D().flipped(3)
with self.assertRaisesRegex(IndexError, "dimension 3 out of range for a 3D view"): with self.assertRaisesRegex(IndexError, "dimension 3 out of range for a 3D view"):
containers.StridedArrayView3D(v).broadcasted(3, 3) containers.StridedArrayView3D(v).broadcasted(3, 3)
with self.assertRaisesRegex(IndexError, "dimension 3 out of range for a 3D view"):
containers.StridedArrayView3D(v).expanded(3, (1, 2))
with self.assertRaisesRegex(ValueError, "can't broadcast dimension 2 with 2 elements"): with self.assertRaisesRegex(ValueError, "can't broadcast dimension 2 with 2 elements"):
containers.StridedArrayView3D(v).broadcasted(2, 3) containers.StridedArrayView3D(v).broadcasted(2, 3)
with self.assertRaisesRegex(IndexError, "dimensions 1, 3 can't be transposed in a 3D view"): with self.assertRaisesRegex(IndexError, "dimensions 1, 3 can't be transposed in a 3D view"):
containers.StridedArrayView3D().transposed(1, 3) containers.StridedArrayView3D().transposed(1, 3)
with self.assertRaisesRegex(ValueError, "total size 2 doesn't match dimension 0 with 1 elements"):
containers.StridedArrayView3D(v).expanded(0, (1, 2))
with self.assertRaisesRegex(ValueError, "total size 3 doesn't match dimension 2 with 2 elements"):
containers.StridedArrayView3D(v).expanded(2, (3, 1))
# This is just a dumb copy of the above with one dimension inserted at the # This is just a dumb copy of the above with one dimension inserted at the
# second place. # second place.
@ -1713,6 +1765,45 @@ class StridedBitArrayView1D(unittest.TestCase):
self.assertEqual(c[3], True) self.assertEqual(c[3], True)
self.assertEqual(c[4], True) self.assertEqual(c[4], True)
d2 = v.expanded(0, (2, 4))
self.assertIsInstance(d2, containers.StridedBitArrayView2D)
self.assertEqual(d2.size, (2, 4))
self.assertEqual(d2.stride, (32, 8))
self.assertEqual(d2[0][0], True)
self.assertEqual(d2[0][1], True)
self.assertEqual(d2[0][2], True)
self.assertEqual(d2[0][3], True)
self.assertEqual(d2[1][0], False)
self.assertEqual(d2[1][1], False)
self.assertEqual(d2[1][2], True)
self.assertEqual(d2[1][3], False)
d3 = v.expanded(0, (2, 2, 2))
self.assertIsInstance(d3, containers.StridedBitArrayView3D)
self.assertEqual(d3.size, (2, 2, 2))
self.assertEqual(d3.stride, (32, 16, 8))
self.assertEqual(d3[0][0][0], True)
self.assertEqual(d3[0][0][1], True)
self.assertEqual(d3[0][1][0], True)
self.assertEqual(d3[0][1][1], True)
self.assertEqual(d3[1][0][0], False)
self.assertEqual(d3[1][0][1], False)
self.assertEqual(d3[1][1][0], True)
self.assertEqual(d3[1][1][1], False)
d4 = v.expanded(0, (2, 1, 2, 2))
self.assertIsInstance(d4, containers.StridedBitArrayView4D)
self.assertEqual(d4.size, (2, 1, 2, 2))
self.assertEqual(d4.stride, (32, 32, 16, 8))
self.assertEqual(d4[0][0][0][0], True)
self.assertEqual(d4[0][0][0][1], True)
self.assertEqual(d4[0][0][1][0], True)
self.assertEqual(d4[0][0][1][1], True)
self.assertEqual(d4[1][0][0][0], False)
self.assertEqual(d4[1][0][0][1], False)
self.assertEqual(d4[1][0][1][0], True)
self.assertEqual(d4[1][0][1][1], False)
def test_ops_invalid(self): def test_ops_invalid(self):
v = containers.StridedArrayView1D(b'00').slice_bit(0) v = containers.StridedArrayView1D(b'00').slice_bit(0)
@ -1720,8 +1811,12 @@ class StridedBitArrayView1D(unittest.TestCase):
containers.StridedBitArrayView1D().flipped(1) containers.StridedBitArrayView1D().flipped(1)
with self.assertRaisesRegex(IndexError, "dimension 1 out of range for a 1D view"): with self.assertRaisesRegex(IndexError, "dimension 1 out of range for a 1D view"):
v.broadcasted(1, 3) v.broadcasted(1, 3)
with self.assertRaisesRegex(IndexError, "dimension 1 out of range for a 1D view"):
v.expanded(1, (1, 2))
with self.assertRaisesRegex(ValueError, "can't broadcast dimension 0 with 2 elements"): with self.assertRaisesRegex(ValueError, "can't broadcast dimension 0 with 2 elements"):
v.broadcasted(0, 3) v.broadcasted(0, 3)
with self.assertRaisesRegex(ValueError, "total size 3 doesn't match dimension 0 with 2 elements"):
v.expanded(0, (1, 3))
class StridedBitArrayView2D(unittest.TestCase): class StridedBitArrayView2D(unittest.TestCase):
def test_init(self): def test_init(self):
@ -1993,6 +2088,32 @@ class StridedBitArrayView2D(unittest.TestCase):
self.assertEqual(d[2, 1], False) self.assertEqual(d[2, 1], False)
self.assertEqual(d[3, 1], False) self.assertEqual(d[3, 1], False)
d3 = a.expanded(1, (2, 2))
self.assertIsInstance(d3, containers.StridedBitArrayView3D)
self.assertEqual(d3.size, (2, 2, 2))
self.assertEqual(d3.stride, (32, 16, 8))
self.assertEqual(d3[0][0][0], True)
self.assertEqual(d3[0][0][1], True)
self.assertEqual(d3[0][1][0], True)
self.assertEqual(d3[0][1][1], True)
self.assertEqual(d3[1][0][0], False)
self.assertEqual(d3[1][0][1], False)
self.assertEqual(d3[1][1][0], True)
self.assertEqual(d3[1][1][1], False)
d4 = a.expanded(1, (1, 2, 2))
self.assertIsInstance(d4, containers.StridedBitArrayView4D)
self.assertEqual(d4.size, (2, 1, 2, 2))
self.assertEqual(d4.stride, (32, 32, 16, 8))
self.assertEqual(d4[0][0][0][0], True)
self.assertEqual(d4[0][0][0][1], True)
self.assertEqual(d4[0][0][1][0], True)
self.assertEqual(d4[0][0][1][1], True)
self.assertEqual(d4[1][0][0][0], False)
self.assertEqual(d4[1][0][0][1], False)
self.assertEqual(d4[1][0][1][0], True)
self.assertEqual(d4[1][0][1][1], False)
def test_ops_invalid(self): def test_ops_invalid(self):
v = containers.StridedArrayView2D(memoryview(b'00').cast('b', shape=[1, 2])).slice_bit(0) v = containers.StridedArrayView2D(memoryview(b'00').cast('b', shape=[1, 2])).slice_bit(0)
@ -2002,8 +2123,14 @@ class StridedBitArrayView2D(unittest.TestCase):
containers.StridedBitArrayView2D().transposed(2, 1) containers.StridedBitArrayView2D().transposed(2, 1)
with self.assertRaisesRegex(IndexError, "dimension 2 out of range for a 2D view"): with self.assertRaisesRegex(IndexError, "dimension 2 out of range for a 2D view"):
v.broadcasted(2, 3) v.broadcasted(2, 3)
with self.assertRaisesRegex(IndexError, "dimension 2 out of range for a 2D view"):
v.expanded(2, (1, 2))
with self.assertRaisesRegex(ValueError, "can't broadcast dimension 1 with 2 elements"): with self.assertRaisesRegex(ValueError, "can't broadcast dimension 1 with 2 elements"):
v.broadcasted(1, 3) v.broadcasted(1, 3)
with self.assertRaisesRegex(ValueError, "total size 2 doesn't match dimension 0 with 1 elements"):
v.expanded(0, (1, 2))
with self.assertRaisesRegex(ValueError, "total size 4 doesn't match dimension 1 with 2 elements"):
v.expanded(1, (2, 1, 2))
# Multi-dimensional behavior is tested extensively for StridedBitArrayView2D, # Multi-dimensional behavior is tested extensively for StridedBitArrayView2D,
# this checks just what differs, like constructors and fancy operations # this checks just what differs, like constructors and fancy operations
@ -2072,6 +2199,19 @@ class StridedBitArrayView3D(unittest.TestCase):
self.assertEqual(d[2, 0, 1], False) self.assertEqual(d[2, 0, 1], False)
self.assertEqual(d[3, 0, 1], False) self.assertEqual(d[3, 0, 1], False)
e4 = a.expanded(2, (2, 2))
self.assertIsInstance(e4, containers.StridedBitArrayView4D)
self.assertEqual(e4.size, (2, 1, 2, 2))
self.assertEqual(e4.stride, (32, 32, 16, 8))
self.assertEqual(e4[0][0][0][0], True)
self.assertEqual(e4[0][0][0][1], True)
self.assertEqual(e4[0][0][1][0], True)
self.assertEqual(e4[0][0][1][1], True)
self.assertEqual(e4[1][0][0][0], False)
self.assertEqual(e4[1][0][0][1], False)
self.assertEqual(e4[1][0][1][0], True)
self.assertEqual(e4[1][0][1][1], False)
def test_ops_invalid(self): def test_ops_invalid(self):
v = containers.StridedArrayView3D(memoryview(b'00').cast('b', shape=[1, 1, 2])).slice_bit(0) v = containers.StridedArrayView3D(memoryview(b'00').cast('b', shape=[1, 1, 2])).slice_bit(0)
@ -2081,8 +2221,14 @@ class StridedBitArrayView3D(unittest.TestCase):
containers.StridedBitArrayView3D().transposed(2, 3) containers.StridedBitArrayView3D().transposed(2, 3)
with self.assertRaisesRegex(IndexError, "dimension 3 out of range for a 3D view"): with self.assertRaisesRegex(IndexError, "dimension 3 out of range for a 3D view"):
v.broadcasted(3, 3) v.broadcasted(3, 3)
with self.assertRaisesRegex(IndexError, "dimension 3 out of range for a 3D view"):
v.expanded(3, (1, 2))
with self.assertRaisesRegex(ValueError, "can't broadcast dimension 2 with 2 elements"): with self.assertRaisesRegex(ValueError, "can't broadcast dimension 2 with 2 elements"):
v.broadcasted(2, 3) v.broadcasted(2, 3)
with self.assertRaisesRegex(ValueError, "total size 3 doesn't match dimension 0 with 1 elements"):
v.expanded(0, (1, 3))
with self.assertRaisesRegex(ValueError, "total size 6 doesn't match dimension 2 with 2 elements"):
v.expanded(2, (2, 3))
# This is just a dumb copy of the above with one dimension inserted at the # This is just a dumb copy of the above with one dimension inserted at the
# second place. # second place.

Loading…
Cancel
Save