CVB++ 15.0
decl_scatter_access.hpp
1#pragma once
2
3#include <array>
4#include <vector>
5#include <utility>
6
7#include "../exception.hpp"
8#include "../shims/stdtype_traits.hpp"
9#include "../shims/stdvariant.hpp"
10
11namespace Cvb
12{
13 CVB_BEGIN_INLINE_NS
14
15 class LinearAccessData;
16 class ArrayAccess;
17 class Vpat;
18
19 namespace Internal
20 {
21 // The plane access types supported for scattered access.
22 using AccessVariant = variant<ArrayAccess, LinearAccessData, Vpat>;
23
24 // The row access types supported for scattered access.
25 using RowVariant = variant<ArrayAccess::Row, LinearAccessData::Row, Vpat::Row>;
26
27 // The column access types supported for scattered access.
28 using ColumnVariant = variant<ArrayAccess::Column, LinearAccessData::Column, Vpat::Column>;
29
30 /*
31 * \brief Gets whether all planes in the range are valid.
32 *
33 * \param [in] first First element to check.
34 * \param [in] last One behind last element to check.
35 * \return \b true if all are valid; \b false otherwise.
36 */
37 template <class FITER>
38 bool AllValid(FITER first, FITER last);
39 } // namespace Internal
40
42 static const constexpr int Dynamic = -1;
43
51 template <int K>
52 class ScatterAccess
53 {
54 static_assert(K > 1, "CVB: empty or single plane scatter access not allowed");
55
56 public:
57 using Variant = Internal::AccessVariant;
58
59 private:
60 // Storage for the single plane access objects.
61 std::array<Variant, K> planeAccesses_;
62
63 static Variant MoveTo(const Variant &planeAccess, const Cvb::Rect<int> newAoi)
64 {
65 return visit([newAoi](auto access) { return Variant{access.NewMoved(newAoi)}; }, planeAccess);
66 }
67
68 template <size_t... INDICES>
69 ScatterAccess<K> NewMoved(const Cvb::Rect<int> newAoi, std::index_sequence<INDICES...>) const noexcept
70 {
71 return ScatterAccess<K>{MoveTo(planeAccesses_[INDICES], newAoi)...};
72 }
73
74 static const void *At(const Variant &planeAccess, int x, int y) noexcept
75 {
76 return visit([x, y](auto access) { return access(x, y); }, planeAccess);
77 }
78
79 template <size_t... INDICES>
80 std::array<const void *, K> At(int x, int y, std::index_sequence<INDICES...>) const noexcept
81 {
82 return std::array<const void *, K>{{At(planeAccesses_[INDICES], x, y)...}};
83 }
84
85 static void *At(Variant &planeAccess, int x, int y) noexcept
86 {
87 return visit([x, y](auto access) { return access(x, y); }, planeAccess);
88 }
89
90 template <size_t... INDICES>
91 std::array<void *, K> At(int x, int y, std::index_sequence<INDICES...>) noexcept
92 {
93 return std::array<void *, K>{{At(planeAccesses_[INDICES], x, y)...}};
94 }
95
96 static const void *At(const Variant &planeAccess, int idx) noexcept
97 {
98 return visit([idx](auto access) { return access[idx]; }, planeAccess);
99 }
100
101 template <size_t... INDICES>
102 std::array<const void *, K> At(int idx, std::index_sequence<INDICES...>) const noexcept
103 {
104 return std::array<const void *, K>{{At(planeAccesses_[INDICES], idx)...}};
105 }
106
107 static void *At(Variant &planeAccess, int idx) noexcept
108 {
109 return visit([idx](auto access) { return access[idx]; }, planeAccess);
110 }
111
112 template <size_t... INDICES>
113 std::array<void *, K> At(int idx, std::index_sequence<INDICES...>) noexcept
114 {
115 return std::array<void *, K>{{At(planeAccesses_[INDICES], idx)...}};
116 }
117
118 template <
119 class... ACCESSES,
120 std::enable_if_t<!conjunction<std::is_same<remove_cvref_t<ACCESSES>, ScatterAccess<K>>...>::value, int> = 0>
121 explicit ScatterAccess(ACCESSES &&...planeAccesses)
122 : planeAccesses_{{planeAccesses...}}
123 {
124 static_assert(sizeof...(ACCESSES) == K, "CVB: plane initialization must match plane count K");
125 }
126
127 public:
138 template <class... ACCESSES>
139 static ScatterAccess<K> FromAccess(ACCESSES &&...planeAccesses)
140 {
141 // must be bracket init for unpack to work
142 return ScatterAccess<K>{Variant(planeAccesses)...};
143 }
144
145 ScatterAccess(const ScatterAccess &other) noexcept
146 : planeAccesses_(other.planeAccesses_)
147 {
148 // must be explicitly defined, as GCC 7.x is not able to generate it automatically for some reason.
149 }
150
151 ScatterAccess &operator=(const ScatterAccess &other) noexcept
152 {
153 // must be explicitly defined, as GCC 7.x is not able to generate it automatically for some reason.
154 if (this != &other)
155 planeAccesses_ = other.planeAccesses_;
156
157 return *this;
158 }
159
160 ScatterAccess(ScatterAccess &&other) noexcept = default;
161 ScatterAccess &operator=(ScatterAccess &&other) noexcept = default;
162 ~ScatterAccess() = default;
163
169 constexpr size_t PlanesCount() const
170 {
171 return K;
172 }
173
183 ScatterAccess<K> NewMoved(const Cvb::Rect<int> newAoi) const noexcept
184 {
185 return NewMoved(newAoi, std::make_index_sequence<K>{});
186 }
187
194 bool Valid() const noexcept
195 {
196 return Internal::AllValid(planeAccesses_.begin(), planeAccesses_.end());
197 }
198
200 explicit operator bool() const noexcept
201 {
202 return Valid();
203 }
204
215 std::array<const void *, K> operator()(int x, int y) const noexcept
216 {
217 return At(x, y, std::make_index_sequence<K>{});
218 }
219
230 std::array<void *, K> operator()(int x, int y) noexcept
231 {
232 return At(x, y, std::make_index_sequence<K>{});
233 }
234
245 {
246 return At(idx, std::make_index_sequence<K>{});
247 }
248
259 {
260 return At(idx, std::make_index_sequence<K>{});
261 }
262
267 class Row
268 {
269 friend class ScatterAccess;
270
272
273 static Internal::RowVariant RowAt(const Variant &planeAccess, int y)
274 {
275 return visit([y](auto access) { return Internal::RowVariant{access.RowAt(y)}; }, planeAccess);
276 }
277
278 template <size_t... INDICES>
279 explicit Row(const ScatterAccess<K> &parent, int y, std::index_sequence<INDICES...>)
280 : rows_{{RowAt(parent.planeAccesses_[INDICES], y)...}}
281 {
282 }
283
284 // Creates a row from the scatter access at line \a y.
285 explicit Row(const ScatterAccess<K> &parent, int y)
286 : Row(parent, y, std::make_index_sequence<K>{})
287 {
288 }
289
290 static const void *ColumnAt(const Internal::RowVariant &row, int x)
291 {
292 return visit([x](auto rowAccess) { return rowAccess[x]; }, row);
293 }
294
295 static void *ColumnAt(Internal::RowVariant &row, int x)
296 {
297 return visit([x](auto rowAccess) { return rowAccess[x]; }, row);
298 }
299
300 template <size_t... INDICES>
301 std::array<const void *, K> ColumnAt(int x, std::index_sequence<INDICES...>) const
302 {
303 return std::array<const void *, K>{{ColumnAt(rows_[INDICES], x)...}};
304 }
305
306 template <size_t... INDICES>
307 std::array<void *, K> ColumnAt(int x, std::index_sequence<INDICES...>)
308 {
309 return std::array<void *, K>{{ColumnAt(rows_[INDICES], x)...}};
310 }
311
312 public:
314 Row() noexcept = default;
315
316 Row(const Row &other) = default;
317 Row &operator=(const Row &other) = default;
318 Row(Row &&other) noexcept = default;
319 Row &operator=(Row &&other) noexcept = default;
320 ~Row() = default;
321
331 std::array<void *, K> operator[](int x) noexcept
332 {
333 return ColumnAt(x, std::make_index_sequence<K>{});
334 }
335
346 {
347 return ColumnAt(x, std::make_index_sequence<K>{});
348 }
349 };
350
357 Row RowAt(int y) const
358 {
359 return Row{*this, y};
360 }
361
366 class Column
367 {
368 friend class ScatterAccess;
369
371
372 static Internal::ColumnVariant ColumnAt(const Variant &planeAccess, int x)
373 {
374 return visit([x](auto access) { return Internal::ColumnVariant{access.ColumnAt(x)}; }, planeAccess);
375 }
376
377 template <size_t... INDICES>
378 explicit Column(const ScatterAccess<K> &parent, int x, std::index_sequence<INDICES...>)
379 : columns_{{ColumnAt(parent.planeAccesses_[INDICES], x)...}}
380 {
381 }
382
383 // Creates a Column from the scatter access at column \a x.
384 explicit Column(const ScatterAccess<K> &parent, int x)
385 : Column(parent, x, std::make_index_sequence<K>{})
386 {
387 }
388
389 static const void *RowAt(const Internal::ColumnVariant &column, int y)
390 {
391 return visit([y](auto colAccess) { return colAccess[y]; }, column);
392 }
393
394 static void *RowAt(Internal::ColumnVariant &column, int y)
395 {
396 return visit([y](auto colAccess) { return colAccess[y]; }, column);
397 }
398
399 template <size_t... INDICES>
400 std::array<const void *, K> RowAt(int y, std::index_sequence<INDICES...>) const
401 {
402 return std::array<const void *, K>{{RowAt(columns_[INDICES], y)...}};
403 }
404
405 template <size_t... INDICES>
406 std::array<void *, K> RowAt(int y, std::index_sequence<INDICES...>)
407 {
408 return std::array<void *, K>{{RowAt(columns_[INDICES], y)...}};
409 }
410
411 public:
413 Column() noexcept = default;
414
415 Column(const Column &other) = default;
416 Column &operator=(const Column &other) = default;
417 Column(Column &&other) noexcept = default;
418 Column &operator=(Column &&other) noexcept = default;
419 ~Column() = default;
420
430 std::array<void *, K> operator[](int y) noexcept
431 {
432 return RowAt(y, std::make_index_sequence<K>{});
433 }
434
445 {
446 return RowAt(y, std::make_index_sequence<K>{});
447 }
448 };
449
456 Column ColumnAt(int x) const
457 {
458 return Column{*this, x};
459 }
460 };
461
469 template <class... ACCESSES>
470 auto MakeStaticScatterAccess(ACCESSES &&...planeAccesses) -> ScatterAccess<sizeof...(ACCESSES)>
471 {
472 return ScatterAccess<sizeof...(ACCESSES)>::FromAccess(std::forward<ACCESSES>(planeAccesses)...);
473 }
474
475#ifndef CVB_DOXYGEN
476 // Specialization for dynamic number of planes.
477 template <>
479 {
480 public:
482 using Variant = Internal::AccessVariant;
483
484 private:
485 // Storage for the single plane access objects.
486 std::vector<Variant> planeAccesses_;
487
488 public:
497 template <class FITER>
498 explicit ScatterAccess(FITER first, FITER last)
499 : planeAccesses_(first, last)
500 {
501 if (planeAccesses_.size() <= 1)
502 throw std::domain_error{"Empty or single plane scatter buffer not allowed"};
503 }
504
511 explicit ScatterAccess(std::vector<Variant> planeAccesses)
512 : planeAccesses_(std::move(planeAccesses))
513 {
514 if (planeAccesses_.size() <= 1)
515 throw std::domain_error{"Empty or single plane scatter buffer not allowed"};
516 }
517
518 template <class... ACCESSES>
519 static ScatterAccess<Dynamic> FromAccess(ACCESSES &&...planeAccesses)
520 {
521 return ScatterAccess<Dynamic>{{Variant(planeAccesses)...}};
522 }
523
524 ScatterAccess(const ScatterAccess &other)
525 : planeAccesses_(other.planeAccesses_)
526 {
527 // must be explicitly defined, as GCC 7.x is not able to generate it automatically for some reason.
528 }
529
530 ScatterAccess &operator=(const ScatterAccess &other)
531 {
532 // must be explicitly defined, as GCC 7.x is not able to generate it automatically for some reason.
533 if (this != &other)
534 planeAccesses_ = other.planeAccesses_;
535
536 return *this;
537 }
538
539 ScatterAccess(ScatterAccess &&other) noexcept = default;
540 ScatterAccess &operator=(ScatterAccess &&other) noexcept = default;
541 ~ScatterAccess() = default;
542
548 size_t PlanesCount() const
549 {
550 return planeAccesses_.size();
551 }
552
562 ScatterAccess<Dynamic> NewMoved(const Cvb::Rect<int> newAoi) const
563 {
564 std::vector<Variant> newMoved;
565 newMoved.reserve(planeAccesses_.size());
566 for (const auto &planeAccess : planeAccesses_)
567 {
568 visit([&newMoved, newAoi](auto access) { newMoved.emplace_back(access.NewMoved(newAoi)); }, planeAccess);
569 }
570
571 return ScatterAccess<Dynamic>{std::move(newMoved)};
572 }
573
580 bool Valid() const noexcept
581 {
582 return Internal::AllValid(planeAccesses_.begin(), planeAccesses_.end());
583 }
584
586 explicit operator bool() const noexcept
587 {
588 return Valid();
589 }
590
601 std::vector<const void *> operator()(int x, int y) const noexcept
602 {
603 std::vector<const void *> pixAddresses;
604 pixAddresses.reserve(planeAccesses_.size());
605 for (const auto &planeAccess : planeAccesses_)
606 {
607 pixAddresses.emplace_back(visit([x, y](auto access) { return access(x, y); }, planeAccess));
608 }
609
610 return pixAddresses;
611 }
612
623 std::vector<void *> operator()(int x, int y) noexcept
624 {
625 std::vector<void *> pixAddresses;
626 pixAddresses.reserve(planeAccesses_.size());
627 for (auto &planeAccess : planeAccesses_)
628 {
629 pixAddresses.emplace_back(visit([x, y](auto access) { return access(x, y); }, planeAccess));
630 }
631 return pixAddresses;
632 }
633
643 std::vector<const void *> operator[](int idx) const noexcept
644 {
645 std::vector<const void *> pixAddresses;
646 pixAddresses.reserve(planeAccesses_.size());
647 for (auto &planeAccess : planeAccesses_)
648 {
649 pixAddresses.emplace_back(visit([idx](auto access) { return access[idx]; }, planeAccess));
650 }
651
652 return pixAddresses;
653 }
654
664 std::vector<void *> operator[](int idx) noexcept
665 {
666 std::vector<void *> pixAddresses;
667 pixAddresses.reserve(planeAccesses_.size());
668 for (auto &planeAccess : planeAccesses_)
669 {
670 pixAddresses.emplace_back(visit([idx](auto access) { return access[idx]; }, planeAccess));
671 }
672
673 return pixAddresses;
674 }
675
680 class Row
681 {
682 friend class ScatterAccess;
683
684 std::vector<Internal::RowVariant> rows_;
685
686 explicit Row(const ScatterAccess<Dynamic> &parent, int y)
687 {
688 rows_.reserve(parent.planeAccesses_.size());
689 for (const auto &planeAccess : parent.planeAccesses_)
690 {
691 visit([this, y](auto access) { rows_.emplace_back(access.RowAt(y)); }, planeAccess);
692 }
693 }
694
695 public:
697 Row() noexcept = default;
698
699 Row(const Row &other) = default; // vector copy may throw
700 Row &operator=(const Row &other) = default; // vector copy may throw
701 Row(Row &&other) noexcept = default;
702 Row &operator=(Row &&other) noexcept = default;
703 ~Row() = default;
704
714 std::vector<void *> operator[](int x) noexcept
715 {
716 std::vector<void *> pixel;
717 pixel.reserve(rows_.size());
718
719 for (auto &row : rows_)
720 {
721 pixel.emplace_back(visit([x](auto rowAccess) { return rowAccess[x]; }, row));
722 }
723
724 return pixel;
725 }
726
736 std::vector<const void *> operator[](int x) const noexcept
737 {
738 std::vector<const void *> pixel;
739 pixel.reserve(rows_.size());
740
741 for (auto &row : rows_)
742 {
743 pixel.emplace_back(visit([x](auto rowAccess) { return rowAccess[x]; }, row));
744 }
745
746 return pixel;
747 }
748 };
749
756 Row RowAt(int y) const
757 {
758 return Row{*this, y};
759 }
760
765 class Column
766 {
767 friend class ScatterAccess;
768
769 std::vector<Internal::ColumnVariant> columns_;
770
771 explicit Column(const ScatterAccess<Dynamic> &parent, int x)
772 {
773 columns_.reserve(parent.planeAccesses_.size());
774 for (const auto &planeAccess : parent.planeAccesses_)
775 {
776 visit([this, x](auto access) { columns_.emplace_back(access.ColumnAt(x)); }, planeAccess);
777 }
778 }
779
780 public:
782 Column() noexcept = default;
783
784 Column(const Column &other) = default; // vector copy may throw
785 Column &operator=(const Column &other) = default; // vector copy may throw
786 Column(Column &&other) noexcept = default;
787 Column &operator=(Column &&other) noexcept = default;
788 ~Column() = default;
789
799 std::vector<void *> operator[](int y) noexcept
800 {
801 std::vector<void *> pixel;
802 pixel.reserve(columns_.size());
803
804 for (auto &column : columns_)
805 {
806 pixel.emplace_back(visit([y](auto colAccess) { return colAccess[y]; }, column));
807 }
808
809 return pixel;
810 }
811
821 std::vector<const void *> operator[](int y) const noexcept
822 {
823 std::vector<const void *> pixel;
824 pixel.reserve(columns_.size());
825
826 for (auto &column : columns_)
827 {
828 pixel.emplace_back(visit([y](auto colAccess) { return colAccess[y]; }, column));
829 }
830
831 return pixel;
832 }
833 };
834
841 Column ColumnAt(int x) const
842 {
843 return Column{*this, x};
844 }
845 };
846#endif
847 CVB_END_INLINE_NS
848
849} // namespace Cvb
Access trait for contiguous linear CVB image planes.
Definition decl_array_access.hpp:27
Linear access properties.
Definition decl_linear_access.hpp:25
Rectangle object.
Definition rect.hpp:24
A single column.
Definition decl_scatter_access.hpp:367
Column() noexcept=default
Default ctor of invalid Column.
std::array< const void *, K > operator[](int y) const noexcept
Value access.
Definition decl_scatter_access.hpp:444
std::array< void *, K > operator[](int y) noexcept
Value access.
Definition decl_scatter_access.hpp:430
A single row.
Definition decl_scatter_access.hpp:268
std::array< const void *, K > operator[](int x) const noexcept
Value access.
Definition decl_scatter_access.hpp:345
Row() noexcept=default
Default ctor of invalid row.
std::array< void *, K > operator[](int x) noexcept
Value access.
Definition decl_scatter_access.hpp:331
Access trait for multiple, possibly scattered planes.
Definition decl_scatter_access.hpp:53
std::array< void *, K > operator()(int x, int y) noexcept
Coordinate pixel access operator.
Definition decl_scatter_access.hpp:230
constexpr size_t PlanesCount() const
Gets the number of planes stored.
Definition decl_scatter_access.hpp:169
Row RowAt(int y) const
Gets the Row at line y.
Definition decl_scatter_access.hpp:357
static ScatterAccess< K > FromAccess(ACCESSES &&...planeAccesses)
Creates a ScatterAccess from the given access planes.
Definition decl_scatter_access.hpp:139
bool Valid() const noexcept
Gets whether the aggregated access objects are all valid.
Definition decl_scatter_access.hpp:194
std::array< const void *, K > operator[](int idx) const noexcept
Index pixel access operator.
Definition decl_scatter_access.hpp:244
std::array< void *, K > operator[](int idx) noexcept
Index pixel access operator.
Definition decl_scatter_access.hpp:258
std::array< const void *, K > operator()(int x, int y) const noexcept
Coordinate pixel access operator.
Definition decl_scatter_access.hpp:215
Column ColumnAt(int x) const
Gets the Column at x.
Definition decl_scatter_access.hpp:456
ScatterAccess< K > NewMoved(const Cvb::Rect< int > newAoi) const noexcept
Creates a new, moved scatter access object.
Definition decl_scatter_access.hpp:183
auto MakeStaticScatterAccess(ACCESSES &&...planeAccesses) -> ScatterAccess< sizeof...(ACCESSES)>
Creates a static scatter access with the given planes.
Definition decl_scatter_access.hpp:470
Virtual Pixel Access Table.
Definition decl_vpat.hpp:24
T forward(T... args)
Root namespace for the Image Manager interface.
Definition c_bayer_to_rgb.h:17
auto visit(VISITOR &&visitor, VARIANT &&var) -> decltype(visitor(get< 0 >(var)))
Visits the given Shims::variant var. Cvb::Shims::visit can only visit one variant (not multiple like ...
Definition variant.hpp:622
static const constexpr int Dynamic
Use with ScatterAccess for runtime variable number of planes.
Definition decl_scatter_access.hpp:42