VTK-m  2.0
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 <type_traits>
28 
29 
30 
31 namespace vtkm
32 {
33 namespace VTK_M_NAMESPACE
34 {
35 namespace detail
36 {
37 
38 // --------------------------------------------------------------------------------
39 // Helper classes to determine if all Variant types are trivial.
40 template <typename... Ts>
41 using AllTriviallyCopyable = vtkm::ListAll<vtkm::List<Ts...>, vtkmstd::is_trivially_copyable>;
42 
43 // Single argument version of is_trivially_constructible
44 template <typename T>
45 using Constructible = vtkmstd::is_trivially_constructible<T>;
46 
47 template <typename... Ts>
48 using AllTriviallyConstructible = vtkm::ListAll<vtkm::List<Ts...>, Constructible>;
49 
50 template <typename... Ts>
51 using AllTriviallyDestructible =
52  vtkm::ListAll<vtkm::List<Ts...>, vtkmstd::is_trivially_destructible>;
53 
54 // clang-format off
55 
56 // --------------------------------------------------------------------------------
57 // Union type used inside of Variant
58 //
59 // You may be asking yourself, why not just use an std::aligned_union rather than a real union
60 // type? That was our first implementation, but the problem is that the std::aligned_union
61 // reference needs to be recast to the actual type. Typically you would do that with
62 // reinterpret_cast. However, doing that leads to undefined behavior. The C++ compiler assumes that
63 // 2 pointers of different types point to different memory (even if it is clear that they are set
64 // to the same address). That means optimizers can remove code because it "knows" that data in one
65 // type cannot affect data in another type. (See Shafik Yaghmour's excellent writeup at
66 // https://gist.github.com/shafik/848ae25ee209f698763cffee272a58f8 for more details.) To safely
67 // change the type of an std::aligned_union, you really have to do an std::memcpy. This is
68 // problematic for types that cannot be trivially copied. Another problem is that we found that
69 // device compilers do not optimize the memcpy as well as most CPU compilers. Likely, memcpy is
70 // used much less frequently on GPU devices.
71 //
72 // Part of the trickiness of the union implementation is trying to preserve when the type is
73 // trivially constructible and copyable. The trick is that if members of the union are not trivial,
74 // then the default constructors are deleted. To get around that, a non-default constructor is
75 // added, which we can use to construct the union for non-trivial types. Working with types with
76 // non-trivial destructors are particularly tricky. Again, if any member of the union has a
77 // non-trivial destructor, the destructor is deleted. Unlike a constructor, you cannot just say to
78 // use a different destructor. Thus, we have to define our own destructor for the union.
79 // Technically, the destructor here does not do anything, but the actual destruction should be
80 // handled by the Variant class that contains this VariantUnion. We actually need two separate
81 // implementations of our union, one that defines a destructor and one that use the default
82 // destructor. If you define your own destructor, you can lose the trivial constructor and trivial
83 // copy properties.
84 //
85 
86 // TD = trivially deconstructible
87 template <typename T0, typename... Ts>
88 union VariantUnionTD;
89 
90 // NTD = non-trivially deconstructible
91 template <typename T0, typename... Ts>
92 union VariantUnionNTD;
93 
94 template <typename T0>
95 union VariantUnionTD<T0>
96 {
97  T0 V0;
98  VTK_M_DEVICE VariantUnionTD(vtkm::internal::NullType) { }
99  VariantUnionTD() = default;
100 };
101 template <typename T0>
102 union VariantUnionNTD<T0>
103 {
104  T0 V0;
105  VTK_M_DEVICE VariantUnionNTD(vtkm::internal::NullType) { }
106  VariantUnionNTD() = default;
107  VTK_M_DEVICE ~VariantUnionNTD() { }
108 };
109 
110 template <typename T0, typename T1>
111 union VariantUnionTD<T0, T1>
112 {
113  T0 V0;
114  T1 V1;
115  VTK_M_DEVICE VariantUnionTD(vtkm::internal::NullType) { }
116  VariantUnionTD() = default;
117 };
118 template <typename T0, typename T1>
119 union VariantUnionNTD<T0, T1>
120 {
121  T0 V0;
122  T1 V1;
123  VTK_M_DEVICE VariantUnionNTD(vtkm::internal::NullType) { }
124  VariantUnionNTD() = default;
125  VTK_M_DEVICE ~VariantUnionNTD() { }
126 };
127 
128 template <typename T0, typename T1, typename T2>
129 union VariantUnionTD<T0, T1, T2>
130 {
131  T0 V0;
132  T1 V1;
133  T2 V2;
134  VTK_M_DEVICE VariantUnionTD(vtkm::internal::NullType) { }
135  VariantUnionTD() = default;
136 };
137 template <typename T0, typename T1, typename T2>
138 union VariantUnionNTD<T0, T1, T2>
139 {
140  T0 V0;
141  T1 V1;
142  T2 V2;
143  VTK_M_DEVICE VariantUnionNTD(vtkm::internal::NullType) { }
144  VariantUnionNTD() = default;
145  VTK_M_DEVICE ~VariantUnionNTD() { }
146 };
147 
148 template <typename T0, typename T1, typename T2, typename T3>
149 union VariantUnionTD<T0, T1, T2, T3>
150 {
151  T0 V0;
152  T1 V1;
153  T2 V2;
154  T3 V3;
155  VTK_M_DEVICE VariantUnionTD(vtkm::internal::NullType) { }
156  VariantUnionTD() = default;
157 };
158 template <typename T0, typename T1, typename T2, typename T3>
159 union VariantUnionNTD<T0, T1, T2, T3>
160 {
161  T0 V0;
162  T1 V1;
163  T2 V2;
164  T3 V3;
165  VTK_M_DEVICE VariantUnionNTD(vtkm::internal::NullType) { }
166  VariantUnionNTD() = default;
167  VTK_M_DEVICE ~VariantUnionNTD() { }
168 };
169 
170 template <typename T0, typename T1, typename T2, typename T3, typename T4>
171 union VariantUnionTD<T0, T1, T2, T3, T4>
172 {
173  T0 V0;
174  T1 V1;
175  T2 V2;
176  T3 V3;
177  T4 V4;
178  VTK_M_DEVICE VariantUnionTD(vtkm::internal::NullType) { }
179  VariantUnionTD() = default;
180 };
181 template <typename T0, typename T1, typename T2, typename T3, typename T4>
182 union VariantUnionNTD<T0, T1, T2, T3, T4>
183 {
184  T0 V0;
185  T1 V1;
186  T2 V2;
187  T3 V3;
188  T4 V4;
189  VTK_M_DEVICE VariantUnionNTD(vtkm::internal::NullType) { }
190  VariantUnionNTD() = default;
191  VTK_M_DEVICE ~VariantUnionNTD() { }
192 };
193 
194 template <typename T0, typename T1, typename T2, typename T3, typename T4, typename T5>
195 union VariantUnionTD<T0, T1, T2, T3, T4, T5>
196 {
197  T0 V0;
198  T1 V1;
199  T2 V2;
200  T3 V3;
201  T4 V4;
202  T5 V5;
203  VTK_M_DEVICE VariantUnionTD(vtkm::internal::NullType) { }
204  VariantUnionTD() = default;
205 };
206 template <typename T0, typename T1, typename T2, typename T3, typename T4, typename T5>
207 union VariantUnionNTD<T0, T1, T2, T3, T4, T5>
208 {
209  T0 V0;
210  T1 V1;
211  T2 V2;
212  T3 V3;
213  T4 V4;
214  T5 V5;
215  VTK_M_DEVICE VariantUnionNTD(vtkm::internal::NullType) { }
216  VariantUnionNTD() = default;
217  VTK_M_DEVICE ~VariantUnionNTD() { }
218 };
219 
220 template <typename T0, typename T1, typename T2, typename T3, typename T4, typename T5, typename T6>
221 union VariantUnionTD<T0, T1, T2, T3, T4, T5, T6>
222 {
223  T0 V0;
224  T1 V1;
225  T2 V2;
226  T3 V3;
227  T4 V4;
228  T5 V5;
229  T6 V6;
230  VTK_M_DEVICE VariantUnionTD(vtkm::internal::NullType) { }
231  VariantUnionTD() = default;
232 };
233 template <typename T0, typename T1, typename T2, typename T3, typename T4, typename T5, typename T6>
234 union VariantUnionNTD<T0, T1, T2, T3, T4, T5, T6>
235 {
236  T0 V0;
237  T1 V1;
238  T2 V2;
239  T3 V3;
240  T4 V4;
241  T5 V5;
242  T6 V6;
243  VTK_M_DEVICE VariantUnionNTD(vtkm::internal::NullType) { }
244  VariantUnionNTD() = default;
245  VTK_M_DEVICE ~VariantUnionNTD() { }
246 };
247 
248 template <typename T0, typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7>
249 union VariantUnionTD<T0, T1, T2, T3, T4, T5, T6, T7>
250 {
251  T0 V0;
252  T1 V1;
253  T2 V2;
254  T3 V3;
255  T4 V4;
256  T5 V5;
257  T6 V6;
258  T7 V7;
259  VTK_M_DEVICE VariantUnionTD(vtkm::internal::NullType) { }
260  VariantUnionTD() = default;
261 };
262 template <typename T0, typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7>
263 union VariantUnionNTD<T0, T1, T2, T3, T4, T5, T6, T7>
264 {
265  T0 V0;
266  T1 V1;
267  T2 V2;
268  T3 V3;
269  T4 V4;
270  T5 V5;
271  T6 V6;
272  T7 V7;
273  VTK_M_DEVICE VariantUnionNTD(vtkm::internal::NullType) { }
274  VariantUnionNTD() = default;
275  VTK_M_DEVICE ~VariantUnionNTD() { }
276 };
277 
278 
279 template <typename T0, typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7, typename T8, typename... Ts>
280 union VariantUnionTD<T0, T1, T2, T3, T4, T5, T6, T7, T8, Ts...>
281 {
282  T0 V0;
283  T1 V1;
284  T2 V2;
285  T3 V3;
286  T4 V4;
287  T5 V5;
288  T6 V6;
289  T7 V7;
290  VariantUnionTD<T8, Ts...> Remaining;
291 
292  VTK_M_DEVICE VariantUnionTD(vtkm::internal::NullType) { }
293  VariantUnionTD() = default;
294 };
295 
296 template <typename T0, typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7, typename T8, typename... Ts>
297 union VariantUnionNTD<T0, T1, T2, T3, T4, T5, T6, T7, T8, Ts...>
298 {
299  T0 V0;
300  T1 V1;
301  T2 V2;
302  T3 V3;
303  T4 V4;
304  T5 V5;
305  T6 V6;
306  T7 V7;
307  VariantUnionNTD<T8, Ts...> Remaining;
308 
309  VTK_M_DEVICE VariantUnionNTD(vtkm::internal::NullType) { }
310  VariantUnionNTD() = default;
311  VTK_M_DEVICE ~VariantUnionNTD() { }
312 };
313 
314 //clang-format on
315 
316 template <bool TrivialConstructor, typename... Ts>
317 struct VariantUnionFinder;
318 
319 template <typename... Ts>
320 struct VariantUnionFinder<true, Ts...>
321 {
322  using type = VariantUnionTD<Ts...>;
323 };
324 template <typename... Ts>
325 struct VariantUnionFinder<false, Ts...>
326 {
327  using type = VariantUnionNTD<Ts...>;
328 };
329 
330 template <typename... Ts>
331 using VariantUnion =
332  typename VariantUnionFinder<AllTriviallyDestructible<Ts...>::value, Ts...>::type;
333 
334 // --------------------------------------------------------------------------------
335 // Methods to get values out of the variant union
336 template <vtkm::IdComponent I, typename UnionType>
337 struct VariantUnionGetImpl;
338 
339 template <typename UnionType>
340 struct VariantUnionGetImpl<0, UnionType>
341 {
342  using ReturnType = decltype(std::declval<UnionType>().V0);
343  VTK_M_DEVICE static ReturnType& Get(UnionType& storage) noexcept
344  {
345  return storage.V0;
346  }
347  VTK_M_DEVICE static const ReturnType& Get(const UnionType& storage) noexcept
348  {
349  return storage.V0;
350  }
351 };
352 
353 template <typename UnionType>
354 struct VariantUnionGetImpl<1, UnionType>
355 {
356  using ReturnType = decltype(std::declval<UnionType>().V1);
357  VTK_M_DEVICE static ReturnType& Get(UnionType& storage) noexcept
358  {
359  return storage.V1;
360  }
361  VTK_M_DEVICE static const ReturnType& Get(const UnionType& storage) noexcept
362  {
363  return storage.V1;
364  }
365 };
366 
367 template <typename UnionType>
368 struct VariantUnionGetImpl<2, UnionType>
369 {
370  using ReturnType = decltype(std::declval<UnionType>().V2);
371  VTK_M_DEVICE static ReturnType& Get(UnionType& storage) noexcept
372  {
373  return storage.V2;
374  }
375  VTK_M_DEVICE static const ReturnType& Get(const UnionType& storage) noexcept
376  {
377  return storage.V2;
378  }
379 };
380 
381 template <typename UnionType>
382 struct VariantUnionGetImpl<3, UnionType>
383 {
384  using ReturnType = decltype(std::declval<UnionType>().V3);
385  VTK_M_DEVICE static ReturnType& Get(UnionType& storage) noexcept
386  {
387  return storage.V3;
388  }
389  VTK_M_DEVICE static const ReturnType& Get(const UnionType& storage) noexcept
390  {
391  return storage.V3;
392  }
393 };
394 
395 template <typename UnionType>
396 struct VariantUnionGetImpl<4, UnionType>
397 {
398  using ReturnType = decltype(std::declval<UnionType>().V4);
399  VTK_M_DEVICE static ReturnType& Get(UnionType& storage) noexcept
400  {
401  return storage.V4;
402  }
403  VTK_M_DEVICE static const ReturnType& Get(const UnionType& storage) noexcept
404  {
405  return storage.V4;
406  }
407 };
408 
409 template <typename UnionType>
410 struct VariantUnionGetImpl<5, UnionType>
411 {
412  using ReturnType = decltype(std::declval<UnionType>().V5);
413  VTK_M_DEVICE static ReturnType& Get(UnionType& storage) noexcept
414  {
415  return storage.V5;
416  }
417  VTK_M_DEVICE static const ReturnType& Get(const UnionType& storage) noexcept
418  {
419  return storage.V5;
420  }
421 };
422 
423 template <typename UnionType>
424 struct VariantUnionGetImpl<6, UnionType>
425 {
426  using ReturnType = decltype(std::declval<UnionType>().V6);
427  VTK_M_DEVICE static ReturnType& Get(UnionType& storage) noexcept
428  {
429  return storage.V6;
430  }
431  VTK_M_DEVICE static const ReturnType& Get(const UnionType& storage) noexcept
432  {
433  return storage.V6;
434  }
435 };
436 
437 template <typename UnionType>
438 struct VariantUnionGetImpl<7, UnionType>
439 {
440  using ReturnType = decltype(std::declval<UnionType>().V7);
441  VTK_M_DEVICE static ReturnType& Get(UnionType& storage) noexcept
442  {
443  return storage.V7;
444  }
445  VTK_M_DEVICE static const ReturnType& Get(const UnionType& storage) noexcept
446  {
447  return storage.V7;
448  }
449 };
450 
451 
452 template <vtkm::IdComponent I, typename UnionType>
453 struct VariantUnionGetImpl
454 {
455  VTKM_STATIC_ASSERT(I >= 8);
456  using RecursiveGet = VariantUnionGetImpl<I - 8, decltype(std::declval<UnionType&>().Remaining)>;
457  using ReturnType = typename RecursiveGet::ReturnType;
458  VTK_M_DEVICE static ReturnType& Get(UnionType& storage) noexcept
459  {
460  return RecursiveGet::Get(storage.Remaining);
461  }
462  VTK_M_DEVICE static const ReturnType& Get(const UnionType& storage) noexcept
463  {
464  return RecursiveGet::Get(storage.Remaining);
465  }
466 };
467 
468 template <vtkm::IdComponent I, typename UnionType>
469 VTK_M_DEVICE auto VariantUnionGet(UnionType& storage) noexcept
470  -> decltype(VariantUnionGetImpl<I, typename std::decay<UnionType>::type>::Get(storage))&
471 {
472  return VariantUnionGetImpl<I, typename std::decay<UnionType>::type>::Get(storage);
473 }
474 
475 // --------------------------------------------------------------------------------
476 // Internal implementation of CastAndCall for Variant
477 template <std::size_t NumCases>
478 struct VariantCases
479 {
480  template <typename Functor, typename UnionType, typename... Args>
481  VTK_M_DEVICE static
482 #ifdef VTKM_HIP
483  // this is a temporary solution to improve Kokkos/HIP compile times for
484  // ConnectivityTracer in Rendering.
485  //
486  // This function currently gets inlined many times, which dramatically increases
487  // both compile time and the size of the resulting code-object
488  __attribute__((noinline))
489 #else
490  inline
491 #endif
492  auto CastAndCall(
493  vtkm::IdComponent index,
494  Functor&& f,
495  UnionType& storage,
496  Args&&... args) noexcept(noexcept(f(storage.V0, args...)))
497  -> decltype(f(storage.V0, args...))
498  {
499  VTKM_ASSERT((index >= 0) && (index < static_cast<vtkm::IdComponent>(NumCases)));
500  switch (index)
501  {
502  case 0:
503  // If you get a compile error here, it probably means that you have called
504  // Variant::CastAndCall with a functor that does not accept one of the types in the
505  // Variant. The functor you provide must be callable with all types in the Variant, not
506  // just the one that it currently holds.
507  return f(storage.V0, std::forward<Args>(args)...);
508  case 1:
509  // If you get a compile error here, it probably means that you have called
510  // Variant::CastAndCall with a functor that does not accept one of the types in the
511  // Variant. The functor you provide must be callable with all types in the Variant, not
512  // just the one that it currently holds.
513  return f(storage.V1, std::forward<Args>(args)...);
514  case 2:
515  // If you get a compile error here, it probably means that you have called
516  // Variant::CastAndCall with a functor that does not accept one of the types in the
517  // Variant. The functor you provide must be callable with all types in the Variant, not
518  // just the one that it currently holds.
519  return f(storage.V2, std::forward<Args>(args)...);
520  case 3:
521  // If you get a compile error here, it probably means that you have called
522  // Variant::CastAndCall with a functor that does not accept one of the types in the
523  // Variant. The functor you provide must be callable with all types in the Variant, not
524  // just the one that it currently holds.
525  return f(storage.V3, std::forward<Args>(args)...);
526  case 4:
527  // If you get a compile error here, it probably means that you have called
528  // Variant::CastAndCall with a functor that does not accept one of the types in the
529  // Variant. The functor you provide must be callable with all types in the Variant, not
530  // just the one that it currently holds.
531  return f(storage.V4, std::forward<Args>(args)...);
532  case 5:
533  // If you get a compile error here, it probably means that you have called
534  // Variant::CastAndCall with a functor that does not accept one of the types in the
535  // Variant. The functor you provide must be callable with all types in the Variant, not
536  // just the one that it currently holds.
537  return f(storage.V5, std::forward<Args>(args)...);
538  case 6:
539  // If you get a compile error here, it probably means that you have called
540  // Variant::CastAndCall with a functor that does not accept one of the types in the
541  // Variant. The functor you provide must be callable with all types in the Variant, not
542  // just the one that it currently holds.
543  return f(storage.V6, std::forward<Args>(args)...);
544  case 7:
545  // If you get a compile error here, it probably means that you have called
546  // Variant::CastAndCall with a functor that does not accept one of the types in the
547  // Variant. The functor you provide must be callable with all types in the Variant, not
548  // just the one that it currently holds.
549  return f(storage.V7, std::forward<Args>(args)...);
550  default:
551  return VariantCases<NumCases - 8>::template CastAndCall(
552  index - 8, std::forward<Functor>(f), storage.Remaining, std::forward<Args>(args)...);
553  }
554  }
555 };
556 
557 template<>
558 struct VariantCases<1>
559 {
560  template <typename Functor, typename UnionType, typename... Args>
561  VTK_M_DEVICE static inline auto CastAndCall(
562  vtkm::IdComponent index,
563  Functor&& f,
564  UnionType& storage,
565  Args&&... args) noexcept(noexcept(f(storage.V0, args...)))
566  -> decltype(f(storage.V0, args...))
567  {
568  // Assume index is 0. Saves us some conditionals.
569  VTKM_ASSERT(index == 0);
570  (void)index;
571  return f(storage.V0, std::forward<Args>(args)...);
572  }
573 };
574 
575 template<>
576 struct VariantCases<2>
577 {
578  template <typename Functor, typename UnionType, typename... Args>
579  VTK_M_DEVICE static
580 #ifdef VTKM_HIP
581  // this is a temporary solution to improve Kokkos/HIP compile times for
582  // ConnectivityTracer in Rendering.
583  //
584  // This function currently gets inlined many times, which dramatically increases
585  // both compile time and the size of the resulting code-object
586  __attribute__((noinline))
587 #else
588  inline
589 #endif
590  auto CastAndCall(
591  vtkm::IdComponent index,
592  Functor&& f,
593  UnionType& storage,
594  Args&&... args) noexcept(noexcept(f(storage.V0, args...)))
595  -> decltype(f(storage.V0, args...))
596  {
597  // Assume index is 0. Saves us some conditionals.
598  VTKM_ASSERT((index >= 0) && (index < 2));
599  switch (index)
600  {
601  default:
602  case 0:
603  // If you get a compile error here, it probably means that you have called
604  // Variant::CastAndCall with a functor that does not accept one of the types in the
605  // Variant. The functor you provide must be callable with all types in the Variant, not
606  // just the one that it currently holds.
607  return f(storage.V0, std::forward<Args>(args)...);
608  case 1:
609  // If you get a compile error here, it probably means that you have called
610  // Variant::CastAndCall with a functor that does not accept one of the types in the
611  // Variant. The functor you provide must be callable with all types in the Variant, not
612  // just the one that it currently holds.
613  return f(storage.V1, std::forward<Args>(args)...);
614  }
615  }
616 };
617 template<>
618 struct VariantCases<3>
619 {
620  template <typename Functor, typename UnionType, typename... Args>
621  VTK_M_DEVICE static
622 #ifdef VTKM_HIP
623  // this is a temporary solution to improve Kokkos/HIP compile times for
624  // ConnectivityTracer in Rendering.
625  //
626  // This function currently gets inlined many times, which dramatically increases
627  // both compile time and the size of the resulting code-object
628  __attribute__((noinline))
629 #else
630  inline
631 #endif
632  auto CastAndCall(
633  vtkm::IdComponent index,
634  Functor&& f,
635  UnionType& storage,
636  Args&&... args) noexcept(noexcept(f(storage.V0, args...)))
637  -> decltype(f(storage.V0, args...))
638  {
639  // Assume index is 0. Saves us some conditionals.
640  VTKM_ASSERT((index >= 0) && (index < 3));
641  switch (index)
642  {
643  default:
644  case 0:
645  // If you get a compile error here, it probably means that you have called
646  // Variant::CastAndCall with a functor that does not accept one of the types in the
647  // Variant. The functor you provide must be callable with all types in the Variant, not
648  // just the one that it currently holds.
649  return f(storage.V0, std::forward<Args>(args)...);
650  case 1:
651  // If you get a compile error here, it probably means that you have called
652  // Variant::CastAndCall with a functor that does not accept one of the types in the
653  // Variant. The functor you provide must be callable with all types in the Variant, not
654  // just the one that it currently holds.
655  return f(storage.V1, std::forward<Args>(args)...);
656  case 2:
657  // If you get a compile error here, it probably means that you have called
658  // Variant::CastAndCall with a functor that does not accept one of the types in the
659  // Variant. The functor you provide must be callable with all types in the Variant, not
660  // just the one that it currently holds.
661  return f(storage.V2, std::forward<Args>(args)...);
662  }
663  }
664 };
665 template<>
666 struct VariantCases<4>
667 {
668  template <typename Functor, typename UnionType, typename... Args>
669  VTK_M_DEVICE static
670 #ifdef VTKM_HIP
671  // this is a temporary solution to improve Kokkos/HIP compile times for
672  // ConnectivityTracer in Rendering.
673  //
674  // This function currently gets inlined many times, which dramatically increases
675  // both compile time and the size of the resulting code-object
676  __attribute__((noinline))
677 #else
678  inline
679 #endif
680  auto CastAndCall(
681  vtkm::IdComponent index,
682  Functor&& f,
683  UnionType& storage,
684  Args&&... args) noexcept(noexcept(f(storage.V0, args...)))
685  -> decltype(f(storage.V0, args...))
686  {
687  // Assume index is 0. Saves us some conditionals.
688  VTKM_ASSERT((index >= 0) && (index < 4));
689  switch (index)
690  {
691  default:
692  case 0:
693  // If you get a compile error here, it probably means that you have called
694  // Variant::CastAndCall with a functor that does not accept one of the types in the
695  // Variant. The functor you provide must be callable with all types in the Variant, not
696  // just the one that it currently holds.
697  return f(storage.V0, std::forward<Args>(args)...);
698  case 1:
699  // If you get a compile error here, it probably means that you have called
700  // Variant::CastAndCall with a functor that does not accept one of the types in the
701  // Variant. The functor you provide must be callable with all types in the Variant, not
702  // just the one that it currently holds.
703  return f(storage.V1, std::forward<Args>(args)...);
704  case 2:
705  // If you get a compile error here, it probably means that you have called
706  // Variant::CastAndCall with a functor that does not accept one of the types in the
707  // Variant. The functor you provide must be callable with all types in the Variant, not
708  // just the one that it currently holds.
709  return f(storage.V2, std::forward<Args>(args)...);
710  case 3:
711  // If you get a compile error here, it probably means that you have called
712  // Variant::CastAndCall with a functor that does not accept one of the types in the
713  // Variant. The functor you provide must be callable with all types in the Variant, not
714  // just the one that it currently holds.
715  return f(storage.V3, std::forward<Args>(args)...);
716  }
717  }
718 };
719 template<>
720 struct VariantCases<5>
721 {
722  template <typename Functor, typename UnionType, typename... Args>
723  VTK_M_DEVICE static
724 #ifdef VTKM_HIP
725  // this is a temporary solution to improve Kokkos/HIP compile times for
726  // ConnectivityTracer in Rendering.
727  //
728  // This function currently gets inlined many times, which dramatically increases
729  // both compile time and the size of the resulting code-object
730  __attribute__((noinline))
731 #else
732  inline
733 #endif
734  auto CastAndCall(
735  vtkm::IdComponent index,
736  Functor&& f,
737  UnionType& storage,
738  Args&&... args) noexcept(noexcept(f(storage.V0, args...)))
739  -> decltype(f(storage.V0, args...))
740  {
741  // Assume index is 0. Saves us some conditionals.
742  VTKM_ASSERT((index >= 0) && (index < 5));
743  switch (index)
744  {
745  default:
746  case 0:
747  // If you get a compile error here, it probably means that you have called
748  // Variant::CastAndCall with a functor that does not accept one of the types in the
749  // Variant. The functor you provide must be callable with all types in the Variant, not
750  // just the one that it currently holds.
751  return f(storage.V0, std::forward<Args>(args)...);
752  case 1:
753  // If you get a compile error here, it probably means that you have called
754  // Variant::CastAndCall with a functor that does not accept one of the types in the
755  // Variant. The functor you provide must be callable with all types in the Variant, not
756  // just the one that it currently holds.
757  return f(storage.V1, std::forward<Args>(args)...);
758  case 2:
759  // If you get a compile error here, it probably means that you have called
760  // Variant::CastAndCall with a functor that does not accept one of the types in the
761  // Variant. The functor you provide must be callable with all types in the Variant, not
762  // just the one that it currently holds.
763  return f(storage.V2, std::forward<Args>(args)...);
764  case 3:
765  // If you get a compile error here, it probably means that you have called
766  // Variant::CastAndCall with a functor that does not accept one of the types in the
767  // Variant. The functor you provide must be callable with all types in the Variant, not
768  // just the one that it currently holds.
769  return f(storage.V3, std::forward<Args>(args)...);
770  case 4:
771  // If you get a compile error here, it probably means that you have called
772  // Variant::CastAndCall with a functor that does not accept one of the types in the
773  // Variant. The functor you provide must be callable with all types in the Variant, not
774  // just the one that it currently holds.
775  return f(storage.V4, std::forward<Args>(args)...);
776  }
777  }
778 };
779 template<>
780 struct VariantCases<6>
781 {
782  template <typename Functor, typename UnionType, typename... Args>
783  VTK_M_DEVICE static
784 #ifdef VTKM_HIP
785  // this is a temporary solution to improve Kokkos/HIP compile times for
786  // ConnectivityTracer in Rendering.
787  //
788  // This function currently gets inlined many times, which dramatically increases
789  // both compile time and the size of the resulting code-object
790  __attribute__((noinline))
791 #else
792  inline
793 #endif
794  auto CastAndCall(
795  vtkm::IdComponent index,
796  Functor&& f,
797  UnionType& storage,
798  Args&&... args) noexcept(noexcept(f(storage.V0, args...)))
799  -> decltype(f(storage.V0, args...))
800  {
801  // Assume index is 0. Saves us some conditionals.
802  VTKM_ASSERT((index >= 0) && (index < 6));
803  switch (index)
804  {
805  default:
806  case 0:
807  // If you get a compile error here, it probably means that you have called
808  // Variant::CastAndCall with a functor that does not accept one of the types in the
809  // Variant. The functor you provide must be callable with all types in the Variant, not
810  // just the one that it currently holds.
811  return f(storage.V0, std::forward<Args>(args)...);
812  case 1:
813  // If you get a compile error here, it probably means that you have called
814  // Variant::CastAndCall with a functor that does not accept one of the types in the
815  // Variant. The functor you provide must be callable with all types in the Variant, not
816  // just the one that it currently holds.
817  return f(storage.V1, std::forward<Args>(args)...);
818  case 2:
819  // If you get a compile error here, it probably means that you have called
820  // Variant::CastAndCall with a functor that does not accept one of the types in the
821  // Variant. The functor you provide must be callable with all types in the Variant, not
822  // just the one that it currently holds.
823  return f(storage.V2, std::forward<Args>(args)...);
824  case 3:
825  // If you get a compile error here, it probably means that you have called
826  // Variant::CastAndCall with a functor that does not accept one of the types in the
827  // Variant. The functor you provide must be callable with all types in the Variant, not
828  // just the one that it currently holds.
829  return f(storage.V3, std::forward<Args>(args)...);
830  case 4:
831  // If you get a compile error here, it probably means that you have called
832  // Variant::CastAndCall with a functor that does not accept one of the types in the
833  // Variant. The functor you provide must be callable with all types in the Variant, not
834  // just the one that it currently holds.
835  return f(storage.V4, std::forward<Args>(args)...);
836  case 5:
837  // If you get a compile error here, it probably means that you have called
838  // Variant::CastAndCall with a functor that does not accept one of the types in the
839  // Variant. The functor you provide must be callable with all types in the Variant, not
840  // just the one that it currently holds.
841  return f(storage.V5, std::forward<Args>(args)...);
842  }
843  }
844 };
845 template<>
846 struct VariantCases<7>
847 {
848  template <typename Functor, typename UnionType, typename... Args>
849  VTK_M_DEVICE static
850 #ifdef VTKM_HIP
851  // this is a temporary solution to improve Kokkos/HIP compile times for
852  // ConnectivityTracer in Rendering.
853  //
854  // This function currently gets inlined many times, which dramatically increases
855  // both compile time and the size of the resulting code-object
856  __attribute__((noinline))
857 #else
858  inline
859 #endif
860  auto CastAndCall(
861  vtkm::IdComponent index,
862  Functor&& f,
863  UnionType& storage,
864  Args&&... args) noexcept(noexcept(f(storage.V0, args...)))
865  -> decltype(f(storage.V0, args...))
866  {
867  // Assume index is 0. Saves us some conditionals.
868  VTKM_ASSERT((index >= 0) && (index < 7));
869  switch (index)
870  {
871  default:
872  case 0:
873  // If you get a compile error here, it probably means that you have called
874  // Variant::CastAndCall with a functor that does not accept one of the types in the
875  // Variant. The functor you provide must be callable with all types in the Variant, not
876  // just the one that it currently holds.
877  return f(storage.V0, std::forward<Args>(args)...);
878  case 1:
879  // If you get a compile error here, it probably means that you have called
880  // Variant::CastAndCall with a functor that does not accept one of the types in the
881  // Variant. The functor you provide must be callable with all types in the Variant, not
882  // just the one that it currently holds.
883  return f(storage.V1, std::forward<Args>(args)...);
884  case 2:
885  // If you get a compile error here, it probably means that you have called
886  // Variant::CastAndCall with a functor that does not accept one of the types in the
887  // Variant. The functor you provide must be callable with all types in the Variant, not
888  // just the one that it currently holds.
889  return f(storage.V2, std::forward<Args>(args)...);
890  case 3:
891  // If you get a compile error here, it probably means that you have called
892  // Variant::CastAndCall with a functor that does not accept one of the types in the
893  // Variant. The functor you provide must be callable with all types in the Variant, not
894  // just the one that it currently holds.
895  return f(storage.V3, std::forward<Args>(args)...);
896  case 4:
897  // If you get a compile error here, it probably means that you have called
898  // Variant::CastAndCall with a functor that does not accept one of the types in the
899  // Variant. The functor you provide must be callable with all types in the Variant, not
900  // just the one that it currently holds.
901  return f(storage.V4, std::forward<Args>(args)...);
902  case 5:
903  // If you get a compile error here, it probably means that you have called
904  // Variant::CastAndCall with a functor that does not accept one of the types in the
905  // Variant. The functor you provide must be callable with all types in the Variant, not
906  // just the one that it currently holds.
907  return f(storage.V5, std::forward<Args>(args)...);
908  case 6:
909  // If you get a compile error here, it probably means that you have called
910  // Variant::CastAndCall with a functor that does not accept one of the types in the
911  // Variant. The functor you provide must be callable with all types in the Variant, not
912  // just the one that it currently holds.
913  return f(storage.V6, std::forward<Args>(args)...);
914  }
915  }
916 };
917 template<>
918 struct VariantCases<8>
919 {
920  template <typename Functor, typename UnionType, typename... Args>
921  VTK_M_DEVICE static
922 #ifdef VTKM_HIP
923  // this is a temporary solution to improve Kokkos/HIP compile times for
924  // ConnectivityTracer in Rendering.
925  //
926  // This function currently gets inlined many times, which dramatically increases
927  // both compile time and the size of the resulting code-object
928  __attribute__((noinline))
929 #else
930  inline
931 #endif
932  auto CastAndCall(
933  vtkm::IdComponent index,
934  Functor&& f,
935  UnionType& storage,
936  Args&&... args) noexcept(noexcept(f(storage.V0, args...)))
937  -> decltype(f(storage.V0, args...))
938  {
939  // Assume index is 0. Saves us some conditionals.
940  VTKM_ASSERT((index >= 0) && (index < 8));
941  switch (index)
942  {
943  default:
944  case 0:
945  // If you get a compile error here, it probably means that you have called
946  // Variant::CastAndCall with a functor that does not accept one of the types in the
947  // Variant. The functor you provide must be callable with all types in the Variant, not
948  // just the one that it currently holds.
949  return f(storage.V0, std::forward<Args>(args)...);
950  case 1:
951  // If you get a compile error here, it probably means that you have called
952  // Variant::CastAndCall with a functor that does not accept one of the types in the
953  // Variant. The functor you provide must be callable with all types in the Variant, not
954  // just the one that it currently holds.
955  return f(storage.V1, std::forward<Args>(args)...);
956  case 2:
957  // If you get a compile error here, it probably means that you have called
958  // Variant::CastAndCall with a functor that does not accept one of the types in the
959  // Variant. The functor you provide must be callable with all types in the Variant, not
960  // just the one that it currently holds.
961  return f(storage.V2, std::forward<Args>(args)...);
962  case 3:
963  // If you get a compile error here, it probably means that you have called
964  // Variant::CastAndCall with a functor that does not accept one of the types in the
965  // Variant. The functor you provide must be callable with all types in the Variant, not
966  // just the one that it currently holds.
967  return f(storage.V3, std::forward<Args>(args)...);
968  case 4:
969  // If you get a compile error here, it probably means that you have called
970  // Variant::CastAndCall with a functor that does not accept one of the types in the
971  // Variant. The functor you provide must be callable with all types in the Variant, not
972  // just the one that it currently holds.
973  return f(storage.V4, std::forward<Args>(args)...);
974  case 5:
975  // If you get a compile error here, it probably means that you have called
976  // Variant::CastAndCall with a functor that does not accept one of the types in the
977  // Variant. The functor you provide must be callable with all types in the Variant, not
978  // just the one that it currently holds.
979  return f(storage.V5, std::forward<Args>(args)...);
980  case 6:
981  // If you get a compile error here, it probably means that you have called
982  // Variant::CastAndCall with a functor that does not accept one of the types in the
983  // Variant. The functor you provide must be callable with all types in the Variant, not
984  // just the one that it currently holds.
985  return f(storage.V6, std::forward<Args>(args)...);
986  case 7:
987  // If you get a compile error here, it probably means that you have called
988  // Variant::CastAndCall with a functor that does not accept one of the types in the
989  // Variant. The functor you provide must be callable with all types in the Variant, not
990  // just the one that it currently holds.
991  return f(storage.V7, std::forward<Args>(args)...);
992  }
993  }
994 };
995 
996 
997 template <std::size_t UnionSize, typename Functor, typename UnionType, typename... Args>
998 VTK_M_DEVICE inline auto VariantCastAndCallImpl(
999  vtkm::IdComponent index,
1000  Functor&& f,
1001  UnionType& storage,
1002  Args&&... args) noexcept(noexcept(f(storage.V0, args...)))
1003  -> decltype(f(storage.V0, args...))
1004 {
1006  index, std::forward<Functor>(f), storage, std::forward<Args>(args)...);
1007 }
1008 
1009 }
1010 }
1011 } // vtkm::VTK_M_NAMESPACE::detail
vtkm
Groups connected points that have the same field value.
Definition: Atomic.h:19
Types.h
VTKM_ASSERT
#define VTKM_ASSERT(condition)
Definition: Assert.h:43
vtkm::Get
VTKM_SUPPRESS_EXEC_WARNINGS VTKM_EXEC_CONT auto Get(const vtkm::Tuple< Ts... > &tuple) -> decltype(tuple.template Get< Index >())
Retrieve the object from a vtkm::Tuple at the given index.
Definition: Tuple.h:83
vtkm::IdComponent
vtkm::Int32 IdComponent
Represents a component ID (index of component in a vector).
Definition: Types.h:168
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
VTK_M_NAMESPACE
#define VTK_M_NAMESPACE
Definition: VariantImplDetail.h:17
vtkm::List
Definition: List.h:34
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:839
List.h
VTK_M_DEVICE
#define VTK_M_DEVICE
Definition: VariantImplDetail.h:16