VTK-m  2.2
VariantImplDetail.h
Go to the documentation of this file.
1 //============================================================================
2 // Copyright (c) Kitware, Inc.
3 // All rights reserved.
4 // See LICENSE.txt for details.
5 //
6 // This software is distributed WITHOUT ANY WARRANTY; without even
7 // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
8 // PURPOSE. See the above copyright notice for more information.
9 //============================================================================
10 // **** DO NOT EDIT THIS FILE!!! ****
11 // This file is automatically generated by VariantDetail.h.in
12 
13 #if !defined(VTK_M_DEVICE) || !defined(VTK_M_NAMESPACE)
14 #error VarianImplDetail.h must be included from VariantImpl.h
15 // Some defines to make my IDE happy.
16 #define VTK_M_DEVICE
17 #define VTK_M_NAMESPACE tmp
18 #endif
19 
20 #include <vtkm/List.h>
21 #include <vtkm/Types.h>
22 
23 #include <vtkm/internal/Assume.h>
24 
25 #include <vtkmstd/is_trivial.h>
26 
27 #include <algorithm>
28 #include <cstddef>
29 #include <type_traits>
30 
31 
32 
33 namespace vtkm
34 {
35 namespace VTK_M_NAMESPACE
36 {
37 namespace detail
38 {
39 
40 // --------------------------------------------------------------------------------
41 // Helper classes to determine if all Variant types are trivial.
42 template <typename... Ts>
43 using AllTriviallyCopyable = vtkm::ListAll<vtkm::List<Ts...>, vtkmstd::is_trivially_copyable>;
44 
45 // Single argument version of is_trivially_constructible
46 template <typename T>
47 using Constructible = vtkmstd::is_trivially_constructible<T>;
48 
49 template <typename... Ts>
50 using AllTriviallyConstructible = vtkm::ListAll<vtkm::List<Ts...>, Constructible>;
51 
52 template <typename... Ts>
53 using AllTriviallyDestructible =
54  vtkm::ListAll<vtkm::List<Ts...>, vtkmstd::is_trivially_destructible>;
55 
56 // --------------------------------------------------------------------------------
57 // Helper functions to determine the maximum type size.
58 #if defined(VTKM_GCC) && (__GNUC__ == 5)
59 // GCC5 gives an error with `sizeof(Ts)...` for an unexpanded parameter pack.
60 template <typename T0>
61 constexpr std::size_t MaxSizeOf()
62 {
63  return sizeof(T0);
64 }
65 template <typename T0, typename T1, typename... Ts>
66 constexpr std::size_t MaxSizeOf()
67 {
68  return std::max(sizeof(T0), MaxSizeOf<T1, Ts...>());
69 }
70 #else
71 template <typename... Ts>
72 constexpr std::size_t MaxSizeOf()
73 {
74  return std::max({ sizeof(Ts)... });
75 }
76 #endif
77 
78 // --------------------------------------------------------------------------------
79 // Helper functions to determine the maximum alignment size.
80 template <typename... Ts>
81 constexpr std::size_t MaxAlignmentOf()
82 {
83  return std::max({ std::alignment_of<Ts>::value... });
84 }
85 
86 // --------------------------------------------------------------------------------
87 // Placeholder for a fully used structure of the given type.
88 // This placeholder is used for compilers that do not correctly copy `struct`s
89 // in `union`s where some of the `struct`s have padding. This is added to the
90 // front of the `union` for the compiler to pick up and use.
91 //
92 // It is normally sufficient to have a full `struct`, but we have also encountered
93 // compilers that only use it if the alignment is at least as large. But we
94 // don't want the alignment too large because it can add unwanted padding
95 // elsewhere. Also, adding `alignas` did not work to resolve this problem for
96 // the compiler.
97 
98 template <std::size_t Alignment>
99 struct TypeForAlignmentImpl;
100 template <>
101 struct TypeForAlignmentImpl<8>
102 {
103  using type = vtkm::Int64;
104 };
105 template <>
106 struct TypeForAlignmentImpl<4>
107 {
108  using type = vtkm::Int32;
109 };
110 template <>
111 struct TypeForAlignmentImpl<2>
112 {
113  using type = vtkm::Int16;
114 };
115 template <>
116 struct TypeForAlignmentImpl<1>
117 {
118  using type = vtkm::Int8;
119 };
120 template <std::size_t Alignment>
121 using TypeForAlignment = typename TypeForAlignmentImpl<Alignment>::type;
122 
123 template <std::size_t Size, typename Word, bool = (Size >= 4)>
124 struct SizedPlaceholderImpl;
125 
126 template <std::size_t Size, typename Word>
127 struct SizedPlaceholderImpl<Size, Word, true>
128 {
129  Word A;
130  Word B;
131  Word C;
132  Word D;
133  SizedPlaceholderImpl<Size - 4, Word> E;
134 };
135 template <typename Word>
136 struct SizedPlaceholderImpl<4, Word, true>
137 {
138  Word A;
139  Word B;
140  Word C;
141  Word D;
142 };
143 
144 template <std::size_t Size, typename Word>
145 struct SizedPlaceholderImpl<Size, Word, false>
146 {
147  Word A;
148  SizedPlaceholderImpl<Size - 1, Word> B;
149 };
150 template <typename Word>
151 struct SizedPlaceholderImpl<1, Word, false>
152 {
153  Word A;
154 };
155 
156 template <typename... Ts>
157 struct SizedPlaceholder
158  : SizedPlaceholderImpl<(MaxSizeOf<Ts...>() / MaxAlignmentOf<Ts...>()),
159  TypeForAlignment<MaxAlignmentOf<Ts...>()>>
160 {
161 };
162 
163 // clang-format off
164 
165 // --------------------------------------------------------------------------------
166 // Union type used inside of Variant
167 //
168 // You may be asking yourself, why not just use an std::aligned_union rather than a real union
169 // type? That was our first implementation, but the problem is that the std::aligned_union
170 // reference needs to be recast to the actual type. Typically you would do that with
171 // reinterpret_cast. However, doing that leads to undefined behavior. The C++ compiler assumes that
172 // 2 pointers of different types point to different memory (even if it is clear that they are set
173 // to the same address). That means optimizers can remove code because it "knows" that data in one
174 // type cannot affect data in another type. (See Shafik Yaghmour's excellent writeup at
175 // https://gist.github.com/shafik/848ae25ee209f698763cffee272a58f8 for more details.) To safely
176 // change the type of an std::aligned_union, you really have to do an std::memcpy. This is
177 // problematic for types that cannot be trivially copied. Another problem is that we found that
178 // device compilers do not optimize the memcpy as well as most CPU compilers. Likely, memcpy is
179 // used much less frequently on GPU devices.
180 //
181 // Part of the trickiness of the union implementation is trying to preserve when the type is
182 // trivially constructible and copyable. The trick is that if members of the union are not trivial,
183 // then the default constructors are deleted. To get around that, a non-default constructor is
184 // added, which we can use to construct the union for non-trivial types. Working with types with
185 // non-trivial destructors are particularly tricky. Again, if any member of the union has a
186 // non-trivial destructor, the destructor is deleted. Unlike a constructor, you cannot just say to
187 // use a different destructor. Thus, we have to define our own destructor for the union.
188 // Technically, the destructor here does not do anything, but the actual destruction should be
189 // handled by the Variant class that contains this VariantUnion. We actually need two separate
190 // implementations of our union, one that defines a destructor and one that use the default
191 // destructor. If you define your own destructor, you can lose the trivial constructor and trivial
192 // copy properties.
193 //
194 
195 // TD = trivially deconstructible
196 template <typename T0, typename... Ts>
197 union VariantUnionTD;
198 
199 // NTD = non-trivially deconstructible
200 template <typename T0, typename... Ts>
201 union VariantUnionNTD;
202 
203 template <typename T0>
204 union VariantUnionTD<T0>
205 {
206  // Work around issue where some compilers miss initializing some struct members if another entry
207  // in the varient has a struct with padding. Place an item that requires everthing to be copied.
208  SizedPlaceholder<T0> Placeholder;
209 
210  T0 V0;
211  VTK_M_DEVICE VariantUnionTD(vtkm::internal::NullType) { }
212  VariantUnionTD() = default;
213 };
214 template <typename T0>
215 union VariantUnionNTD<T0>
216 {
217  // Work around issue where some compilers miss initializing some struct members if another entry
218  // in the varient has a struct with padding. Place an item that requires everthing to be copied.
219  SizedPlaceholder<T0> Placeholder;
220 
221  T0 V0;
222  VTK_M_DEVICE VariantUnionNTD(vtkm::internal::NullType) { }
223  VariantUnionNTD() = default;
224  VTK_M_DEVICE ~VariantUnionNTD() { }
225 };
226 
227 template <typename T0, typename T1>
228 union VariantUnionTD<T0, T1>
229 {
230  // Work around issue where some compilers miss initializing some struct members if another entry
231  // in the varient has a struct with padding. Place an item that requires everthing to be copied.
232  SizedPlaceholder<T0, T1> Placeholder;
233 
234  T0 V0;
235  T1 V1;
236  VTK_M_DEVICE VariantUnionTD(vtkm::internal::NullType) { }
237  VariantUnionTD() = default;
238 };
239 template <typename T0, typename T1>
240 union VariantUnionNTD<T0, T1>
241 {
242  // Work around issue where some compilers miss initializing some struct members if another entry
243  // in the varient has a struct with padding. Place an item that requires everthing to be copied.
244  SizedPlaceholder<T0, T1> Placeholder;
245 
246  T0 V0;
247  T1 V1;
248  VTK_M_DEVICE VariantUnionNTD(vtkm::internal::NullType) { }
249  VariantUnionNTD() = default;
250  VTK_M_DEVICE ~VariantUnionNTD() { }
251 };
252 
253 template <typename T0, typename T1, typename T2>
254 union VariantUnionTD<T0, T1, T2>
255 {
256  // Work around issue where some compilers miss initializing some struct members if another entry
257  // in the varient has a struct with padding. Place an item that requires everthing to be copied.
258  SizedPlaceholder<T0, T1, T2> Placeholder;
259 
260  T0 V0;
261  T1 V1;
262  T2 V2;
263  VTK_M_DEVICE VariantUnionTD(vtkm::internal::NullType) { }
264  VariantUnionTD() = default;
265 };
266 template <typename T0, typename T1, typename T2>
267 union VariantUnionNTD<T0, T1, T2>
268 {
269  // Work around issue where some compilers miss initializing some struct members if another entry
270  // in the varient has a struct with padding. Place an item that requires everthing to be copied.
271  SizedPlaceholder<T0, T1, T2> Placeholder;
272 
273  T0 V0;
274  T1 V1;
275  T2 V2;
276  VTK_M_DEVICE VariantUnionNTD(vtkm::internal::NullType) { }
277  VariantUnionNTD() = default;
278  VTK_M_DEVICE ~VariantUnionNTD() { }
279 };
280 
281 template <typename T0, typename T1, typename T2, typename T3>
282 union VariantUnionTD<T0, T1, T2, T3>
283 {
284  // Work around issue where some compilers miss initializing some struct members if another entry
285  // in the varient has a struct with padding. Place an item that requires everthing to be copied.
286  SizedPlaceholder<T0, T1, T2, T3> Placeholder;
287 
288  T0 V0;
289  T1 V1;
290  T2 V2;
291  T3 V3;
292  VTK_M_DEVICE VariantUnionTD(vtkm::internal::NullType) { }
293  VariantUnionTD() = default;
294 };
295 template <typename T0, typename T1, typename T2, typename T3>
296 union VariantUnionNTD<T0, T1, T2, T3>
297 {
298  // Work around issue where some compilers miss initializing some struct members if another entry
299  // in the varient has a struct with padding. Place an item that requires everthing to be copied.
300  SizedPlaceholder<T0, T1, T2, T3> Placeholder;
301 
302  T0 V0;
303  T1 V1;
304  T2 V2;
305  T3 V3;
306  VTK_M_DEVICE VariantUnionNTD(vtkm::internal::NullType) { }
307  VariantUnionNTD() = default;
308  VTK_M_DEVICE ~VariantUnionNTD() { }
309 };
310 
311 template <typename T0, typename T1, typename T2, typename T3, typename T4>
312 union VariantUnionTD<T0, T1, T2, T3, T4>
313 {
314  // Work around issue where some compilers miss initializing some struct members if another entry
315  // in the varient has a struct with padding. Place an item that requires everthing to be copied.
316  SizedPlaceholder<T0, T1, T2, T3, T4> Placeholder;
317 
318  T0 V0;
319  T1 V1;
320  T2 V2;
321  T3 V3;
322  T4 V4;
323  VTK_M_DEVICE VariantUnionTD(vtkm::internal::NullType) { }
324  VariantUnionTD() = default;
325 };
326 template <typename T0, typename T1, typename T2, typename T3, typename T4>
327 union VariantUnionNTD<T0, T1, T2, T3, T4>
328 {
329  // Work around issue where some compilers miss initializing some struct members if another entry
330  // in the varient has a struct with padding. Place an item that requires everthing to be copied.
331  SizedPlaceholder<T0, T1, T2, T3, T4> Placeholder;
332 
333  T0 V0;
334  T1 V1;
335  T2 V2;
336  T3 V3;
337  T4 V4;
338  VTK_M_DEVICE VariantUnionNTD(vtkm::internal::NullType) { }
339  VariantUnionNTD() = default;
340  VTK_M_DEVICE ~VariantUnionNTD() { }
341 };
342 
343 template <typename T0, typename T1, typename T2, typename T3, typename T4, typename T5>
344 union VariantUnionTD<T0, T1, T2, T3, T4, T5>
345 {
346  // Work around issue where some compilers miss initializing some struct members if another entry
347  // in the varient has a struct with padding. Place an item that requires everthing to be copied.
348  SizedPlaceholder<T0, T1, T2, T3, T4, T5> Placeholder;
349 
350  T0 V0;
351  T1 V1;
352  T2 V2;
353  T3 V3;
354  T4 V4;
355  T5 V5;
356  VTK_M_DEVICE VariantUnionTD(vtkm::internal::NullType) { }
357  VariantUnionTD() = default;
358 };
359 template <typename T0, typename T1, typename T2, typename T3, typename T4, typename T5>
360 union VariantUnionNTD<T0, T1, T2, T3, T4, T5>
361 {
362  // Work around issue where some compilers miss initializing some struct members if another entry
363  // in the varient has a struct with padding. Place an item that requires everthing to be copied.
364  SizedPlaceholder<T0, T1, T2, T3, T4, T5> Placeholder;
365 
366  T0 V0;
367  T1 V1;
368  T2 V2;
369  T3 V3;
370  T4 V4;
371  T5 V5;
372  VTK_M_DEVICE VariantUnionNTD(vtkm::internal::NullType) { }
373  VariantUnionNTD() = default;
374  VTK_M_DEVICE ~VariantUnionNTD() { }
375 };
376 
377 template <typename T0, typename T1, typename T2, typename T3, typename T4, typename T5, typename T6>
378 union VariantUnionTD<T0, T1, T2, T3, T4, T5, T6>
379 {
380  // Work around issue where some compilers miss initializing some struct members if another entry
381  // in the varient has a struct with padding. Place an item that requires everthing to be copied.
382  SizedPlaceholder<T0, T1, T2, T3, T4, T5, T6> Placeholder;
383 
384  T0 V0;
385  T1 V1;
386  T2 V2;
387  T3 V3;
388  T4 V4;
389  T5 V5;
390  T6 V6;
391  VTK_M_DEVICE VariantUnionTD(vtkm::internal::NullType) { }
392  VariantUnionTD() = default;
393 };
394 template <typename T0, typename T1, typename T2, typename T3, typename T4, typename T5, typename T6>
395 union VariantUnionNTD<T0, T1, T2, T3, T4, T5, T6>
396 {
397  // Work around issue where some compilers miss initializing some struct members if another entry
398  // in the varient has a struct with padding. Place an item that requires everthing to be copied.
399  SizedPlaceholder<T0, T1, T2, T3, T4, T5, T6> Placeholder;
400 
401  T0 V0;
402  T1 V1;
403  T2 V2;
404  T3 V3;
405  T4 V4;
406  T5 V5;
407  T6 V6;
408  VTK_M_DEVICE VariantUnionNTD(vtkm::internal::NullType) { }
409  VariantUnionNTD() = default;
410  VTK_M_DEVICE ~VariantUnionNTD() { }
411 };
412 
413 template <typename T0, typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7>
414 union VariantUnionTD<T0, T1, T2, T3, T4, T5, T6, T7>
415 {
416  // Work around issue where some compilers miss initializing some struct members if another entry
417  // in the varient has a struct with padding. Place an item that requires everthing to be copied.
418  SizedPlaceholder<T0, T1, T2, T3, T4, T5, T6, T7> Placeholder;
419 
420  T0 V0;
421  T1 V1;
422  T2 V2;
423  T3 V3;
424  T4 V4;
425  T5 V5;
426  T6 V6;
427  T7 V7;
428  VTK_M_DEVICE VariantUnionTD(vtkm::internal::NullType) { }
429  VariantUnionTD() = default;
430 };
431 template <typename T0, typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7>
432 union VariantUnionNTD<T0, T1, T2, T3, T4, T5, T6, T7>
433 {
434  // Work around issue where some compilers miss initializing some struct members if another entry
435  // in the varient has a struct with padding. Place an item that requires everthing to be copied.
436  SizedPlaceholder<T0, T1, T2, T3, T4, T5, T6, T7> Placeholder;
437 
438  T0 V0;
439  T1 V1;
440  T2 V2;
441  T3 V3;
442  T4 V4;
443  T5 V5;
444  T6 V6;
445  T7 V7;
446  VTK_M_DEVICE VariantUnionNTD(vtkm::internal::NullType) { }
447  VariantUnionNTD() = default;
448  VTK_M_DEVICE ~VariantUnionNTD() { }
449 };
450 
451 
452 template <typename T0, typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7, typename T8, typename... Ts>
453 union VariantUnionTD<T0, T1, T2, T3, T4, T5, T6, T7, T8, Ts...>
454 {
455  // Work around issue where CUDA sometimes seems to miss initializing some struct members
456  // if another entry in the varient has a struct with padding. Place an item that requires
457  // everthing to be copied.
458  SizedPlaceholder<T0, T1, T2, T3, T4, T5, T6, T7, T8, Ts...> Placeholder;
459 
460  T0 V0;
461  T1 V1;
462  T2 V2;
463  T3 V3;
464  T4 V4;
465  T5 V5;
466  T6 V6;
467  T7 V7;
468  VariantUnionTD<T8, Ts...> Remaining;
469 
470  VTK_M_DEVICE VariantUnionTD(vtkm::internal::NullType) { }
471  VariantUnionTD() = default;
472 };
473 
474 template <typename T0, typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7, typename T8, typename... Ts>
475 union VariantUnionNTD<T0, T1, T2, T3, T4, T5, T6, T7, T8, Ts...>
476 {
477  // Work around issue where CUDA sometimes seems to miss initializing some struct members
478  // if another entry in the varient has a struct with padding. Place an item that requires
479  // everthing to be copied.
480  SizedPlaceholder<T0, T1, T2, T3, T4, T5, T6, T7, T8, Ts...> Placeholder;
481 
482  T0 V0;
483  T1 V1;
484  T2 V2;
485  T3 V3;
486  T4 V4;
487  T5 V5;
488  T6 V6;
489  T7 V7;
490  VariantUnionNTD<T8, Ts...> Remaining;
491 
492  VTK_M_DEVICE VariantUnionNTD(vtkm::internal::NullType) { }
493  VariantUnionNTD() = default;
494  VTK_M_DEVICE ~VariantUnionNTD() { }
495 };
496 
497 //clang-format on
498 
499 template <bool TrivialConstructor, typename... Ts>
500 struct VariantUnionFinder;
501 
502 template <typename... Ts>
503 struct VariantUnionFinder<true, Ts...>
504 {
505  using type = VariantUnionTD<Ts...>;
506 };
507 template <typename... Ts>
508 struct VariantUnionFinder<false, Ts...>
509 {
510  using type = VariantUnionNTD<Ts...>;
511 };
512 
513 template <typename... Ts>
514 using VariantUnion =
515  typename VariantUnionFinder<AllTriviallyDestructible<Ts...>::value, Ts...>::type;
516 
517 // --------------------------------------------------------------------------------
518 // Methods to get values out of the variant union
519 template <vtkm::IdComponent I, typename UnionType>
520 struct VariantUnionGetImpl;
521 
522 template <typename UnionType>
523 struct VariantUnionGetImpl<0, UnionType>
524 {
525  using ReturnType = decltype(std::declval<UnionType>().V0);
526  VTK_M_DEVICE static ReturnType& Get(UnionType& storage) noexcept
527  {
528  return storage.V0;
529  }
530  VTK_M_DEVICE static const ReturnType& Get(const UnionType& storage) noexcept
531  {
532  return storage.V0;
533  }
534 };
535 
536 template <typename UnionType>
537 struct VariantUnionGetImpl<1, UnionType>
538 {
539  using ReturnType = decltype(std::declval<UnionType>().V1);
540  VTK_M_DEVICE static ReturnType& Get(UnionType& storage) noexcept
541  {
542  return storage.V1;
543  }
544  VTK_M_DEVICE static const ReturnType& Get(const UnionType& storage) noexcept
545  {
546  return storage.V1;
547  }
548 };
549 
550 template <typename UnionType>
551 struct VariantUnionGetImpl<2, UnionType>
552 {
553  using ReturnType = decltype(std::declval<UnionType>().V2);
554  VTK_M_DEVICE static ReturnType& Get(UnionType& storage) noexcept
555  {
556  return storage.V2;
557  }
558  VTK_M_DEVICE static const ReturnType& Get(const UnionType& storage) noexcept
559  {
560  return storage.V2;
561  }
562 };
563 
564 template <typename UnionType>
565 struct VariantUnionGetImpl<3, UnionType>
566 {
567  using ReturnType = decltype(std::declval<UnionType>().V3);
568  VTK_M_DEVICE static ReturnType& Get(UnionType& storage) noexcept
569  {
570  return storage.V3;
571  }
572  VTK_M_DEVICE static const ReturnType& Get(const UnionType& storage) noexcept
573  {
574  return storage.V3;
575  }
576 };
577 
578 template <typename UnionType>
579 struct VariantUnionGetImpl<4, UnionType>
580 {
581  using ReturnType = decltype(std::declval<UnionType>().V4);
582  VTK_M_DEVICE static ReturnType& Get(UnionType& storage) noexcept
583  {
584  return storage.V4;
585  }
586  VTK_M_DEVICE static const ReturnType& Get(const UnionType& storage) noexcept
587  {
588  return storage.V4;
589  }
590 };
591 
592 template <typename UnionType>
593 struct VariantUnionGetImpl<5, UnionType>
594 {
595  using ReturnType = decltype(std::declval<UnionType>().V5);
596  VTK_M_DEVICE static ReturnType& Get(UnionType& storage) noexcept
597  {
598  return storage.V5;
599  }
600  VTK_M_DEVICE static const ReturnType& Get(const UnionType& storage) noexcept
601  {
602  return storage.V5;
603  }
604 };
605 
606 template <typename UnionType>
607 struct VariantUnionGetImpl<6, UnionType>
608 {
609  using ReturnType = decltype(std::declval<UnionType>().V6);
610  VTK_M_DEVICE static ReturnType& Get(UnionType& storage) noexcept
611  {
612  return storage.V6;
613  }
614  VTK_M_DEVICE static const ReturnType& Get(const UnionType& storage) noexcept
615  {
616  return storage.V6;
617  }
618 };
619 
620 template <typename UnionType>
621 struct VariantUnionGetImpl<7, UnionType>
622 {
623  using ReturnType = decltype(std::declval<UnionType>().V7);
624  VTK_M_DEVICE static ReturnType& Get(UnionType& storage) noexcept
625  {
626  return storage.V7;
627  }
628  VTK_M_DEVICE static const ReturnType& Get(const UnionType& storage) noexcept
629  {
630  return storage.V7;
631  }
632 };
633 
634 
635 template <vtkm::IdComponent I, typename UnionType>
636 struct VariantUnionGetImpl
637 {
638  VTKM_STATIC_ASSERT(I >= 8);
639  using RecursiveGet = VariantUnionGetImpl<I - 8, decltype(std::declval<UnionType&>().Remaining)>;
640  using ReturnType = typename RecursiveGet::ReturnType;
641  VTK_M_DEVICE static ReturnType& Get(UnionType& storage) noexcept
642  {
643  return RecursiveGet::Get(storage.Remaining);
644  }
645  VTK_M_DEVICE static const ReturnType& Get(const UnionType& storage) noexcept
646  {
647  return RecursiveGet::Get(storage.Remaining);
648  }
649 };
650 
651 template <vtkm::IdComponent I, typename UnionType>
652 VTK_M_DEVICE auto VariantUnionGet(UnionType& storage) noexcept
653  -> decltype(VariantUnionGetImpl<I, typename std::decay<UnionType>::type>::Get(storage))&
654 {
655  return VariantUnionGetImpl<I, typename std::decay<UnionType>::type>::Get(storage);
656 }
657 
658 // --------------------------------------------------------------------------------
659 // Internal implementation of CastAndCall for Variant
660 template <std::size_t NumCases>
661 struct VariantCases
662 {
663  template <typename Functor, typename UnionType, typename... Args>
664  VTK_M_DEVICE static
665 #ifdef VTKM_HIP
666  // this is a temporary solution to improve Kokkos/HIP compile times for
667  // ConnectivityTracer in Rendering.
668  //
669  // This function currently gets inlined many times, which dramatically increases
670  // both compile time and the size of the resulting code-object
671  __attribute__((noinline))
672 #else
673  inline
674 #endif
675  auto CastAndCall(
676  vtkm::IdComponent index,
677  Functor&& f,
678  UnionType& storage,
679  Args&&... args) noexcept(noexcept(f(storage.V0, args...)))
680  -> decltype(f(storage.V0, args...))
681  {
682  VTKM_ASSERT((index >= 0) && (index < static_cast<vtkm::IdComponent>(NumCases)));
683  switch (index)
684  {
685  case 0:
686  // If you get a compile error here, it probably means that you have called
687  // Variant::CastAndCall with a functor that does not accept one of the types in the
688  // Variant. The functor you provide must be callable with all types in the Variant, not
689  // just the one that it currently holds.
690  return f(storage.V0, std::forward<Args>(args)...);
691  case 1:
692  // If you get a compile error here, it probably means that you have called
693  // Variant::CastAndCall with a functor that does not accept one of the types in the
694  // Variant. The functor you provide must be callable with all types in the Variant, not
695  // just the one that it currently holds.
696  return f(storage.V1, std::forward<Args>(args)...);
697  case 2:
698  // If you get a compile error here, it probably means that you have called
699  // Variant::CastAndCall with a functor that does not accept one of the types in the
700  // Variant. The functor you provide must be callable with all types in the Variant, not
701  // just the one that it currently holds.
702  return f(storage.V2, std::forward<Args>(args)...);
703  case 3:
704  // If you get a compile error here, it probably means that you have called
705  // Variant::CastAndCall with a functor that does not accept one of the types in the
706  // Variant. The functor you provide must be callable with all types in the Variant, not
707  // just the one that it currently holds.
708  return f(storage.V3, std::forward<Args>(args)...);
709  case 4:
710  // If you get a compile error here, it probably means that you have called
711  // Variant::CastAndCall with a functor that does not accept one of the types in the
712  // Variant. The functor you provide must be callable with all types in the Variant, not
713  // just the one that it currently holds.
714  return f(storage.V4, std::forward<Args>(args)...);
715  case 5:
716  // If you get a compile error here, it probably means that you have called
717  // Variant::CastAndCall with a functor that does not accept one of the types in the
718  // Variant. The functor you provide must be callable with all types in the Variant, not
719  // just the one that it currently holds.
720  return f(storage.V5, std::forward<Args>(args)...);
721  case 6:
722  // If you get a compile error here, it probably means that you have called
723  // Variant::CastAndCall with a functor that does not accept one of the types in the
724  // Variant. The functor you provide must be callable with all types in the Variant, not
725  // just the one that it currently holds.
726  return f(storage.V6, std::forward<Args>(args)...);
727  case 7:
728  // If you get a compile error here, it probably means that you have called
729  // Variant::CastAndCall with a functor that does not accept one of the types in the
730  // Variant. The functor you provide must be callable with all types in the Variant, not
731  // just the one that it currently holds.
732  return f(storage.V7, std::forward<Args>(args)...);
733  default:
734  return VariantCases<NumCases - 8>::template CastAndCall<>(
735  index - 8, std::forward<Functor>(f), storage.Remaining, std::forward<Args>(args)...);
736  }
737  }
738 };
739 
740 template<>
741 struct VariantCases<1>
742 {
743  template <typename Functor, typename UnionType, typename... Args>
744  VTK_M_DEVICE static inline auto CastAndCall(
745  vtkm::IdComponent index,
746  Functor&& f,
747  UnionType& storage,
748  Args&&... args) noexcept(noexcept(f(storage.V0, args...)))
749  -> decltype(f(storage.V0, args...))
750  {
751  // Assume index is 0. Saves us some conditionals.
752  VTKM_ASSERT(index == 0);
753  (void)index;
754  return f(storage.V0, std::forward<Args>(args)...);
755  }
756 };
757 
758 template<>
759 struct VariantCases<2>
760 {
761  template <typename Functor, typename UnionType, typename... Args>
762  VTK_M_DEVICE static
763 #ifdef VTKM_HIP
764  // this is a temporary solution to improve Kokkos/HIP compile times for
765  // ConnectivityTracer in Rendering.
766  //
767  // This function currently gets inlined many times, which dramatically increases
768  // both compile time and the size of the resulting code-object
769  __attribute__((noinline))
770 #else
771  inline
772 #endif
773  auto CastAndCall(
774  vtkm::IdComponent index,
775  Functor&& f,
776  UnionType& storage,
777  Args&&... args) noexcept(noexcept(f(storage.V0, args...)))
778  -> decltype(f(storage.V0, args...))
779  {
780  // Assume index is 0. Saves us some conditionals.
781  VTKM_ASSERT((index >= 0) && (index < 2));
782  switch (index)
783  {
784  default:
785  case 0:
786  // If you get a compile error here, it probably means that you have called
787  // Variant::CastAndCall with a functor that does not accept one of the types in the
788  // Variant. The functor you provide must be callable with all types in the Variant, not
789  // just the one that it currently holds.
790  return f(storage.V0, std::forward<Args>(args)...);
791  case 1:
792  // If you get a compile error here, it probably means that you have called
793  // Variant::CastAndCall with a functor that does not accept one of the types in the
794  // Variant. The functor you provide must be callable with all types in the Variant, not
795  // just the one that it currently holds.
796  return f(storage.V1, std::forward<Args>(args)...);
797  }
798  }
799 };
800 template<>
801 struct VariantCases<3>
802 {
803  template <typename Functor, typename UnionType, typename... Args>
804  VTK_M_DEVICE static
805 #ifdef VTKM_HIP
806  // this is a temporary solution to improve Kokkos/HIP compile times for
807  // ConnectivityTracer in Rendering.
808  //
809  // This function currently gets inlined many times, which dramatically increases
810  // both compile time and the size of the resulting code-object
811  __attribute__((noinline))
812 #else
813  inline
814 #endif
815  auto CastAndCall(
816  vtkm::IdComponent index,
817  Functor&& f,
818  UnionType& storage,
819  Args&&... args) noexcept(noexcept(f(storage.V0, args...)))
820  -> decltype(f(storage.V0, args...))
821  {
822  // Assume index is 0. Saves us some conditionals.
823  VTKM_ASSERT((index >= 0) && (index < 3));
824  switch (index)
825  {
826  default:
827  case 0:
828  // If you get a compile error here, it probably means that you have called
829  // Variant::CastAndCall with a functor that does not accept one of the types in the
830  // Variant. The functor you provide must be callable with all types in the Variant, not
831  // just the one that it currently holds.
832  return f(storage.V0, std::forward<Args>(args)...);
833  case 1:
834  // If you get a compile error here, it probably means that you have called
835  // Variant::CastAndCall with a functor that does not accept one of the types in the
836  // Variant. The functor you provide must be callable with all types in the Variant, not
837  // just the one that it currently holds.
838  return f(storage.V1, std::forward<Args>(args)...);
839  case 2:
840  // If you get a compile error here, it probably means that you have called
841  // Variant::CastAndCall with a functor that does not accept one of the types in the
842  // Variant. The functor you provide must be callable with all types in the Variant, not
843  // just the one that it currently holds.
844  return f(storage.V2, std::forward<Args>(args)...);
845  }
846  }
847 };
848 template<>
849 struct VariantCases<4>
850 {
851  template <typename Functor, typename UnionType, typename... Args>
852  VTK_M_DEVICE static
853 #ifdef VTKM_HIP
854  // this is a temporary solution to improve Kokkos/HIP compile times for
855  // ConnectivityTracer in Rendering.
856  //
857  // This function currently gets inlined many times, which dramatically increases
858  // both compile time and the size of the resulting code-object
859  __attribute__((noinline))
860 #else
861  inline
862 #endif
863  auto CastAndCall(
864  vtkm::IdComponent index,
865  Functor&& f,
866  UnionType& storage,
867  Args&&... args) noexcept(noexcept(f(storage.V0, args...)))
868  -> decltype(f(storage.V0, args...))
869  {
870  // Assume index is 0. Saves us some conditionals.
871  VTKM_ASSERT((index >= 0) && (index < 4));
872  switch (index)
873  {
874  default:
875  case 0:
876  // If you get a compile error here, it probably means that you have called
877  // Variant::CastAndCall with a functor that does not accept one of the types in the
878  // Variant. The functor you provide must be callable with all types in the Variant, not
879  // just the one that it currently holds.
880  return f(storage.V0, std::forward<Args>(args)...);
881  case 1:
882  // If you get a compile error here, it probably means that you have called
883  // Variant::CastAndCall with a functor that does not accept one of the types in the
884  // Variant. The functor you provide must be callable with all types in the Variant, not
885  // just the one that it currently holds.
886  return f(storage.V1, std::forward<Args>(args)...);
887  case 2:
888  // If you get a compile error here, it probably means that you have called
889  // Variant::CastAndCall with a functor that does not accept one of the types in the
890  // Variant. The functor you provide must be callable with all types in the Variant, not
891  // just the one that it currently holds.
892  return f(storage.V2, std::forward<Args>(args)...);
893  case 3:
894  // If you get a compile error here, it probably means that you have called
895  // Variant::CastAndCall with a functor that does not accept one of the types in the
896  // Variant. The functor you provide must be callable with all types in the Variant, not
897  // just the one that it currently holds.
898  return f(storage.V3, std::forward<Args>(args)...);
899  }
900  }
901 };
902 template<>
903 struct VariantCases<5>
904 {
905  template <typename Functor, typename UnionType, typename... Args>
906  VTK_M_DEVICE static
907 #ifdef VTKM_HIP
908  // this is a temporary solution to improve Kokkos/HIP compile times for
909  // ConnectivityTracer in Rendering.
910  //
911  // This function currently gets inlined many times, which dramatically increases
912  // both compile time and the size of the resulting code-object
913  __attribute__((noinline))
914 #else
915  inline
916 #endif
917  auto CastAndCall(
918  vtkm::IdComponent index,
919  Functor&& f,
920  UnionType& storage,
921  Args&&... args) noexcept(noexcept(f(storage.V0, args...)))
922  -> decltype(f(storage.V0, args...))
923  {
924  // Assume index is 0. Saves us some conditionals.
925  VTKM_ASSERT((index >= 0) && (index < 5));
926  switch (index)
927  {
928  default:
929  case 0:
930  // If you get a compile error here, it probably means that you have called
931  // Variant::CastAndCall with a functor that does not accept one of the types in the
932  // Variant. The functor you provide must be callable with all types in the Variant, not
933  // just the one that it currently holds.
934  return f(storage.V0, std::forward<Args>(args)...);
935  case 1:
936  // If you get a compile error here, it probably means that you have called
937  // Variant::CastAndCall with a functor that does not accept one of the types in the
938  // Variant. The functor you provide must be callable with all types in the Variant, not
939  // just the one that it currently holds.
940  return f(storage.V1, std::forward<Args>(args)...);
941  case 2:
942  // If you get a compile error here, it probably means that you have called
943  // Variant::CastAndCall with a functor that does not accept one of the types in the
944  // Variant. The functor you provide must be callable with all types in the Variant, not
945  // just the one that it currently holds.
946  return f(storage.V2, std::forward<Args>(args)...);
947  case 3:
948  // If you get a compile error here, it probably means that you have called
949  // Variant::CastAndCall with a functor that does not accept one of the types in the
950  // Variant. The functor you provide must be callable with all types in the Variant, not
951  // just the one that it currently holds.
952  return f(storage.V3, std::forward<Args>(args)...);
953  case 4:
954  // If you get a compile error here, it probably means that you have called
955  // Variant::CastAndCall with a functor that does not accept one of the types in the
956  // Variant. The functor you provide must be callable with all types in the Variant, not
957  // just the one that it currently holds.
958  return f(storage.V4, std::forward<Args>(args)...);
959  }
960  }
961 };
962 template<>
963 struct VariantCases<6>
964 {
965  template <typename Functor, typename UnionType, typename... Args>
966  VTK_M_DEVICE static
967 #ifdef VTKM_HIP
968  // this is a temporary solution to improve Kokkos/HIP compile times for
969  // ConnectivityTracer in Rendering.
970  //
971  // This function currently gets inlined many times, which dramatically increases
972  // both compile time and the size of the resulting code-object
973  __attribute__((noinline))
974 #else
975  inline
976 #endif
977  auto CastAndCall(
978  vtkm::IdComponent index,
979  Functor&& f,
980  UnionType& storage,
981  Args&&... args) noexcept(noexcept(f(storage.V0, args...)))
982  -> decltype(f(storage.V0, args...))
983  {
984  // Assume index is 0. Saves us some conditionals.
985  VTKM_ASSERT((index >= 0) && (index < 6));
986  switch (index)
987  {
988  default:
989  case 0:
990  // If you get a compile error here, it probably means that you have called
991  // Variant::CastAndCall with a functor that does not accept one of the types in the
992  // Variant. The functor you provide must be callable with all types in the Variant, not
993  // just the one that it currently holds.
994  return f(storage.V0, std::forward<Args>(args)...);
995  case 1:
996  // If you get a compile error here, it probably means that you have called
997  // Variant::CastAndCall with a functor that does not accept one of the types in the
998  // Variant. The functor you provide must be callable with all types in the Variant, not
999  // just the one that it currently holds.
1000  return f(storage.V1, std::forward<Args>(args)...);
1001  case 2:
1002  // If you get a compile error here, it probably means that you have called
1003  // Variant::CastAndCall with a functor that does not accept one of the types in the
1004  // Variant. The functor you provide must be callable with all types in the Variant, not
1005  // just the one that it currently holds.
1006  return f(storage.V2, std::forward<Args>(args)...);
1007  case 3:
1008  // If you get a compile error here, it probably means that you have called
1009  // Variant::CastAndCall with a functor that does not accept one of the types in the
1010  // Variant. The functor you provide must be callable with all types in the Variant, not
1011  // just the one that it currently holds.
1012  return f(storage.V3, std::forward<Args>(args)...);
1013  case 4:
1014  // If you get a compile error here, it probably means that you have called
1015  // Variant::CastAndCall with a functor that does not accept one of the types in the
1016  // Variant. The functor you provide must be callable with all types in the Variant, not
1017  // just the one that it currently holds.
1018  return f(storage.V4, std::forward<Args>(args)...);
1019  case 5:
1020  // If you get a compile error here, it probably means that you have called
1021  // Variant::CastAndCall with a functor that does not accept one of the types in the
1022  // Variant. The functor you provide must be callable with all types in the Variant, not
1023  // just the one that it currently holds.
1024  return f(storage.V5, std::forward<Args>(args)...);
1025  }
1026  }
1027 };
1028 template<>
1029 struct VariantCases<7>
1030 {
1031  template <typename Functor, typename UnionType, typename... Args>
1032  VTK_M_DEVICE static
1033 #ifdef VTKM_HIP
1034  // this is a temporary solution to improve Kokkos/HIP compile times for
1035  // ConnectivityTracer in Rendering.
1036  //
1037  // This function currently gets inlined many times, which dramatically increases
1038  // both compile time and the size of the resulting code-object
1039  __attribute__((noinline))
1040 #else
1041  inline
1042 #endif
1043  auto CastAndCall(
1044  vtkm::IdComponent index,
1045  Functor&& f,
1046  UnionType& storage,
1047  Args&&... args) noexcept(noexcept(f(storage.V0, args...)))
1048  -> decltype(f(storage.V0, args...))
1049  {
1050  // Assume index is 0. Saves us some conditionals.
1051  VTKM_ASSERT((index >= 0) && (index < 7));
1052  switch (index)
1053  {
1054  default:
1055  case 0:
1056  // If you get a compile error here, it probably means that you have called
1057  // Variant::CastAndCall with a functor that does not accept one of the types in the
1058  // Variant. The functor you provide must be callable with all types in the Variant, not
1059  // just the one that it currently holds.
1060  return f(storage.V0, std::forward<Args>(args)...);
1061  case 1:
1062  // If you get a compile error here, it probably means that you have called
1063  // Variant::CastAndCall with a functor that does not accept one of the types in the
1064  // Variant. The functor you provide must be callable with all types in the Variant, not
1065  // just the one that it currently holds.
1066  return f(storage.V1, std::forward<Args>(args)...);
1067  case 2:
1068  // If you get a compile error here, it probably means that you have called
1069  // Variant::CastAndCall with a functor that does not accept one of the types in the
1070  // Variant. The functor you provide must be callable with all types in the Variant, not
1071  // just the one that it currently holds.
1072  return f(storage.V2, std::forward<Args>(args)...);
1073  case 3:
1074  // If you get a compile error here, it probably means that you have called
1075  // Variant::CastAndCall with a functor that does not accept one of the types in the
1076  // Variant. The functor you provide must be callable with all types in the Variant, not
1077  // just the one that it currently holds.
1078  return f(storage.V3, std::forward<Args>(args)...);
1079  case 4:
1080  // If you get a compile error here, it probably means that you have called
1081  // Variant::CastAndCall with a functor that does not accept one of the types in the
1082  // Variant. The functor you provide must be callable with all types in the Variant, not
1083  // just the one that it currently holds.
1084  return f(storage.V4, std::forward<Args>(args)...);
1085  case 5:
1086  // If you get a compile error here, it probably means that you have called
1087  // Variant::CastAndCall with a functor that does not accept one of the types in the
1088  // Variant. The functor you provide must be callable with all types in the Variant, not
1089  // just the one that it currently holds.
1090  return f(storage.V5, std::forward<Args>(args)...);
1091  case 6:
1092  // If you get a compile error here, it probably means that you have called
1093  // Variant::CastAndCall with a functor that does not accept one of the types in the
1094  // Variant. The functor you provide must be callable with all types in the Variant, not
1095  // just the one that it currently holds.
1096  return f(storage.V6, std::forward<Args>(args)...);
1097  }
1098  }
1099 };
1100 template<>
1101 struct VariantCases<8>
1102 {
1103  template <typename Functor, typename UnionType, typename... Args>
1104  VTK_M_DEVICE static
1105 #ifdef VTKM_HIP
1106  // this is a temporary solution to improve Kokkos/HIP compile times for
1107  // ConnectivityTracer in Rendering.
1108  //
1109  // This function currently gets inlined many times, which dramatically increases
1110  // both compile time and the size of the resulting code-object
1111  __attribute__((noinline))
1112 #else
1113  inline
1114 #endif
1115  auto CastAndCall(
1116  vtkm::IdComponent index,
1117  Functor&& f,
1118  UnionType& storage,
1119  Args&&... args) noexcept(noexcept(f(storage.V0, args...)))
1120  -> decltype(f(storage.V0, args...))
1121  {
1122  // Assume index is 0. Saves us some conditionals.
1123  VTKM_ASSERT((index >= 0) && (index < 8));
1124  switch (index)
1125  {
1126  default:
1127  case 0:
1128  // If you get a compile error here, it probably means that you have called
1129  // Variant::CastAndCall with a functor that does not accept one of the types in the
1130  // Variant. The functor you provide must be callable with all types in the Variant, not
1131  // just the one that it currently holds.
1132  return f(storage.V0, std::forward<Args>(args)...);
1133  case 1:
1134  // If you get a compile error here, it probably means that you have called
1135  // Variant::CastAndCall with a functor that does not accept one of the types in the
1136  // Variant. The functor you provide must be callable with all types in the Variant, not
1137  // just the one that it currently holds.
1138  return f(storage.V1, std::forward<Args>(args)...);
1139  case 2:
1140  // If you get a compile error here, it probably means that you have called
1141  // Variant::CastAndCall with a functor that does not accept one of the types in the
1142  // Variant. The functor you provide must be callable with all types in the Variant, not
1143  // just the one that it currently holds.
1144  return f(storage.V2, std::forward<Args>(args)...);
1145  case 3:
1146  // If you get a compile error here, it probably means that you have called
1147  // Variant::CastAndCall with a functor that does not accept one of the types in the
1148  // Variant. The functor you provide must be callable with all types in the Variant, not
1149  // just the one that it currently holds.
1150  return f(storage.V3, std::forward<Args>(args)...);
1151  case 4:
1152  // If you get a compile error here, it probably means that you have called
1153  // Variant::CastAndCall with a functor that does not accept one of the types in the
1154  // Variant. The functor you provide must be callable with all types in the Variant, not
1155  // just the one that it currently holds.
1156  return f(storage.V4, std::forward<Args>(args)...);
1157  case 5:
1158  // If you get a compile error here, it probably means that you have called
1159  // Variant::CastAndCall with a functor that does not accept one of the types in the
1160  // Variant. The functor you provide must be callable with all types in the Variant, not
1161  // just the one that it currently holds.
1162  return f(storage.V5, std::forward<Args>(args)...);
1163  case 6:
1164  // If you get a compile error here, it probably means that you have called
1165  // Variant::CastAndCall with a functor that does not accept one of the types in the
1166  // Variant. The functor you provide must be callable with all types in the Variant, not
1167  // just the one that it currently holds.
1168  return f(storage.V6, std::forward<Args>(args)...);
1169  case 7:
1170  // If you get a compile error here, it probably means that you have called
1171  // Variant::CastAndCall with a functor that does not accept one of the types in the
1172  // Variant. The functor you provide must be callable with all types in the Variant, not
1173  // just the one that it currently holds.
1174  return f(storage.V7, std::forward<Args>(args)...);
1175  }
1176  }
1177 };
1178 
1179 
1180 template <std::size_t UnionSize, typename Functor, typename UnionType, typename... Args>
1181 VTK_M_DEVICE inline auto VariantCastAndCallImpl(
1182  vtkm::IdComponent index,
1183  Functor&& f,
1184  UnionType& storage,
1185  Args&&... args) noexcept(noexcept(f(storage.V0, args...)))
1186  -> decltype(f(storage.V0, args...))
1187 {
1189  index, std::forward<Functor>(f), storage, std::forward<Args>(args)...);
1190 }
1191 
1192 }
1193 }
1194 } // vtkm::VTK_M_NAMESPACE::detail
vtkm
Groups connected points that have the same field value.
Definition: Atomic.h:19
vtkm::Get
auto Get(const vtkm::Tuple< Ts... > &tuple)
Retrieve the object from a vtkm::Tuple at the given index.
Definition: Tuple.h:81
Types.h
VTKM_ASSERT
#define VTKM_ASSERT(condition)
Definition: Assert.h:43
vtkm::IdComponent
vtkm::Int32 IdComponent
Base type to use to index small lists.
Definition: Types.h:194
vtkm::Int16
int16_t Int16
Base type to use for 16-bit signed integer numbers.
Definition: Types.h:173
vtkm::cont::CastAndCall
void CastAndCall(const DynamicObject &dynamicObject, Functor &&f, Args &&... args)
A Generic interface to CastAndCall.
Definition: CastAndCall.h:47
Assume.h
VTKM_STATIC_ASSERT
#define VTKM_STATIC_ASSERT(condition)
Definition: StaticAssert.h:16
vtkm::Int8
int8_t Int8
Base type to use for 8-bit signed integer numbers.
Definition: Types.h:165
vtkm::Int64
signed long long Int64
Base type to use for 64-bit signed integer numbers.
Definition: Types.h:204
VTK_M_NAMESPACE
#define VTK_M_NAMESPACE
Definition: VariantImplDetail.h:17
vtkm::List
A template used to hold a list of types.
Definition: List.h:39
vtkm::Int32
int32_t Int32
Base type to use for 32-bit signed integer numbers.
Definition: Types.h:181
vtkm::ListAll
vtkm::ListReduce< vtkm::ListTransform< List, Predicate >, vtkm::internal::meta::And, std::true_type > ListAll
Determines whether all the types in the list are "true.".
Definition: List.h:843
List.h
VTK_M_DEVICE
#define VTK_M_DEVICE
Definition: VariantImplDetail.h:16