class Frame<P>
represents an image with pixels of type P
. The algorithm that iterates through its pixels is non-trivial due to several flexibilities in the underlying data buffer format.
I define its point-wise arithmetic operators like this:
template <typename P, bool RM = true> // P is pixel type; RM = is_row_major
class Frame {
template<typename T>
Frame<P, RM>& operator += (const Frame<T, RM>& rhs) {
iterateTogether(rhs, [](auto& me, auto him) {
me += him;
});
return *this;
}
// ...
// ...
// ... many operations similar to above ...
template<typename P2, bool RM2, typename F>
void iterateTogether(const Frame<P2, RM2>& other, F f) {
// This function has a non-trivial body and may be extended in future.
// ************************************************************************
// * The rest of the code is background info. Feel free to ignore below. *
// ************************************************************************
static_assert(RM == RM2, "TODO: Implement for cases with RM!=RM2.");
if (size != other.size) {
throw std::invalid_argument("Frame sizes inconsistent.");
}
// Choose a performant way to iterate under the present conditions.
if (stride == other.stride) {
if (stride == (RM ? size.w : size.h)) {
auto n = size.area();
for (index_t k = 0; k < n; k++) {
f(view[k], other.view[k]);
}
}
else {
auto s = static_cast<index_t>(stride)*(RM ? size.h : size.w);
for (index_t k0 = 0; k0 < s; k0 += stride) {
auto m = k0 + (RM ? size.w : size.h);
for (index_t k = k0; k < m; k++) {
f(view[k], other.view[k]);
}
}
}
}
else {
auto s = static_cast<index_t>(stride)*(RM ? size.h : size.w);
index_t l0 = 0;
for (index_t k0 = 0; k0 < s; k0 += stride) {
auto m = k0 + (RM ? size.w : size.h);
auto n = l0 + (RM ? size.w : size.h);
auto l = l0;
for (index_t k = k0; k < m; k++) {
f(view[k], other.view[l++]);
}
l0 += other.stride;
}
}
}
}
However, occasionally I would like to call iterateTogether()
on a const Frame
. Since the method does not modify its host object (except if the lambda passed into it modifies its own arguments) I can duplicate the entire method and attach const
to its signature. But is there a better way?
Aucun commentaire:
Enregistrer un commentaire