CVB++ 15.0
detail_visit.hpp
1#pragma once
2
3#include <map>
4
5#include "../../plane.hpp"
6#include "../../size_2d.hpp"
7
8#include "../detail_callable.hpp"
9
10#include "../../_decl/block/decl_block.hpp"
11
12namespace Cvb
13{
14 CVB_BEGIN_INLINE_NS
15
16 namespace Internal
17 {
18 struct FindDifferingDataType
19 {
20 const Cvb::DataType dt_;
21
22 template <class PLANE_T>
23 inline bool operator()(const PLANE_T *plane) const noexcept
24 {
25 using PlaneTrait = PlaneTraits<PLANE_T>;
26 return dt_ != PlaneTrait::GetDataType(*plane);
27 }
28 };
29
30 } // namespace Internal
31
32 template <class PLANE_T>
33 inline bool AllPlanesHaveSameDataType(const PLANE_T &)
34 {
35 return true;
36 }
37
38 template <class PLANE_T, class... PLNS>
39 inline bool AllPlanesHaveSameDataType(const PLANE_T &plane0, const PLNS &...planes)
40 {
41 using PlaneTrait = PlaneTraits<PLANE_T>;
42 const std::array<const PLANE_T *, sizeof...(planes)> arr{&planes...};
43 return std::find_if(arr.cbegin(), arr.cend(), Internal::FindDifferingDataType{PlaneTrait::GetDataType(plane0)})
44 == arr.cend();
45 }
46
47 namespace Internal
48 {
49 struct PlanesFindDifferingLength
50 {
51 int length_;
52 template <class PLANE_T>
53 inline bool operator()(const PLANE_T *plane) const noexcept
54 {
55 using PlaneTrait = PlaneTraits<PLANE_T>;
56 return length_ != PlaneTrait::GetWidth(*plane);
57 }
58 };
59
60 struct PlanesFindDifferingSize
61 {
62 const Cvb::Size2D<int> size_;
63
64 template <class PLANE_T>
65 inline bool operator()(const PLANE_T *plane) const noexcept
66 {
67 using PlaneTrait = PlaneTraits<PLANE_T>;
68 return size_.Width() != PlaneTrait::GetWidth(*plane) || size_.Height() != PlaneTrait::GetHeight(*plane);
69 }
70 };
71 } // namespace Internal
72
73 template <class PLANE_T>
74 inline bool AllPlanesHaveSameSize(const PLANE_T &)
75 {
76 return true;
77 }
78
79 template <class PLANE_T, class... PLNS>
80 bool AllPlanesHaveSameSize(const PLANE_T &plane0, const PLNS &...planes)
81 {
82 using PlaneTrait = PlaneTraits<PLANE_T>;
83 const std::array<const PLANE_T *, sizeof...(planes)> arr{&planes...};
84 const int rank = PlaneTrait::GetRank(plane0);
85 if (rank == 1)
86 return std::find_if(arr.cbegin(), arr.cend(), Internal::PlanesFindDifferingLength{PlaneTrait::GetWidth(plane0)})
87 == arr.cend();
88 return std::find_if(
89 arr.cbegin(), arr.cend(),
90 Internal::PlanesFindDifferingSize{{PlaneTrait::GetWidth(plane0), PlaneTrait::GetHeight(plane0)}})
91 == arr.cend();
92 }
93
94 // specialization as known 2 rank
95 template <class... PLNS>
96 bool AllPlanesHaveSameSize(const ImagePlane &plane0, const PLNS &...planes)
97 {
98 const std::array<const ImagePlane *, sizeof...(planes)> arr{&planes...};
99 return std::find_if(arr.cbegin(), arr.cend(), Internal::PlanesFindDifferingSize{plane0.Parent().Size()})
100 == arr.cend();
101 }
102
103 namespace Internal
104 {
105 struct PlanesFindDifferingRank
106 {
107 int rank_;
108 template <class PLANE_T>
109 bool operator()(const PLANE_T *plane) const noexcept
110 {
111 using PlaneTrait = PlaneTraits<PLANE_T>;
112 return rank_ != PlaneTrait::GetRank(*plane);
113 }
114 };
115 } // namespace Internal
116
117 template <class PLANE_T>
118 inline bool AllPlanesHaveSameRank(const PLANE_T &) noexcept
119 {
120 return true;
121 }
122
123 template <class PLANE_T, class... PLNS>
124 bool AllPlanesHaveSameRank(const PLANE_T &plane0, const PLNS &...planes) noexcept
125 {
126 using PlaneTrait = PlaneTraits<PLANE_T>;
127 const std::array<const PLANE_T *, sizeof...(planes)> arr{&planes...};
128 return std::find_if(arr.cbegin(), arr.cend(), Internal::PlanesFindDifferingRank{PlaneTrait::GetRank(plane0)})
129 == arr.cend();
130 }
131
132 namespace Internal
133 {
134 /*
135 * \brief Allows specialization of blocks to only have one template parameter left.
136 * Used to fit template parameter for DataType::CallWithInstanceOf.
137 */
138 template <template <class> class BlockT, template <class...> class T>
139 struct TemplatedTypeBlock
140 {
141 template <class Ty>
142 using type = BlockT<T<Ty>>;
143 };
144
145 /*
146 * \brief Allows specialization of types by their size to only have one template parameter left.
147 * Used to fit template parameter for DataType::CallWithInstanceOf.
148 */
149 template <template <class, size_t> class T, size_t K>
150 struct TemplatedSizedType
151 {
152 template <class Ty>
153 using type = T<Ty, K>;
154 };
155
156 // uses the template parameter T to build the blocks
157 template <class T>
158 struct BlockBuilder
159 {
160 Cvb::Size2D<int> size_;
161
162 template <class AccessTrait>
163 Block<T, AccessTrait> operator()(AccessTrait trait) const
164 {
165 return Block<T, AccessTrait>{trait, size_};
166 }
167
168 template <class AccessTrait>
169 Block<T, AccessTrait> operator()(AccessTrait trait, Cvb::Size2D<int> size) const
170 {
171 return Block<T, AccessTrait>{trait, size};
172 }
173 };
174
175 template <template <class...> class T>
176 struct TemplatedTypeBuilder
177 {
178 template <class Ty>
179 using type = BlockBuilder<T<Ty>>;
180 };
181
182 inline Size2D<int> GetCloudBlockSize(const PointCloud &cloud)
183 {
184 if (cloud.Plane(0)->Rank() == 1)
185 return {cloud.Plane(0)->Length(0), 1};
186 return {cloud.Plane(0)->Length(0), cloud.Plane(0)->Length(1)};
187 }
188
189 template <class PLANE_T>
190 inline Size2D<int> GetBlockSize(const PLANE_T &plane)
191 {
192 using PlaneTrait = PlaneTraits<PLANE_T>;
193 if (PlaneTrait::GetRank(plane) == 1)
194 return {PlaneTrait::GetWidth(plane), 1};
195 return {PlaneTrait::GetWidth(plane), PlaneTrait::GetHeight(plane)};
196 }
197
198 // specialization as known 2 rank
199 inline Size2D<int> GetBlockSize(const ImagePlane &plane)
200 {
201 return plane.Parent().Size();
202 }
203
204 template <template <class> class T, class DEFAULT_T, class ACTION, class... CTORARGS>
205 inline auto CallWithAnyOfTypes(Cvb::DataType, DispatchableTypeList<>, ACTION &&action, CTORARGS &&...args)
206 -> decltype(std::forward<ACTION>(action)(T<DEFAULT_T>{std::forward<CTORARGS>(args)...}))
207 {
208 throw std::runtime_error("Could not match native data type");
209 }
210
211 template <template <class> class T, class DEFAULT_T, class ACTION, class DT, class... DTL, class... CTORARGS>
212 inline auto CallWithAnyOfTypes(Cvb::DataType dt, DispatchableTypeList<DT, DTL...>, ACTION &&action,
213 CTORARGS &&...args)
214 -> decltype(std::forward<ACTION>(action)(T<DEFAULT_T>{std::forward<CTORARGS>(args)...}))
215 {
216 if (dt.Matches<DT>())
217 return std::forward<ACTION>(action)(T<DT>{std::forward<CTORARGS>(args)...});
218 return CallWithAnyOfTypes<T, DEFAULT_T>(std::move(dt), DispatchableTypeList<DTL...>{},
219 std::forward<ACTION>(action), std::forward<CTORARGS>(args)...);
220 }
221
222 struct LinearAccessAndSize
223 {
224 LinearAccess access_;
225 Cvb::Size2D<int> size_;
226 };
227
228 struct VpatAndSize
229 {
230 Vpat access_;
231 Cvb::Size2D<int> size_;
232 };
233
234 template <class PLANE_T, std::enable_if_t<!PlaneTraits<PLANE_T>::HasVpat, int> = 0>
235 inline LinearAccessAndSize GetAccessAndSize(const PLANE_T &plane)
236 {
237 return {LinearAccess::FromPlane(plane), GetBlockSize(plane)};
238 }
239
240 template <class PLANE_T, std::enable_if_t<PlaneTraits<PLANE_T>::HasVpat, int> = 0>
241 inline VpatAndSize GetAccessAndSize(const PLANE_T &plane)
242 {
243 return {PlaneTraits<PLANE_T>::GetVpat(plane), GetBlockSize(plane)};
244 }
245
246 /*
247 * \brief Checks if all LinearAccesses can be converted to ArrayAccesses.
248 * If all are convertible, the first array access is returned.
249 * Otherwise an invalid ArrayAccess is returned.
250 *
251 * \param [in] size Size of the Block.
252 * \param [in] access LinearAccess to be converted.
253 * \param [in] accs More LinearAccess to be tested.
254 * \return Either the ArrayAccess for the first \a access or an invalid one.
255 */
256 inline ArrayAccess MakeArrayAccessIfAllAre(Cvb::Size2D<int> size, const LinearAccess &access) noexcept
257 {
258 return ArrayAccess::FromLinearAccess(access, size);
259 }
260
261 namespace // NOLINT(cert-dcl59-cpp)
262 {
263 struct IsLinearValidArrayAccess
264 {
265 Cvb::Size2D<int> size;
266 bool operator()(const LinearAccess *access) const noexcept
267 {
268 return ArrayAccess::FromLinearAccess(*access, size).Valid();
269 }
270
271 bool operator()(const LinearAccess &access) const noexcept
272 {
273 return ArrayAccess::FromLinearAccess(access, size).Valid();
274 }
275 };
276 } // namespace
277
278 template <size_t I>
279 ArrayAccess MakeArrayAccessIfAllAre(Cvb::Size2D<int> size,
280 const std::array<LinearAccess, I> &linearAccesses) noexcept
281 {
282 static_assert(I > 0, "Cvb: linearAccesses array must not be empty");
283 if (std::all_of(++linearAccesses.cbegin(), linearAccesses.cend(), IsLinearValidArrayAccess{size}))
284 if (auto arrayAcc = ArrayAccess::FromLinearAccess(linearAccesses[0], size))
285 return arrayAcc;
286 return {};
287 }
288
289 template <class... ACCESSES>
290 ArrayAccess MakeArrayAccessIfAllAre(Cvb::Size2D<int> size, const LinearAccess &access,
291 const ACCESSES &...accs) noexcept
292 {
293 const std::array<const LinearAccess *, sizeof...(accs)> arr{&accs...};
294 if (std::all_of(arr.cbegin(), arr.cend(), IsLinearValidArrayAccess{size}))
295 if (auto arrayAcc = ArrayAccess::FromLinearAccess(access, size))
296 return arrayAcc;
297 return {};
298 }
299
300 /*
301 * \brief Checks if all Vpats can be converted to LinearAccesses.
302 * If all are convertible, the first linear access is returned.
303 * Otherwise an invalid LinearAccess is returned.
304 *
305 * \param [in] size Size of the Block.
306 * \param [in] dt Data type of the block.
307 * \param [in] access Vpat to be converted.
308 * \return Either the LinearAccess for the first \a access or an invalid one.
309 */
310 inline std::array<LinearAccess, 1> MakeLinearAccessesIfAllAre(Cvb::Size2D<int> size, const DataType dt,
311 const Vpat &access) noexcept
312 {
313 return {LinearAccess::FromVpat(access, size, dt)};
314 }
315
316 template <class... ACCESSES>
317 std::array<LinearAccess, sizeof...(ACCESSES) + 1> MakeLinearAccessesIfAllAre(Cvb::Size2D<int> size,
318 const DataType dt, const Vpat &access,
319 const ACCESSES &...accs) noexcept
320 {
321 const std::array<const Vpat *, sizeof...(accs) + 1> vpatAccesses{&access, &accs...};
322 std::array<LinearAccess, sizeof...(ACCESSES) + 1> linearAccesses;
323 for (size_t i = 0; i < linearAccesses.size(); ++i)
324 {
325 if (linearAccesses[i] = LinearAccess::FromVpat(*vpatAccesses[i], size, dt)) // NOLINT
326 ;
327 else
328 return {};
329 }
330 return linearAccesses;
331 }
332
334 template <size_t NrVisitorArguments, class VISITOR, class DT, class... DTL, class... ACCESSES,
335 std::enable_if_t<NrVisitorArguments == 1 && sizeof...(ACCESSES) != 0, int> = 0>
336 auto VisitAccesses(VISITOR &&visitor, Cvb::DataType dataType, DispatchableTypeList<DT, DTL...> dtl,
337 const LinearAccessAndSize &access, const ACCESSES &...accesses)
338 {
339 constexpr const size_t NumAccesses = 1 + sizeof...(ACCESSES);
340 auto blockSize = access.size_;
341
342 if (IsInterleaved(dataType.BytesPerPixel(), access.access_, accesses.access_...))
343 {
344 if (auto aPlane0Access = MakeArrayAccessIfAllAre(blockSize, access.access_, accesses.access_...))
345 return CallWithAnyOfTypes<
346 TemplatedTypeBlock<ArrayPlaneBlock,
347 TemplatedSizedType<LinearValue, NumAccesses>::template type>::template type,
348 DT>(dataType, dtl, visitor, aPlane0Access, blockSize);
349 else
350 return CallWithAnyOfTypes<
351 TemplatedTypeBlock<LinearPlaneBlock,
352 TemplatedSizedType<LinearValue, NumAccesses>::template type>::template type,
353 DT>(dataType, dtl, visitor, access.access_, blockSize);
354 }
355 else
356 {
357 auto scatterAccess = MakeStaticScatterAccess(access.access_, accesses.access_...);
358
359 return CallWithAnyOfTypes<
360 TemplatedTypeBlock<TemplatedSizedType<ScatterBlock, NumAccesses>::template type,
361 TemplatedSizedType<RefValue, NumAccesses>::template type>::template type,
362 DT>(dataType, dtl, visitor, scatterAccess, blockSize);
363 }
364 }
365
367 template <size_t NrVisitorArguments, class VISITOR, class DT, class... DTL, class... ACCESSES,
368 std::enable_if_t<sizeof...(ACCESSES) + 1 == NrVisitorArguments || sizeof...(ACCESSES) == 0, int> = 0>
369 auto VisitAccesses(VISITOR &&visitor, Cvb::DataType dataType, DispatchableTypeList<DT, DTL...> dtl,
370 const LinearAccessAndSize &access, const ACCESSES &...accesses)
371 {
372 constexpr const size_t NumAccesses = 1 + sizeof...(ACCESSES);
373
374 static_assert(IsCallableMParameters<VISITOR, NumAccesses, Block<DT, LinearAccess>>::value,
375 "Cvb: visitor must have either one argument or as many arguments as plane arguments are given.");
376
377 if (auto aPlane0Access = MakeArrayAccessIfAllAre(access.size_, access.access_, accesses.access_...))
378 return CallWithAnyOfTypes<BlockBuilder, DT>(
379 dataType, dtl,
380 [=](auto typedThingy) {
381 visitor(typedThingy(aPlane0Access, access.size_),
382 typedThingy(ArrayAccess::FromLinearAccess(accesses.access_, accesses.size_), accesses.size_)...);
383 },
384 access.size_);
385 else
386 return CallWithAnyOfTypes<BlockBuilder, DT>(
387 dataType, dtl,
388 [visitor, access, accesses...](auto typedThingy) {
389 visitor(typedThingy(access.access_, access.size_), typedThingy(accesses.access_, accesses.size_)...);
390 },
391 access.size_);
392 }
393
395 template <
396 size_t VisitorArgCount, class T, class VISITOR, class... DTL, class... ACCESSES,
397 std::enable_if_t<!std::is_arithmetic<T>::value && (VisitorArgCount == 1 && sizeof...(ACCESSES) != 0), int> = 0>
398 auto VisitAccessesAs(VISITOR &&visitor, Cvb::DataType dataType, DispatchableTypeList<DTL...>,
399 const LinearAccessAndSize &access, const ACCESSES &...accesses)
400 {
401 constexpr const size_t NumAccesses = 1 + sizeof...(ACCESSES);
402
403 if (IsInterleaved(dataType.BytesPerPixel(), access.access_, accesses.access_...))
404 {
405 if (auto aPlane0Access = MakeArrayAccessIfAllAre(access.size_, access.access_, accesses.access_...))
406 return visitor(ArrayPlaneBlock<T>{aPlane0Access, access.size_});
407 else
408 return visitor(LinearPlaneBlock<T>{access.access_, access.size_});
409 }
410 else
411 {
412 auto scatterAccess = MakeStaticScatterAccess(access.access_, accesses.access_...);
413
414 return visitor(ScatterBlock<T, NumAccesses>{scatterAccess, access.size_});
415 }
416 }
417
419 template <
420 size_t VisitorArgCount, class T, class VISITOR, class... DTL, class... ACCESSES,
421 std::enable_if_t<std::is_arithmetic<T>::value && (VisitorArgCount == 1 && sizeof...(ACCESSES) != 0), int> = 0>
422 auto VisitAccessesAs(VISITOR &&visitor, Cvb::DataType dataType, DispatchableTypeList<DTL...>,
423 const LinearAccessAndSize &access, const ACCESSES &...accesses)
424 {
425 constexpr const size_t NumAccesses = 1 + sizeof...(ACCESSES);
427 if (IsInterleaved(dataType.BytesPerPixel(), access.access_, accesses.access_...))
428 {
429 if (auto aPlane0Access = MakeArrayAccessIfAllAre(access.size_, access.access_, accesses.access_...))
430 return visitor(ArrayPlaneBlock<LinearValue<T, NumAccesses>>{aPlane0Access, access.size_});
431 else
432 return visitor(LinearPlaneBlock<LinearValue<T, NumAccesses>>{access.access_, access.size_});
433 }
434 else
435 {
436 auto scatterAccess = MakeStaticScatterAccess(access.access_, accesses.access_...);
437
438 return visitor(ScatterBlock<RefValue<T, NumAccesses>, NumAccesses>{scatterAccess, access.size_});
439 }
440 }
441
443 template <size_t VisitorArgCount, class T, class VISITOR, class... DTL, class... ACCESSES,
444 std::enable_if_t<sizeof...(ACCESSES) + 1 == VisitorArgCount || sizeof...(ACCESSES) == 0, int> = 0>
445 auto VisitAccessesAs(VISITOR &&visitor, Cvb::DataType, DispatchableTypeList<DTL...>,
446 const LinearAccessAndSize &access, const ACCESSES &...accesses)
447 {
448 if (auto aPlane0Access = MakeArrayAccessIfAllAre(access.size_, access.access_, accesses.access_...))
449 return visitor(
450 ArrayPlaneBlock<T>{aPlane0Access, access.size_},
451 ArrayPlaneBlock<T>{ArrayAccess::FromLinearAccess(accesses.access_, accesses.size_), accesses.size_}...);
452 else
453 return visitor(LinearPlaneBlock<T>{access.access_, access.size_},
454 LinearPlaneBlock<T>{accesses.access_, accesses.size_}...);
455 }
456
458 template <size_t VisitorArgCount, template <class...> class T, class VISITOR, class DT, class... DTL,
459 class... ACCESSES, std::enable_if_t<(VisitorArgCount == 1 && sizeof...(ACCESSES) != 0), int> = 0>
460 auto VisitAccessesAs(VISITOR &&visitor, Cvb::DataType dataType, DispatchableTypeList<DT, DTL...> dtl,
461 const LinearAccessAndSize &access, const ACCESSES &...accesses)
462 {
463 constexpr const size_t NumAccesses = 1 + sizeof...(ACCESSES);
464
465 if (IsInterleaved(dataType.BytesPerPixel(), access.access_, accesses.access_...))
466 {
467 if (auto aPlane0Access = MakeArrayAccessIfAllAre(access.size_, access.access_, accesses.access_...))
468 return CallWithAnyOfTypes<TemplatedTypeBlock<ArrayPlaneBlock, T>::template type, DT>(
469 dataType, dtl, visitor, aPlane0Access, access.size_);
470 else
471 return CallWithAnyOfTypes<TemplatedTypeBlock<LinearPlaneBlock, T>::template type, DT>(
472 dataType, dtl, visitor, access.access_, access.size_);
473 }
474 else
475 {
476 auto scatterAccess = MakeStaticScatterAccess(access.access_, accesses.access_...);
477
478 return CallWithAnyOfTypes<
479 TemplatedTypeBlock<TemplatedSizedType<ScatterBlock, NumAccesses>::template type, T>::template type, DT>(
480 dataType, dtl, visitor, scatterAccess, access.size_);
481 }
482 }
483
485 template <size_t VisitorArgCount, template <class...> class T, class VISITOR, class DT, class... DTL,
486 class... ACCESSES,
487 std::enable_if_t<(sizeof...(ACCESSES) + 1 == VisitorArgCount || sizeof...(ACCESSES) == 0), int> = 0>
488 auto VisitAccessesAs(VISITOR &&visitor, Cvb::DataType dataType, DispatchableTypeList<DT, DTL...> dtl,
489 const LinearAccessAndSize &access, const ACCESSES &...accesses)
490 {
491 constexpr const size_t NumAccesses = 1 + sizeof...(ACCESSES);
492
493 if (auto aPlane0Access = MakeArrayAccessIfAllAre(access.size_, access.access_, accesses.access_...))
494 return CallWithAnyOfTypes<TemplatedTypeBuilder<T>::template type, DT>(
495 dataType, dtl,
496 [=](auto typedThingy) {
497 visitor(typedThingy(aPlane0Access, access.size_),
498 typedThingy(ArrayAccess::FromLinearAccess(accesses.access_, accesses.size_), accesses.size_)...);
499 },
500 access.size_);
501 else
502 return CallWithAnyOfTypes<TemplatedTypeBuilder<T>::template type, DT>(
503 dataType, dtl,
504 [=](auto typedThingy) {
505 visitor(typedThingy(access.access_, access.size_), typedThingy(accesses.access_, accesses.size_)...);
506 },
507 access.size_);
508 }
509
510#pragma region VpatVisit
511
512 template <class INVOKER, size_t... I>
513 auto InvokeWithLinearAccessesAndSizes(INVOKER &&invoker, const std::array<LinearAccess, sizeof...(I)> &accesses,
514 const std::array<Cvb::Size2D<int>, sizeof...(I)> &sizes,
515 std::index_sequence<I...>)
516 {
517 return std::forward<INVOKER>(invoker)(LinearAccessAndSize{accesses[I], sizes[I]}...);
518 }
519
521 template <size_t VisitorArgCount, class VISITOR, class DT, class... DTL, class... ACCESSES,
522 std::enable_if_t<VisitorArgCount == sizeof...(ACCESSES) + 1 || sizeof...(ACCESSES) == 0, int> = 0>
523 auto VisitAccesses(VISITOR &&visitor, Cvb::DataType dataType, DispatchableTypeList<DT, DTL...> dtl,
524 const VpatAndSize &vpatAndSize, const ACCESSES &...vpatAndSizes)
525 {
526 const auto lPlaneAccesses =
527 MakeLinearAccessesIfAllAre(vpatAndSize.size_, dataType, vpatAndSize.access_, vpatAndSizes.access_...);
528 if (lPlaneAccesses[0])
529 {
530 return InvokeWithLinearAccessesAndSizes(
531 [visitor = std::forward<VISITOR>(visitor), dataType, dtl](auto &&...linAccessesAndSizes) {
532 return VisitAccesses<VisitorArgCount>(visitor, dataType, dtl, linAccessesAndSizes...);
533 },
534 lPlaneAccesses, {vpatAndSize.size_, vpatAndSizes.size_...},
535 std::make_index_sequence<sizeof...(ACCESSES) + 1>());
536 }
537
538 return CallWithAnyOfTypes<BlockBuilder, DT>(
539 dataType, dtl,
540 [visitor, vpatAndSize, vpatAndSizes...](auto typedThingy) {
541 visitor(typedThingy(vpatAndSize.access_, vpatAndSize.size_),
542 typedThingy(vpatAndSizes.access_, vpatAndSizes.size_)...);
543 },
544 vpatAndSize.size_);
545 }
546
548 template <size_t VisitorArgCount, class VISITOR, class DT, class... DTL, class... ACCESSES,
549 std::enable_if_t<VisitorArgCount == 1 && sizeof...(ACCESSES) != 0, int> = 0>
550 auto VisitAccesses(VISITOR &&visitor, Cvb::DataType dataType, DispatchableTypeList<DT, DTL...> dtl,
551 const VpatAndSize &vpatAndSize, const ACCESSES &...vpatAndSizes)
552 {
553 const auto lPlaneAccesses =
554 MakeLinearAccessesIfAllAre(vpatAndSize.size_, dataType, vpatAndSize.access_, vpatAndSizes.access_...);
555 if (lPlaneAccesses[0])
556 {
557 return InvokeWithLinearAccessesAndSizes(
558 [visitor = std::forward<VISITOR>(visitor), dataType, dtl](auto &&...linAccessesAndSizes) {
559 return VisitAccesses<VisitorArgCount>(visitor, dataType, dtl, linAccessesAndSizes...);
560 },
561 lPlaneAccesses, {vpatAndSize.size_, vpatAndSizes.size_...},
562 std::make_index_sequence<sizeof...(ACCESSES) + 1>());
563 }
564
565 // avoid one instantiation for the (hopefully rather uncommon VPAT case): just use a vpat scatter block directly
566 // instead of vpat with LinearValue + vpat with RefValue.
567 auto scatterAccess = MakeStaticScatterAccess(vpatAndSize.access_, vpatAndSizes.access_...);
568
569 constexpr const size_t NumAccesses = 1 + sizeof...(ACCESSES);
570 return CallWithAnyOfTypes<
571 TemplatedTypeBlock<TemplatedSizedType<ScatterBlock, NumAccesses>::template type,
572 TemplatedSizedType<RefValue, NumAccesses>::template type>::template type,
573 DT>(dataType, dtl, std::forward<VISITOR>(visitor), scatterAccess, vpatAndSize.size_);
574 }
575
577 template <
578 size_t VisitorArgCount, class T, class VISITOR, class... DTL, class... ACCESSES,
579 std::enable_if_t<!std::is_arithmetic<T>::value && (VisitorArgCount == 1 && sizeof...(ACCESSES) != 0), int> = 0>
580 auto VisitAccessesAs(VISITOR &&visitor, Cvb::DataType dataType, DispatchableTypeList<DTL...> dtl,
581 const VpatAndSize &vpatAndSize, const ACCESSES &...vpatAndSizes)
582 {
583 const auto lPlaneAccesses =
584 MakeLinearAccessesIfAllAre(vpatAndSize.size_, dataType, vpatAndSize.access_, vpatAndSizes.access_...);
585 if (lPlaneAccesses[0])
586 {
587 return InvokeWithLinearAccessesAndSizes(
588 [visitor = std::forward<VISITOR>(visitor), dataType, dtl](auto &&...linAccessesAndSizes) {
589 return VisitAccessesAs<VisitorArgCount, T>(visitor, dataType, dtl, linAccessesAndSizes...);
590 },
591 lPlaneAccesses, {vpatAndSize.size_, vpatAndSizes.size_...},
592 std::make_index_sequence<sizeof...(ACCESSES) + 1>());
593 }
594
595 // avoid one instantiation for the (hopefully rather uncommon VPAT case): just use a vpat scatter block directly
596 // instead of vpat with LinearValue + vpat with RefValue.
597 auto scatterAccess = MakeStaticScatterAccess(vpatAndSize.access_, vpatAndSizes.access_...);
598
599 constexpr const size_t NumAccesses = 1 + sizeof...(ACCESSES);
600 return visitor(ScatterBlock<T, NumAccesses>{scatterAccess, vpatAndSize.size_});
601 }
602
604 template <
605 size_t VisitorArgCount, class T, class VISITOR, class... DTL, class... ACCESSES,
606 std::enable_if_t<std::is_arithmetic<T>::value && (VisitorArgCount == 1 && sizeof...(ACCESSES) != 0), int> = 0>
607 auto VisitAccessesAs(VISITOR &&visitor, Cvb::DataType dataType, DispatchableTypeList<DTL...> dtl,
608 const VpatAndSize &vpatAndSize, const ACCESSES &...vpatAndSizes)
609 {
610 const auto lPlaneAccesses =
611 MakeLinearAccessesIfAllAre(vpatAndSize.size_, dataType, vpatAndSize.access_, vpatAndSizes.access_...);
612 if (lPlaneAccesses[0])
613 {
614 return InvokeWithLinearAccessesAndSizes(
615 [visitor = std::forward<VISITOR>(visitor), dataType, dtl](auto &&...linAccessesAndSizes) {
616 return VisitAccessesAs<VisitorArgCount, T>(visitor, dataType, dtl, linAccessesAndSizes...);
617 },
618 lPlaneAccesses, {vpatAndSize.size_, vpatAndSizes.size_...},
619 std::make_index_sequence<sizeof...(ACCESSES) + 1>());
620 }
621
622 // avoid one instantiation for the (hopefully rather uncommon VPAT case): just use a vpat scatter block directly
623 // instead of vpat with LinearValue + vpat with RefValue.
624 auto scatterAccess = MakeStaticScatterAccess(vpatAndSize.access_, vpatAndSizes.access_...);
625
626 constexpr const size_t NumAccesses = 1 + sizeof...(ACCESSES);
627 return visitor(ScatterBlock<RefValue<T, NumAccesses>, NumAccesses>{scatterAccess, vpatAndSize.size_});
628 }
629
631 template <size_t VisitorArgCount, class T, class VISITOR, class... DTL, class... ACCESSES,
632 std::enable_if_t<(VisitorArgCount == sizeof...(ACCESSES) + 1 || sizeof...(ACCESSES) == 0), int> = 0>
633 auto VisitAccessesAs(VISITOR &&visitor, Cvb::DataType dataType, DispatchableTypeList<DTL...> dtl,
634 const VpatAndSize &vpatAndSize, const ACCESSES &...vpatAndSizes)
635 {
636 const auto lPlaneAccesses =
637 MakeLinearAccessesIfAllAre(vpatAndSize.size_, dataType, vpatAndSize.access_, vpatAndSizes.access_...);
638 if (lPlaneAccesses[0])
639 {
640 return InvokeWithLinearAccessesAndSizes(
641 [visitor = std::forward<VISITOR>(visitor), dataType, dtl](auto &&...linAccessesAndSizes) {
642 return VisitAccessesAs<VisitorArgCount, T>(visitor, dataType, dtl, linAccessesAndSizes...);
643 },
644 lPlaneAccesses, {vpatAndSize.size_, vpatAndSizes.size_...},
645 std::make_index_sequence<sizeof...(ACCESSES) + 1>());
646 }
647
648 return std::forward<VISITOR>(visitor)(VpatPlaneBlock<T>{vpatAndSize.access_, vpatAndSize.size_},
649 VpatPlaneBlock<T>{vpatAndSizes.access_, vpatAndSizes.size_}...);
650 }
651
653 template <size_t VisitorArgCount, template <class...> class T, class VISITOR, class DT, class... DTL,
654 class... ACCESSES, std::enable_if_t<VisitorArgCount == 1 && sizeof...(ACCESSES) != 0, int> = 0>
655 auto VisitAccessesAs(VISITOR &&visitor, Cvb::DataType dataType, DispatchableTypeList<DT, DTL...> dtl,
656 const VpatAndSize &vpatAndSize, const ACCESSES &...vpatAndSizes)
657 {
658 const auto lPlaneAccesses =
659 MakeLinearAccessesIfAllAre(vpatAndSize.size_, dataType, vpatAndSize.access_, vpatAndSizes.access_...);
660 if (lPlaneAccesses[0])
661 {
662 return InvokeWithLinearAccessesAndSizes(
663 [visitor = std::forward<VISITOR>(visitor), dataType, dtl](auto &&...linAccessesAndSizes) {
664 return VisitAccessesAs<VisitorArgCount, T>(visitor, dataType, dtl, linAccessesAndSizes...);
665 },
666 lPlaneAccesses, {vpatAndSize.size_, vpatAndSizes.size_...},
667 std::make_index_sequence<sizeof...(ACCESSES) + 1>());
668 }
669
670 // avoid one instantiation for the (hopefully rather uncommon VPAT case): just use a vpat scatter block directly
671 // instead of vpat with LinearValue + vpat with RefValue.
672 auto scatterAccess = MakeStaticScatterAccess(vpatAndSize.access_, vpatAndSizes.access_...);
673
674 constexpr const size_t NumAccesses = 1 + sizeof...(ACCESSES);
675 return CallWithAnyOfTypes<
676 TemplatedTypeBlock<TemplatedSizedType<ScatterBlock, NumAccesses>::template type, T>::template type, DT>(
677 dataType, dtl, std::forward<VISITOR>(visitor), scatterAccess, vpatAndSize.size_);
678 }
679
681 template <size_t VisitorArgCount, template <class...> class T, class VISITOR, class DT, class... DTL,
682 class... ACCESSES,
683 std::enable_if_t<VisitorArgCount == sizeof...(ACCESSES) + 1 || sizeof...(ACCESSES) == 0, int> = 0>
684 auto VisitAccessesAs(VISITOR &&visitor, Cvb::DataType dataType, DispatchableTypeList<DT, DTL...> dtl,
685 const VpatAndSize &vpatAndSize, const ACCESSES &...vpatAndSizes)
686 {
687 const auto lPlaneAccesses =
688 MakeLinearAccessesIfAllAre(vpatAndSize.size_, dataType, vpatAndSize.access_, vpatAndSizes.access_...);
689 if (lPlaneAccesses[0])
690 {
691 return InvokeWithLinearAccessesAndSizes(
692 [visitor = std::forward<VISITOR>(visitor), dataType, dtl](auto &&...linAccessesAndSizes) {
693 return VisitAccessesAs<VisitorArgCount, T>(visitor, dataType, dtl, linAccessesAndSizes...);
694 },
695 lPlaneAccesses, {vpatAndSize.size_, vpatAndSizes.size_...},
696 std::make_index_sequence<sizeof...(ACCESSES) + 1>());
697 }
698
699 return CallWithAnyOfTypes<TemplatedTypeBuilder<T>::template type, DT>(
700 dataType, dtl,
701 [=](auto typedThingy) {
702 visitor(typedThingy(vpatAndSize.access_, vpatAndSize.size_),
703 typedThingy(vpatAndSizes.access_, vpatAndSizes.size_)...);
704 },
705 vpatAndSize.size_);
706 }
707
709 template <class PIXEL_TYPE, class VISITOR, class... DTL>
710 auto VisitAccessesAs(VISITOR &&visitor, Cvb::DataType dataType, DispatchableTypeList<DTL...>,
711 const VpatAndSize &accessAndSize)
712 {
713 Internal::BlockBuilder<PIXEL_TYPE> builder{accessAndSize.size_};
714 if (const auto linearAccess = LinearAccess::FromVpat(accessAndSize.access_, accessAndSize.size_, dataType))
715 {
716 if (const auto arrayAccess = ArrayAccess::FromLinearAccess(linearAccess, accessAndSize.size_))
717 return std::forward<VISITOR>(visitor)(builder(arrayAccess));
718 else
719 return std::forward<VISITOR>(visitor)(builder(linearAccess));
720 }
721 else
722 return std::forward<VISITOR>(visitor)(builder(accessAndSize.access_));
723 }
724#pragma endregion VpatVisit
725
726 // multi plane dispatch
727 template <class T, class VISITOR, class PLANE_T, class... PLNS,
728 std::enable_if_t<!std::is_arithmetic<T>::value, int> = 0>
729 auto VisitPlanesAs(VISITOR &&visitor, const PLANE_T &plane, const PLNS &...planes)
730 {
731 using PlaneTrait = PlaneTraits<PLANE_T>;
732 constexpr const size_t ArgCount = 1 + sizeof...(PLNS);
733 constexpr const size_t VisitorArgCount =
734 Cvb::Internal::IsCallableMParameters<VISITOR, ArgCount, Block<T, LinearAccess>>::value ? ArgCount : 1;
735
736 static_assert(VisitorArgCount == ArgCount || VisitorArgCount == 1,
737 "Cvb: visitor must have either one argument or as many arguments as plane arguments are given.");
738
739 if (!PlaneTrait::GetDataType(plane).template Matches<ComponentOfT<T>>()
740 || !AllPlanesHaveSameDataType(plane, planes...))
741 throw std::domain_error{"The requested planes must have all the same data type"};
742
743#pragma warning(push, 4)
744#pragma warning(disable : 4127)
745 if (VisitorArgCount == 1 && !AllPlanesHaveSameSize(plane, planes...))
746 throw std::domain_error{"Planes must have same size."};
747#pragma warning(pop)
748
749 return VisitAccessesAs<VisitorArgCount, T>(std::forward<VISITOR>(visitor), PlaneTrait::GetDataType(plane),
750 typename PlaneTrait::TypeList{}, GetAccessAndSize(plane),
751 GetAccessAndSize(planes)...);
752 }
753
754 // multi plane dispatch for integral Ts
755 template <class T, class VISITOR, class PLANE_T, class... PLNS,
756 std::enable_if_t<std::is_arithmetic<T>::value, int> = 0>
757 auto VisitPlanesAs(VISITOR &&visitor, const PLANE_T &plane, const PLNS &...planes)
758 {
759 using PlaneTrait = PlaneTraits<PLANE_T>;
760 constexpr const size_t ArgCount = 1 + sizeof...(PLNS);
761 constexpr const size_t VisitorArgCount =
762 Cvb::Internal::IsCallableMParameters<VISITOR, ArgCount, Block<T, LinearAccess>>::value ? ArgCount : 1;
763
764 static_assert(VisitorArgCount == ArgCount || VisitorArgCount == 1,
765 "Cvb: visitor must have either one argument or as many arguments as plane arguments are given.");
766
767 if (!PlaneTrait::GetDataType(plane).template Matches<T>() || !AllPlanesHaveSameDataType(plane, planes...))
768 throw std::domain_error{"The requested planes must have all the same data type"};
769
770#pragma warning(push, 4)
771#pragma warning(disable : 4127)
772 if (VisitorArgCount == 1 && !AllPlanesHaveSameSize(plane, planes...))
773 throw std::domain_error{"Planes must have same size."};
774#pragma warning(pop)
775
776 return VisitAccessesAs<VisitorArgCount, T>(std::forward<VISITOR>(visitor), PlaneTrait::GetDataType(plane),
777 typename PlaneTrait::TypeList{}, GetAccessAndSize(plane),
778 GetAccessAndSize(planes)...);
779 }
780
781 // multi plane dispatch
782 template <template <class...> class T, class VISITOR, class PLANE_T, class... PLNS>
783 auto VisitPlanesAs(VISITOR &&visitor, const PLANE_T &plane, const PLNS &...planes)
784 {
785 using PlaneTrait = PlaneTraits<PLANE_T>;
786 constexpr const size_t ArgCount = 1 + sizeof...(PLNS);
787 constexpr const size_t VisitorArgCount =
788 Cvb::Internal::IsCallableMParameters<
789 VISITOR, ArgCount, Block<T<typename PlaneTrait::TypeList::DefaultType>, LinearAccess>>::value
790 ? ArgCount
791 : 1;
792
793 static_assert(VisitorArgCount == ArgCount || VisitorArgCount == 1,
794 "Cvb: visitor must have either one argument or as many arguments as plane arguments are given.");
795
796 if (!AllPlanesHaveSameDataType(plane, planes...))
797 throw std::domain_error{"The requested planes must have all the same data type"};
798
799#pragma warning(push, 4)
800#pragma warning(disable : 4127)
801 if (VisitorArgCount == 1 && !AllPlanesHaveSameSize(plane, planes...))
802 throw std::domain_error{"Planes must have same size."};
803#pragma warning(pop)
804
805 return VisitAccessesAs<VisitorArgCount, T>(std::forward<VISITOR>(visitor), PlaneTrait::GetDataType(plane),
806 typename PlaneTrait::TypeList{}, GetAccessAndSize(plane),
807 GetAccessAndSize(planes)...);
808 }
809
810 // single plane dispatch
811 template <class T, class VISITOR, class PLANE_T>
812 auto VisitPlanesAs(VISITOR &&visitor, const PLANE_T &plane)
813 {
814 static_assert(Cvb::Internal::is_callable<VISITOR(Block<T, LinearAccess>)>::value,
815 "Cvb: The visitor must be visitable with a single typed block.");
816
817 using PlaneTrait = PlaneTraits<PLANE_T>;
818 return VisitAccessesAs<1, T>(std::forward<VISITOR>(visitor), PlaneTrait::GetDataType(plane),
819 typename PlaneTrait::TypeList{}, GetAccessAndSize(plane));
820 }
821
822 template <class VISITOR, class PLANE_T, std::enable_if_t<!PlaneTraits<PLANE_T>::HasVpat, int> = 0>
823 auto VisitPlanes(VISITOR &&visitor, const PLANE_T &plane)
824 {
825 using PlaneTrait = PlaneTraits<PLANE_T>;
826 constexpr const size_t VisitorArgCount = 1;
827
828 const auto dataType = PlaneTrait::GetDataType(plane);
829 return VisitAccesses<VisitorArgCount>(std::forward<VISITOR>(visitor), dataType, typename PlaneTrait::TypeList{},
830 LinearAccessAndSize{LinearAccess::FromPlane(plane), GetBlockSize(plane)});
831 }
832
833 template <class VISITOR, class PLANE_T, std::enable_if_t<PlaneTraits<PLANE_T>::HasVpat, int> = 0>
834 auto VisitPlanes(VISITOR &&visitor, const PLANE_T &plane)
835 {
836 using PlaneTrait = PlaneTraits<PLANE_T>;
837 const auto blockSize = GetBlockSize(plane);
838 auto vpat = PlaneTrait::GetVpat(plane);
839 const Cvb::DataType dt = PlaneTrait::GetDataType(plane);
840 if (const auto access = LinearAccess::FromVpat(vpat, blockSize, dt))
841 {
842 if (const auto arrayAccess = ArrayAccess::FromLinearAccess(access, blockSize))
843 return CallWithAnyOfTypes<ArrayPlaneBlock, typename PlaneTrait::TypeList::DefaultType>(
844 dt, typename PlaneTrait::TypeList{}, visitor, arrayAccess, blockSize);
845 else
846 return CallWithAnyOfTypes<LinearPlaneBlock, typename PlaneTrait::TypeList::DefaultType>(
847 dt, typename PlaneTrait::TypeList{}, visitor, access, blockSize);
848 }
849 else
850 return CallWithAnyOfTypes<VpatPlaneBlock, typename PlaneTrait::TypeList::DefaultType>(
851 dt, typename PlaneTrait::TypeList{}, visitor, vpat, blockSize);
852 }
853
854 template <class VISITOR, class PLANE_T, class... PLANEARGS>
855 auto VisitPlanes(VISITOR &&visitor, const PLANE_T &plane, const PLANEARGS &...planes)
856 {
857 using PlaneTrait = PlaneTraits<PLANE_T>;
858 constexpr const size_t ArgCount = 1 + sizeof...(PLANEARGS);
859 constexpr const size_t VisitorArgCount =
860 Cvb::Internal::IsCallableMParameters<VISITOR, ArgCount,
861 Block<typename PlaneTrait::TypeList::DefaultType, LinearAccess>>::value
862 ? ArgCount
863 : 1;
864
865 static_assert(VisitorArgCount == ArgCount || VisitorArgCount == 1,
866 "Cvb: visitor must have either one argument or as many arguments as plane arguments are given.");
867
868 if (!AllPlanesHaveSameDataType(plane, planes...))
869 throw std::domain_error{"Planes must have all the same data type"};
870
871#pragma warning(push, 4)
872#pragma warning(disable : 4127)
873 if (VisitorArgCount == 1 && !AllPlanesHaveSameSize(plane, planes...))
874 throw std::domain_error{"Planes must have same size."};
875#pragma warning(pop)
876
877 return VisitAccesses<VisitorArgCount>(std::forward<VISITOR>(visitor), PlaneTrait::GetDataType(plane),
878 typename PlaneTrait::TypeList{}, GetAccessAndSize(plane),
879 GetAccessAndSize(planes)...);
880 }
881
882 } // namespace Internal
883
884 template <class VISITOR, class PLANE_T, class... PLNS,
885 std::enable_if_t<std::is_same<typename PlaneTraits<PLANE_T>::PlaneT, PLANE_T>::value, int>>
886 auto Visit(VISITOR &&visitor, const PLANE_T &plane, const PLNS &...planes)
887 {
888 return Internal::VisitPlanes(std::forward<VISITOR>(visitor), plane, planes...);
889 }
890
891 template <class T, class VISITOR, class PLANE_T, class... PLANEARGS,
892 std::enable_if_t<std::is_same<typename PlaneTraits<PLANE_T>::PlaneT, PLANE_T>::value, int>>
893 auto VisitAs(VISITOR &&visitor, const PLANE_T &plane, const PLANEARGS &...planes)
894 {
895 return Internal::VisitPlanesAs<T>(std::forward<VISITOR>(visitor), plane, planes...);
896 }
897
898 template <template <class...> class T, class VISITOR, class PLANE_T, class... PLANEARGS,
899 std::enable_if_t<std::is_same<typename PlaneTraits<PLANE_T>::PlaneT, PLANE_T>::value, int>>
900 auto VisitAs(VISITOR &&visitor, const PLANE_T &plane, const PLANEARGS &...planes)
901 {
902 return Internal::VisitPlanesAs<T>(std::forward<VISITOR>(visitor), plane, planes...);
903 }
904
905 template <class VISITOR>
906 auto Visit(VISITOR &&visitor, const PointCloud &cloud)
907 {
908 assert(cloud.PlaneCount() >= 3);
909 return Internal::VisitPlanes(std::forward<VISITOR>(visitor), *cloud.Plane(0), *cloud.Plane(1), *cloud.Plane(2));
910 }
911
912 template <class T, class VISITOR>
913 auto VisitAs(VISITOR &&visitor, const PointCloud &cloud)
914 {
915 assert(cloud.PlaneCount() >= 3);
916
917 return Internal::VisitPlanesAs<remove_cvref_t<T>>(std::forward<VISITOR>(visitor), *cloud.Plane(0), *cloud.Plane(1),
918 *cloud.Plane(2));
919 }
920
921 template <template <class...> class T, class VISITOR>
922 auto VisitAs(VISITOR &&visitor, const PointCloud &cloud)
923 {
924 assert(cloud.PlaneCount() >= 3);
925
926 return Internal::VisitPlanesAs<T>(std::forward<VISITOR>(visitor), *cloud.Plane(0), *cloud.Plane(1),
927 *cloud.Plane(2));
928 }
929
930 CVB_END_INLINE_NS
931} // namespace Cvb
auto Visit(VISITOR &&visitor, const PointCloud &cloud)
Creates a Cvb::Block based on the cloud object's access trait and pixel type and calls the given visi...
Definition detail_visit.hpp:906
Block< T, ScatterAccess< K > > ScatterBlock
Definition decl_block.hpp:936
auto VisitAs(VISITOR &&visitor, const PointCloud &cloud)
Creates a Cvb::Block based on the cloud object's access trait and given pixel type T and calls the gi...
Definition detail_visit.hpp:913
Block< T, LinearAccess > LinearPlaneBlock
Definition decl_block.hpp:918
Block< T, ArrayAccess > ArrayPlaneBlock
Definition decl_block.hpp:909
Data type description for an image plane.
Definition data_type.hpp:23
int BytesPerPixel() const noexcept
Number of bytes occupied by each pixel.
Definition data_type.hpp:332
This class is memory compatible to K values of type T.
Definition block_helper_linear_value.hpp:50
A point cloud object.
Definition decl_point_cloud.hpp:62
PlanePtr Plane(int index) const
Index based plane access.
Definition decl_point_cloud.hpp:625
int PlaneCount() const noexcept
Gets the number of planes enumerated by this object.
Definition decl_point_cloud.hpp:598
This class holds mutable references to K values of type T.
Definition block_helper_ref_value.hpp:201
auto MakeStaticScatterAccess(ACCESSES &&...planeAccesses) -> ScatterAccess< sizeof...(ACCESSES)>
Creates a static scatter access with the given planes.
Definition decl_scatter_access.hpp:470
T find_if(T... args)
T forward(T... args)
Root namespace for the Image Manager interface.
Definition c_bayer_to_rgb.h:17
Definition global.hpp:1080