CVB++ 15.1
Loading...
Searching...
No Matches
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 linearAccesses[i] = LinearAccess::FromVpat(*vpatAccesses[i], size, dt);
326 if (!linearAccesses[i].Valid())
327 return {};
328 }
329 return linearAccesses;
330 }
331
333 template <size_t NrVisitorArguments, class VISITOR, class DT, class... DTL, class... ACCESSES,
334 std::enable_if_t<NrVisitorArguments == 1 && sizeof...(ACCESSES) != 0, int> = 0>
335 auto VisitAccesses(VISITOR &&visitor, Cvb::DataType dataType, DispatchableTypeList<DT, DTL...> dtl,
336 const LinearAccessAndSize &access, const ACCESSES &...accesses)
337 {
338 constexpr const size_t NumAccesses = 1 + sizeof...(ACCESSES);
339 auto blockSize = access.size_;
340
341 if (IsInterleaved(dataType.BytesPerPixel(), access.access_, accesses.access_...))
342 {
343 if (auto aPlane0Access = MakeArrayAccessIfAllAre(blockSize, access.access_, accesses.access_...))
344 return CallWithAnyOfTypes<
345 TemplatedTypeBlock<ArrayPlaneBlock,
346 TemplatedSizedType<LinearValue, NumAccesses>::template type>::template type,
347 DT>(dataType, dtl, visitor, aPlane0Access, blockSize);
348 else
349 return CallWithAnyOfTypes<
350 TemplatedTypeBlock<LinearPlaneBlock,
351 TemplatedSizedType<LinearValue, NumAccesses>::template type>::template type,
352 DT>(dataType, dtl, visitor, access.access_, blockSize);
353 }
354 else
355 {
356 auto scatterAccess = MakeStaticScatterAccess(access.access_, accesses.access_...);
357
358 return CallWithAnyOfTypes<
359 TemplatedTypeBlock<TemplatedSizedType<ScatterBlock, NumAccesses>::template type,
360 TemplatedSizedType<RefValue, NumAccesses>::template type>::template type,
361 DT>(dataType, dtl, visitor, scatterAccess, blockSize);
362 }
363 }
364
366 template <size_t NrVisitorArguments, class VISITOR, class DT, class... DTL, class... ACCESSES,
367 std::enable_if_t<sizeof...(ACCESSES) + 1 == NrVisitorArguments || sizeof...(ACCESSES) == 0, int> = 0>
368 auto VisitAccesses(VISITOR &&visitor, Cvb::DataType dataType, DispatchableTypeList<DT, DTL...> dtl,
369 const LinearAccessAndSize &access, const ACCESSES &...accesses)
370 {
371 constexpr const size_t NumAccesses = 1 + sizeof...(ACCESSES);
372
373 static_assert(IsCallableMParameters<VISITOR, NumAccesses, Block<DT, LinearAccess>>::value,
374 "Cvb: visitor must have either one argument or as many arguments as plane arguments are given.");
375
376 if (auto aPlane0Access = MakeArrayAccessIfAllAre(access.size_, access.access_, accesses.access_...))
377 return CallWithAnyOfTypes<BlockBuilder, DT>(
378 dataType, dtl,
379 [=](auto typedThingy) {
380 visitor(typedThingy(aPlane0Access, access.size_),
381 typedThingy(ArrayAccess::FromLinearAccess(accesses.access_, accesses.size_), accesses.size_)...);
382 },
383 access.size_);
384 else
385 return CallWithAnyOfTypes<BlockBuilder, DT>(
386 dataType, dtl,
387 [visitor, access, accesses...](auto typedThingy) {
388 visitor(typedThingy(access.access_, access.size_), typedThingy(accesses.access_, accesses.size_)...);
389 },
390 access.size_);
391 }
392
394 template <
395 size_t VisitorArgCount, class T, class VISITOR, class... DTL, class... ACCESSES,
396 std::enable_if_t<!std::is_arithmetic<T>::value && (VisitorArgCount == 1 && sizeof...(ACCESSES) != 0), int> = 0>
397 auto VisitAccessesAs(VISITOR &&visitor, Cvb::DataType dataType, DispatchableTypeList<DTL...>,
398 const LinearAccessAndSize &access, const ACCESSES &...accesses)
399 {
400 constexpr const size_t NumAccesses = 1 + sizeof...(ACCESSES);
401
402 if (IsInterleaved(dataType.BytesPerPixel(), access.access_, accesses.access_...))
403 {
404 if (auto aPlane0Access = MakeArrayAccessIfAllAre(access.size_, access.access_, accesses.access_...))
405 return visitor(ArrayPlaneBlock<T>{aPlane0Access, access.size_});
406 else
407 return visitor(LinearPlaneBlock<T>{access.access_, access.size_});
408 }
409 else
410 {
411 auto scatterAccess = MakeStaticScatterAccess(access.access_, accesses.access_...);
412
413 return visitor(ScatterBlock<T, NumAccesses>{scatterAccess, access.size_});
414 }
415 }
416
418 template <
419 size_t VisitorArgCount, class T, class VISITOR, class... DTL, class... ACCESSES,
420 std::enable_if_t<std::is_arithmetic<T>::value && (VisitorArgCount == 1 && sizeof...(ACCESSES) != 0), int> = 0>
421 auto VisitAccessesAs(VISITOR &&visitor, Cvb::DataType dataType, DispatchableTypeList<DTL...>,
422 const LinearAccessAndSize &access, const ACCESSES &...accesses)
423 {
424 constexpr const size_t NumAccesses = 1 + sizeof...(ACCESSES);
425
426 if (IsInterleaved(dataType.BytesPerPixel(), access.access_, accesses.access_...))
427 {
428 if (auto aPlane0Access = MakeArrayAccessIfAllAre(access.size_, access.access_, accesses.access_...))
429 return visitor(ArrayPlaneBlock<LinearValue<T, NumAccesses>>{aPlane0Access, access.size_});
430 else
431 return visitor(LinearPlaneBlock<LinearValue<T, NumAccesses>>{access.access_, access.size_});
432 }
433 else
434 {
435 auto scatterAccess = MakeStaticScatterAccess(access.access_, accesses.access_...);
436
437 return visitor(ScatterBlock<RefValue<T, NumAccesses>, NumAccesses>{scatterAccess, access.size_});
438 }
439 }
440
442 template <size_t VisitorArgCount, class T, class VISITOR, class... DTL, class... ACCESSES,
443 std::enable_if_t<sizeof...(ACCESSES) + 1 == VisitorArgCount || sizeof...(ACCESSES) == 0, int> = 0>
444 auto VisitAccessesAs(VISITOR &&visitor, Cvb::DataType, DispatchableTypeList<DTL...>,
445 const LinearAccessAndSize &access, const ACCESSES &...accesses)
446 {
447 if (auto aPlane0Access = MakeArrayAccessIfAllAre(access.size_, access.access_, accesses.access_...))
448 return visitor(
449 ArrayPlaneBlock<T>{aPlane0Access, access.size_},
450 ArrayPlaneBlock<T>{ArrayAccess::FromLinearAccess(accesses.access_, accesses.size_), accesses.size_}...);
451 else
452 return visitor(LinearPlaneBlock<T>{access.access_, access.size_},
453 LinearPlaneBlock<T>{accesses.access_, accesses.size_}...);
454 }
455
457 template <size_t VisitorArgCount, template <class...> class T, class VISITOR, class DT, class... DTL,
458 class... ACCESSES, std::enable_if_t<(VisitorArgCount == 1 && sizeof...(ACCESSES) != 0), int> = 0>
459 auto VisitAccessesAs(VISITOR &&visitor, Cvb::DataType dataType, DispatchableTypeList<DT, DTL...> dtl,
460 const LinearAccessAndSize &access, const ACCESSES &...accesses)
461 {
462 constexpr const size_t NumAccesses = 1 + sizeof...(ACCESSES);
463
464 if (IsInterleaved(dataType.BytesPerPixel(), access.access_, accesses.access_...))
465 {
466 if (auto aPlane0Access = MakeArrayAccessIfAllAre(access.size_, access.access_, accesses.access_...))
467 return CallWithAnyOfTypes<TemplatedTypeBlock<ArrayPlaneBlock, T>::template type, DT>(
468 dataType, dtl, visitor, aPlane0Access, access.size_);
469 else
470 return CallWithAnyOfTypes<TemplatedTypeBlock<LinearPlaneBlock, T>::template type, DT>(
471 dataType, dtl, visitor, access.access_, access.size_);
472 }
473 else
474 {
475 auto scatterAccess = MakeStaticScatterAccess(access.access_, accesses.access_...);
476
477 return CallWithAnyOfTypes<
478 TemplatedTypeBlock<TemplatedSizedType<ScatterBlock, NumAccesses>::template type, T>::template type, DT>(
479 dataType, dtl, visitor, scatterAccess, access.size_);
480 }
481 }
482
484 template <size_t VisitorArgCount, template <class...> class T, class VISITOR, class DT, class... DTL,
485 class... ACCESSES,
486 std::enable_if_t<(sizeof...(ACCESSES) + 1 == VisitorArgCount || sizeof...(ACCESSES) == 0), int> = 0>
487 auto VisitAccessesAs(VISITOR &&visitor, Cvb::DataType dataType, DispatchableTypeList<DT, DTL...> dtl,
488 const LinearAccessAndSize &access, const ACCESSES &...accesses)
489 {
490 if (auto aPlane0Access = MakeArrayAccessIfAllAre(access.size_, access.access_, accesses.access_...))
491 return CallWithAnyOfTypes<TemplatedTypeBuilder<T>::template type, DT>(
492 dataType, dtl,
493 [=](auto typedThingy) {
494 visitor(typedThingy(aPlane0Access, access.size_),
495 typedThingy(ArrayAccess::FromLinearAccess(accesses.access_, accesses.size_), accesses.size_)...);
496 },
497 access.size_);
498 else
499 return CallWithAnyOfTypes<TemplatedTypeBuilder<T>::template type, DT>(
500 dataType, dtl,
501 [=](auto typedThingy) {
502 visitor(typedThingy(access.access_, access.size_), typedThingy(accesses.access_, accesses.size_)...);
503 },
504 access.size_);
505 }
506
507#pragma region VpatVisit
508
509 template <class INVOKER, size_t... I>
510 auto InvokeWithLinearAccessesAndSizes(INVOKER &&invoker, const std::array<LinearAccess, sizeof...(I)> &accesses,
511 const std::array<Cvb::Size2D<int>, sizeof...(I)> &sizes,
512 std::index_sequence<I...>)
513 {
514 return std::forward<INVOKER>(invoker)(LinearAccessAndSize{accesses[I], sizes[I]}...);
515 }
516
518 template <size_t VisitorArgCount, class VISITOR, class DT, class... DTL, class... ACCESSES,
519 std::enable_if_t<VisitorArgCount == sizeof...(ACCESSES) + 1 || sizeof...(ACCESSES) == 0, int> = 0>
520 auto VisitAccesses(VISITOR &&visitor, Cvb::DataType dataType, DispatchableTypeList<DT, DTL...> dtl,
521 const VpatAndSize &vpatAndSize, const ACCESSES &...vpatAndSizes)
522 {
523 const auto lPlaneAccesses =
524 MakeLinearAccessesIfAllAre(vpatAndSize.size_, dataType, vpatAndSize.access_, vpatAndSizes.access_...);
525 if (lPlaneAccesses[0])
526 {
527 return InvokeWithLinearAccessesAndSizes(
528 [visitor = std::forward<VISITOR>(visitor), dataType, dtl](auto &&...linAccessesAndSizes) {
529 return VisitAccesses<VisitorArgCount>(visitor, dataType, dtl, linAccessesAndSizes...);
530 },
531 lPlaneAccesses, {vpatAndSize.size_, vpatAndSizes.size_...},
532 std::make_index_sequence<sizeof...(ACCESSES) + 1>());
533 }
534
535 return CallWithAnyOfTypes<BlockBuilder, DT>(
536 dataType, dtl,
537 [visitor, vpatAndSize, vpatAndSizes...](auto typedThingy) {
538 visitor(typedThingy(vpatAndSize.access_, vpatAndSize.size_),
539 typedThingy(vpatAndSizes.access_, vpatAndSizes.size_)...);
540 },
541 vpatAndSize.size_);
542 }
543
545 template <size_t VisitorArgCount, class VISITOR, class DT, class... DTL, class... ACCESSES,
546 std::enable_if_t<VisitorArgCount == 1 && sizeof...(ACCESSES) != 0, int> = 0>
547 auto VisitAccesses(VISITOR &&visitor, Cvb::DataType dataType, DispatchableTypeList<DT, DTL...> dtl,
548 const VpatAndSize &vpatAndSize, const ACCESSES &...vpatAndSizes)
549 {
550 const auto lPlaneAccesses =
551 MakeLinearAccessesIfAllAre(vpatAndSize.size_, dataType, vpatAndSize.access_, vpatAndSizes.access_...);
552 if (lPlaneAccesses[0])
553 {
554 return InvokeWithLinearAccessesAndSizes(
555 [visitor = std::forward<VISITOR>(visitor), dataType, dtl](auto &&...linAccessesAndSizes) {
556 return VisitAccesses<VisitorArgCount>(visitor, dataType, dtl, linAccessesAndSizes...);
557 },
558 lPlaneAccesses, {vpatAndSize.size_, vpatAndSizes.size_...},
559 std::make_index_sequence<sizeof...(ACCESSES) + 1>());
560 }
561
562 // avoid one instantiation for the (hopefully rather uncommon VPAT case): just use a vpat scatter block directly
563 // instead of vpat with LinearValue + vpat with RefValue.
564 auto scatterAccess = MakeStaticScatterAccess(vpatAndSize.access_, vpatAndSizes.access_...);
565
566 constexpr const size_t NumAccesses = 1 + sizeof...(ACCESSES);
567 return CallWithAnyOfTypes<
568 TemplatedTypeBlock<TemplatedSizedType<ScatterBlock, NumAccesses>::template type,
569 TemplatedSizedType<RefValue, NumAccesses>::template type>::template type,
570 DT>(dataType, dtl, std::forward<VISITOR>(visitor), scatterAccess, vpatAndSize.size_);
571 }
572
574 template <
575 size_t VisitorArgCount, class T, class VISITOR, class... DTL, class... ACCESSES,
576 std::enable_if_t<!std::is_arithmetic<T>::value && (VisitorArgCount == 1 && sizeof...(ACCESSES) != 0), int> = 0>
577 auto VisitAccessesAs(VISITOR &&visitor, Cvb::DataType dataType, DispatchableTypeList<DTL...> dtl,
578 const VpatAndSize &vpatAndSize, const ACCESSES &...vpatAndSizes)
579 {
580 const auto lPlaneAccesses =
581 MakeLinearAccessesIfAllAre(vpatAndSize.size_, dataType, vpatAndSize.access_, vpatAndSizes.access_...);
582 if (lPlaneAccesses[0])
583 {
584 return InvokeWithLinearAccessesAndSizes(
585 [visitor = std::forward<VISITOR>(visitor), dataType, dtl](auto &&...linAccessesAndSizes) {
586 return VisitAccessesAs<VisitorArgCount, T>(visitor, dataType, dtl, linAccessesAndSizes...);
587 },
588 lPlaneAccesses, {vpatAndSize.size_, vpatAndSizes.size_...},
589 std::make_index_sequence<sizeof...(ACCESSES) + 1>());
590 }
591
592 // avoid one instantiation for the (hopefully rather uncommon VPAT case): just use a vpat scatter block directly
593 // instead of vpat with LinearValue + vpat with RefValue.
594 auto scatterAccess = MakeStaticScatterAccess(vpatAndSize.access_, vpatAndSizes.access_...);
595
596 constexpr const size_t NumAccesses = 1 + sizeof...(ACCESSES);
597 return visitor(ScatterBlock<T, NumAccesses>{scatterAccess, vpatAndSize.size_});
598 }
599
601 template <
602 size_t VisitorArgCount, class T, class VISITOR, class... DTL, class... ACCESSES,
603 std::enable_if_t<std::is_arithmetic<T>::value && (VisitorArgCount == 1 && sizeof...(ACCESSES) != 0), int> = 0>
604 auto VisitAccessesAs(VISITOR &&visitor, Cvb::DataType dataType, DispatchableTypeList<DTL...> dtl,
605 const VpatAndSize &vpatAndSize, const ACCESSES &...vpatAndSizes)
606 {
607 const auto lPlaneAccesses =
608 MakeLinearAccessesIfAllAre(vpatAndSize.size_, dataType, vpatAndSize.access_, vpatAndSizes.access_...);
609 if (lPlaneAccesses[0])
610 {
611 return InvokeWithLinearAccessesAndSizes(
612 [visitor = std::forward<VISITOR>(visitor), dataType, dtl](auto &&...linAccessesAndSizes) {
613 return VisitAccessesAs<VisitorArgCount, T>(visitor, dataType, dtl, linAccessesAndSizes...);
614 },
615 lPlaneAccesses, {vpatAndSize.size_, vpatAndSizes.size_...},
616 std::make_index_sequence<sizeof...(ACCESSES) + 1>());
617 }
618
619 // avoid one instantiation for the (hopefully rather uncommon VPAT case): just use a vpat scatter block directly
620 // instead of vpat with LinearValue + vpat with RefValue.
621 auto scatterAccess = MakeStaticScatterAccess(vpatAndSize.access_, vpatAndSizes.access_...);
622
623 constexpr const size_t NumAccesses = 1 + sizeof...(ACCESSES);
624 return visitor(ScatterBlock<RefValue<T, NumAccesses>, NumAccesses>{scatterAccess, vpatAndSize.size_});
625 }
626
628 template <size_t VisitorArgCount, class T, class VISITOR, class... DTL, class... ACCESSES,
629 std::enable_if_t<(VisitorArgCount == sizeof...(ACCESSES) + 1 || sizeof...(ACCESSES) == 0), int> = 0>
630 auto VisitAccessesAs(VISITOR &&visitor, Cvb::DataType dataType, DispatchableTypeList<DTL...> dtl,
631 const VpatAndSize &vpatAndSize, const ACCESSES &...vpatAndSizes)
632 {
633 const auto lPlaneAccesses =
634 MakeLinearAccessesIfAllAre(vpatAndSize.size_, dataType, vpatAndSize.access_, vpatAndSizes.access_...);
635 if (lPlaneAccesses[0])
636 {
637 return InvokeWithLinearAccessesAndSizes(
638 [visitor = std::forward<VISITOR>(visitor), dataType, dtl](auto &&...linAccessesAndSizes) {
639 return VisitAccessesAs<VisitorArgCount, T>(visitor, dataType, dtl, linAccessesAndSizes...);
640 },
641 lPlaneAccesses, {vpatAndSize.size_, vpatAndSizes.size_...},
642 std::make_index_sequence<sizeof...(ACCESSES) + 1>());
643 }
644
645 return std::forward<VISITOR>(visitor)(VpatPlaneBlock<T>{vpatAndSize.access_, vpatAndSize.size_},
646 VpatPlaneBlock<T>{vpatAndSizes.access_, vpatAndSizes.size_}...);
647 }
648
650 template <size_t VisitorArgCount, template <class...> class T, class VISITOR, class DT, class... DTL,
651 class... ACCESSES, std::enable_if_t<VisitorArgCount == 1 && sizeof...(ACCESSES) != 0, int> = 0>
652 auto VisitAccessesAs(VISITOR &&visitor, Cvb::DataType dataType, DispatchableTypeList<DT, DTL...> dtl,
653 const VpatAndSize &vpatAndSize, const ACCESSES &...vpatAndSizes)
654 {
655 const auto lPlaneAccesses =
656 MakeLinearAccessesIfAllAre(vpatAndSize.size_, dataType, vpatAndSize.access_, vpatAndSizes.access_...);
657 if (lPlaneAccesses[0])
658 {
659 return InvokeWithLinearAccessesAndSizes(
660 [visitor = std::forward<VISITOR>(visitor), dataType, dtl](auto &&...linAccessesAndSizes) {
661 return VisitAccessesAs<VisitorArgCount, T>(visitor, dataType, dtl, linAccessesAndSizes...);
662 },
663 lPlaneAccesses, {vpatAndSize.size_, vpatAndSizes.size_...},
664 std::make_index_sequence<sizeof...(ACCESSES) + 1>());
665 }
666
667 // avoid one instantiation for the (hopefully rather uncommon VPAT case): just use a vpat scatter block directly
668 // instead of vpat with LinearValue + vpat with RefValue.
669 auto scatterAccess = MakeStaticScatterAccess(vpatAndSize.access_, vpatAndSizes.access_...);
670
671 constexpr const size_t NumAccesses = 1 + sizeof...(ACCESSES);
672 return CallWithAnyOfTypes<
673 TemplatedTypeBlock<TemplatedSizedType<ScatterBlock, NumAccesses>::template type, T>::template type, DT>(
674 dataType, dtl, std::forward<VISITOR>(visitor), scatterAccess, vpatAndSize.size_);
675 }
676
678 template <size_t VisitorArgCount, template <class...> class T, class VISITOR, class DT, class... DTL,
679 class... ACCESSES,
680 std::enable_if_t<VisitorArgCount == sizeof...(ACCESSES) + 1 || sizeof...(ACCESSES) == 0, int> = 0>
681 auto VisitAccessesAs(VISITOR &&visitor, Cvb::DataType dataType, DispatchableTypeList<DT, DTL...> dtl,
682 const VpatAndSize &vpatAndSize, const ACCESSES &...vpatAndSizes)
683 {
684 const auto lPlaneAccesses =
685 MakeLinearAccessesIfAllAre(vpatAndSize.size_, dataType, vpatAndSize.access_, vpatAndSizes.access_...);
686 if (lPlaneAccesses[0])
687 {
688 return InvokeWithLinearAccessesAndSizes(
689 [visitor = std::forward<VISITOR>(visitor), dataType, dtl](auto &&...linAccessesAndSizes) {
690 return VisitAccessesAs<VisitorArgCount, T>(visitor, dataType, dtl, linAccessesAndSizes...);
691 },
692 lPlaneAccesses, {vpatAndSize.size_, vpatAndSizes.size_...},
693 std::make_index_sequence<sizeof...(ACCESSES) + 1>());
694 }
695
696 return CallWithAnyOfTypes<TemplatedTypeBuilder<T>::template type, DT>(
697 dataType, dtl,
698 [=](auto typedThingy) {
699 visitor(typedThingy(vpatAndSize.access_, vpatAndSize.size_),
700 typedThingy(vpatAndSizes.access_, vpatAndSizes.size_)...);
701 },
702 vpatAndSize.size_);
703 }
704
706 template <class PIXEL_TYPE, class VISITOR, class... DTL>
707 auto VisitAccessesAs(VISITOR &&visitor, Cvb::DataType dataType, DispatchableTypeList<DTL...>,
708 const VpatAndSize &accessAndSize)
709 {
710 Internal::BlockBuilder<PIXEL_TYPE> builder{accessAndSize.size_};
711 if (const auto linearAccess = LinearAccess::FromVpat(accessAndSize.access_, accessAndSize.size_, dataType))
712 {
713 if (const auto arrayAccess = ArrayAccess::FromLinearAccess(linearAccess, accessAndSize.size_))
714 return std::forward<VISITOR>(visitor)(builder(arrayAccess));
715 else
716 return std::forward<VISITOR>(visitor)(builder(linearAccess));
717 }
718 else
719 return std::forward<VISITOR>(visitor)(builder(accessAndSize.access_));
720 }
721#pragma endregion VpatVisit
722
723 // multi plane dispatch
724 template <class T, class VISITOR, class PLANE_T, class... PLNS,
725 std::enable_if_t<!std::is_arithmetic<T>::value, int> = 0>
726 auto VisitPlanesAs(VISITOR &&visitor, const PLANE_T &plane, const PLNS &...planes)
727 {
728 using PlaneTrait = PlaneTraits<PLANE_T>;
729 constexpr const size_t ArgCount = 1 + sizeof...(PLNS);
730 constexpr const size_t VisitorArgCount =
731 Cvb::Internal::IsCallableMParameters<VISITOR, ArgCount, Block<T, LinearAccess>>::value ? ArgCount : 1;
732
733 static_assert(VisitorArgCount == ArgCount || VisitorArgCount == 1,
734 "Cvb: visitor must have either one argument or as many arguments as plane arguments are given.");
735
736 if (!PlaneTrait::GetDataType(plane).template Matches<ComponentOfT<T>>()
737 || !AllPlanesHaveSameDataType(plane, planes...))
738 throw std::domain_error{"The requested planes must have all the same data type"};
739
740#pragma warning(push, 4)
741#pragma warning(disable : 4127)
742 if (VisitorArgCount == 1 && !AllPlanesHaveSameSize(plane, planes...))
743 throw std::domain_error{"Planes must have same size."};
744#pragma warning(pop)
745
746 return VisitAccessesAs<VisitorArgCount, T>(std::forward<VISITOR>(visitor), PlaneTrait::GetDataType(plane),
747 typename PlaneTrait::TypeList{}, GetAccessAndSize(plane),
748 GetAccessAndSize(planes)...);
749 }
750
751 // multi plane dispatch for integral Ts
752 template <class T, class VISITOR, class PLANE_T, class... PLNS,
753 std::enable_if_t<std::is_arithmetic<T>::value, int> = 0>
754 auto VisitPlanesAs(VISITOR &&visitor, const PLANE_T &plane, const PLNS &...planes)
755 {
756 using PlaneTrait = PlaneTraits<PLANE_T>;
757 constexpr const size_t ArgCount = 1 + sizeof...(PLNS);
758 constexpr const size_t VisitorArgCount =
759 Cvb::Internal::IsCallableMParameters<VISITOR, ArgCount, Block<T, LinearAccess>>::value ? ArgCount : 1;
760
761 static_assert(VisitorArgCount == ArgCount || VisitorArgCount == 1,
762 "Cvb: visitor must have either one argument or as many arguments as plane arguments are given.");
763
764 if (!PlaneTrait::GetDataType(plane).template Matches<T>() || !AllPlanesHaveSameDataType(plane, planes...))
765 throw std::domain_error{"The requested planes must have all the same data type"};
766
767#pragma warning(push, 4)
768#pragma warning(disable : 4127)
769 if (VisitorArgCount == 1 && !AllPlanesHaveSameSize(plane, planes...))
770 throw std::domain_error{"Planes must have same size."};
771#pragma warning(pop)
772
773 return VisitAccessesAs<VisitorArgCount, T>(std::forward<VISITOR>(visitor), PlaneTrait::GetDataType(plane),
774 typename PlaneTrait::TypeList{}, GetAccessAndSize(plane),
775 GetAccessAndSize(planes)...);
776 }
777
778 // multi plane dispatch
779 template <template <class...> class T, class VISITOR, class PLANE_T, class... PLNS>
780 auto VisitPlanesAs(VISITOR &&visitor, const PLANE_T &plane, const PLNS &...planes)
781 {
782 using PlaneTrait = PlaneTraits<PLANE_T>;
783 constexpr const size_t ArgCount = 1 + sizeof...(PLNS);
784 constexpr const size_t VisitorArgCount =
785 Cvb::Internal::IsCallableMParameters<
786 VISITOR, ArgCount, Block<T<typename PlaneTrait::TypeList::DefaultType>, LinearAccess>>::value
787 ? ArgCount
788 : 1;
789
790 static_assert(VisitorArgCount == ArgCount || VisitorArgCount == 1,
791 "Cvb: visitor must have either one argument or as many arguments as plane arguments are given.");
792
793 if (!AllPlanesHaveSameDataType(plane, planes...))
794 throw std::domain_error{"The requested planes must have all the same data type"};
795
796#pragma warning(push, 4)
797#pragma warning(disable : 4127)
798 if (VisitorArgCount == 1 && !AllPlanesHaveSameSize(plane, planes...))
799 throw std::domain_error{"Planes must have same size."};
800#pragma warning(pop)
801
802 return VisitAccessesAs<VisitorArgCount, T>(std::forward<VISITOR>(visitor), PlaneTrait::GetDataType(plane),
803 typename PlaneTrait::TypeList{}, GetAccessAndSize(plane),
804 GetAccessAndSize(planes)...);
805 }
806
807 // single plane dispatch
808 template <class T, class VISITOR, class PLANE_T>
809 auto VisitPlanesAs(VISITOR &&visitor, const PLANE_T &plane)
810 {
811 static_assert(Cvb::Internal::is_callable<VISITOR(Block<T, LinearAccess>)>::value,
812 "Cvb: The visitor must be visitable with a single typed block.");
813
814 using PlaneTrait = PlaneTraits<PLANE_T>;
815 return VisitAccessesAs<1, T>(std::forward<VISITOR>(visitor), PlaneTrait::GetDataType(plane),
816 typename PlaneTrait::TypeList{}, GetAccessAndSize(plane));
817 }
818
819 template <class VISITOR, class PLANE_T, std::enable_if_t<!PlaneTraits<PLANE_T>::HasVpat, int> = 0>
820 auto VisitPlanes(VISITOR &&visitor, const PLANE_T &plane)
821 {
822 using PlaneTrait = PlaneTraits<PLANE_T>;
823 constexpr const size_t VisitorArgCount = 1;
824
825 const auto dataType = PlaneTrait::GetDataType(plane);
826 return VisitAccesses<VisitorArgCount>(std::forward<VISITOR>(visitor), dataType, typename PlaneTrait::TypeList{},
827 LinearAccessAndSize{LinearAccess::FromPlane(plane), GetBlockSize(plane)});
828 }
829
830 template <class VISITOR, class PLANE_T, std::enable_if_t<PlaneTraits<PLANE_T>::HasVpat, int> = 0>
831 auto VisitPlanes(VISITOR &&visitor, const PLANE_T &plane)
832 {
833 using PlaneTrait = PlaneTraits<PLANE_T>;
834 const auto blockSize = GetBlockSize(plane);
835 auto vpat = PlaneTrait::GetVpat(plane);
836 const Cvb::DataType dt = PlaneTrait::GetDataType(plane);
837 if (const auto access = LinearAccess::FromVpat(vpat, blockSize, dt))
838 {
839 if (const auto arrayAccess = ArrayAccess::FromLinearAccess(access, blockSize))
840 return CallWithAnyOfTypes<ArrayPlaneBlock, typename PlaneTrait::TypeList::DefaultType>(
841 dt, typename PlaneTrait::TypeList{}, visitor, arrayAccess, blockSize);
842 else
843 return CallWithAnyOfTypes<LinearPlaneBlock, typename PlaneTrait::TypeList::DefaultType>(
844 dt, typename PlaneTrait::TypeList{}, visitor, access, blockSize);
845 }
846 else
847 return CallWithAnyOfTypes<VpatPlaneBlock, typename PlaneTrait::TypeList::DefaultType>(
848 dt, typename PlaneTrait::TypeList{}, visitor, vpat, blockSize);
849 }
850
851 template <class VISITOR, class PLANE_T, class... PLANEARGS>
852 auto VisitPlanes(VISITOR &&visitor, const PLANE_T &plane, const PLANEARGS &...planes)
853 {
854 using PlaneTrait = PlaneTraits<PLANE_T>;
855 constexpr const size_t ArgCount = 1 + sizeof...(PLANEARGS);
856 constexpr const size_t VisitorArgCount =
857 Cvb::Internal::IsCallableMParameters<VISITOR, ArgCount,
858 Block<typename PlaneTrait::TypeList::DefaultType, LinearAccess>>::value
859 ? ArgCount
860 : 1;
861
862 static_assert(VisitorArgCount == ArgCount || VisitorArgCount == 1,
863 "Cvb: visitor must have either one argument or as many arguments as plane arguments are given.");
864
865 if (!AllPlanesHaveSameDataType(plane, planes...))
866 throw std::domain_error{"Planes must have all the same data type"};
867
868#pragma warning(push, 4)
869#pragma warning(disable : 4127)
870 if (VisitorArgCount == 1 && !AllPlanesHaveSameSize(plane, planes...))
871 throw std::domain_error{"Planes must have same size."};
872#pragma warning(pop)
873
874 return VisitAccesses<VisitorArgCount>(std::forward<VISITOR>(visitor), PlaneTrait::GetDataType(plane),
875 typename PlaneTrait::TypeList{}, GetAccessAndSize(plane),
876 GetAccessAndSize(planes)...);
877 }
878
879 } // namespace Internal
880
881 template <class VISITOR, class PLANE_T, class... PLNS,
882 std::enable_if_t<std::is_same<typename PlaneTraits<PLANE_T>::PlaneT, PLANE_T>::value, int>>
883 auto Visit(VISITOR &&visitor, const PLANE_T &plane, const PLNS &...planes)
884 {
885 return Internal::VisitPlanes(std::forward<VISITOR>(visitor), plane, planes...);
886 }
887
888 template <class T, class VISITOR, class PLANE_T, class... PLANEARGS,
889 std::enable_if_t<std::is_same<typename PlaneTraits<PLANE_T>::PlaneT, PLANE_T>::value, int>>
890 auto VisitAs(VISITOR &&visitor, const PLANE_T &plane, const PLANEARGS &...planes)
891 {
892 return Internal::VisitPlanesAs<T>(std::forward<VISITOR>(visitor), plane, planes...);
893 }
894
895 template <template <class...> class T, class VISITOR, class PLANE_T, class... PLANEARGS,
896 std::enable_if_t<std::is_same<typename PlaneTraits<PLANE_T>::PlaneT, PLANE_T>::value, int>>
897 auto VisitAs(VISITOR &&visitor, const PLANE_T &plane, const PLANEARGS &...planes)
898 {
899 return Internal::VisitPlanesAs<T>(std::forward<VISITOR>(visitor), plane, planes...);
900 }
901
902 template <class VISITOR>
903 auto Visit(VISITOR &&visitor, const PointCloud &cloud)
904 {
905 assert(cloud.PlaneCount() >= 3);
906 return Internal::VisitPlanes(std::forward<VISITOR>(visitor), *cloud.Plane(0), *cloud.Plane(1), *cloud.Plane(2));
907 }
908
909 template <class T, class VISITOR>
910 auto VisitAs(VISITOR &&visitor, const PointCloud &cloud)
911 {
912 assert(cloud.PlaneCount() >= 3);
913
914 return Internal::VisitPlanesAs<remove_cvref_t<T>>(std::forward<VISITOR>(visitor), *cloud.Plane(0), *cloud.Plane(1),
915 *cloud.Plane(2));
916 }
917
918 template <template <class...> class T, class VISITOR>
919 auto VisitAs(VISITOR &&visitor, const PointCloud &cloud)
920 {
921 assert(cloud.PlaneCount() >= 3);
922
923 return Internal::VisitPlanesAs<T>(std::forward<VISITOR>(visitor), *cloud.Plane(0), *cloud.Plane(1),
924 *cloud.Plane(2));
925 }
926
927 CVB_END_INLINE_NS
928} // 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:903
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:910
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:361
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:74
PlanePtr Plane(int index) const
Index based plane access.
Definition decl_point_cloud.hpp:716
int PlaneCount() const noexcept
Gets the number of planes enumerated by this object.
Definition decl_point_cloud.hpp:689
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 version.hpp:11
Definition global.hpp:1049