//============================================================================ // Copyright (c) Kitware, Inc. // All rights reserved. // See LICENSE.txt for details. // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notice for more information. //============================================================================ // **** DO NOT EDIT THIS FILE!!! **** // This file is automatically generated by VariantDetail.h.in #if !defined(VTK_M_DEVICE) || !defined(VTK_M_NAMESPACE) #error VarianImplDetail.h must be included from VariantImpl.h // Some defines to make my IDE happy. #define VTK_M_DEVICE #define VTK_M_NAMESPACE tmp #endif #include #include #include #include #include #include namespace vtkm { namespace VTK_M_NAMESPACE { namespace detail { // -------------------------------------------------------------------------------- // Helper classes to determine if all Variant types are trivial. template using AllTriviallyCopyable = vtkm::ListAll, vtkmstd::is_trivially_copyable>; // Single argument version of is_trivially_constructible template using Constructible = vtkmstd::is_trivially_constructible; template using AllTriviallyConstructible = vtkm::ListAll, Constructible>; template using AllTriviallyDestructible = vtkm::ListAll, vtkmstd::is_trivially_destructible>; // -------------------------------------------------------------------------------- // Helper functions to determine the maximum type size. #if defined(VTKM_GCC) && (__GNUC__ == 5) // GCC5 gives an error with `sizeof(Ts)...` for an unexpanded parameter pack. template constexpr std::size_t MaxSizeOf() { return sizeof(T0); } template constexpr std::size_t MaxSizeOf() { return std::max(sizeof(T0), MaxSizeOf()); } #else template constexpr std::size_t MaxSizeOf() { return std::max({ sizeof(Ts)... }); } #endif // -------------------------------------------------------------------------------- // Placeholder for a fully used structure of the given type. template 8)> struct SizedPlaceholder { VTKM_STATIC_ASSERT(Size > 0); vtkm::Int8 A; SizedPlaceholder B; }; template <> struct SizedPlaceholder<1, false> { vtkm::Int8 A; }; template struct SizedPlaceholder { vtkm::Int8 A; vtkm::Int8 B; vtkm::Int8 C; vtkm::Int8 D; vtkm::Int8 E; vtkm::Int8 F; vtkm::Int8 G; vtkm::Int8 H; SizedPlaceholder I; }; // clang-format off // -------------------------------------------------------------------------------- // Union type used inside of Variant // // You may be asking yourself, why not just use an std::aligned_union rather than a real union // type? That was our first implementation, but the problem is that the std::aligned_union // reference needs to be recast to the actual type. Typically you would do that with // reinterpret_cast. However, doing that leads to undefined behavior. The C++ compiler assumes that // 2 pointers of different types point to different memory (even if it is clear that they are set // to the same address). That means optimizers can remove code because it "knows" that data in one // type cannot affect data in another type. (See Shafik Yaghmour's excellent writeup at // https://gist.github.com/shafik/848ae25ee209f698763cffee272a58f8 for more details.) To safely // change the type of an std::aligned_union, you really have to do an std::memcpy. This is // problematic for types that cannot be trivially copied. Another problem is that we found that // device compilers do not optimize the memcpy as well as most CPU compilers. Likely, memcpy is // used much less frequently on GPU devices. // // Part of the trickiness of the union implementation is trying to preserve when the type is // trivially constructible and copyable. The trick is that if members of the union are not trivial, // then the default constructors are deleted. To get around that, a non-default constructor is // added, which we can use to construct the union for non-trivial types. Working with types with // non-trivial destructors are particularly tricky. Again, if any member of the union has a // non-trivial destructor, the destructor is deleted. Unlike a constructor, you cannot just say to // use a different destructor. Thus, we have to define our own destructor for the union. // Technically, the destructor here does not do anything, but the actual destruction should be // handled by the Variant class that contains this VariantUnion. We actually need two separate // implementations of our union, one that defines a destructor and one that use the default // destructor. If you define your own destructor, you can lose the trivial constructor and trivial // copy properties. // // TD = trivially deconstructible template union VariantUnionTD; // NTD = non-trivially deconstructible template union VariantUnionNTD; template union VariantUnionTD { // Work around issue where CUDA sometimes seems to miss initializing some struct members // if another entry in the varient has a struct with padding. Place an item that requires // everthing to be copied. SizedPlaceholder()> Placeholder; T0 V0; VTK_M_DEVICE VariantUnionTD(vtkm::internal::NullType) { } VariantUnionTD() = default; }; template union VariantUnionNTD { // Work around issue where CUDA sometimes seems to miss initializing some struct members // if another entry in the varient has a struct with padding. Place an item that requires // everthing to be copied. SizedPlaceholder()> Placeholder; T0 V0; VTK_M_DEVICE VariantUnionNTD(vtkm::internal::NullType) { } VariantUnionNTD() = default; VTK_M_DEVICE ~VariantUnionNTD() { } }; template union VariantUnionTD { // Work around issue where CUDA sometimes seems to miss initializing some struct members // if another entry in the varient has a struct with padding. Place an item that requires // everthing to be copied. SizedPlaceholder()> Placeholder; T0 V0; T1 V1; VTK_M_DEVICE VariantUnionTD(vtkm::internal::NullType) { } VariantUnionTD() = default; }; template union VariantUnionNTD { // Work around issue where CUDA sometimes seems to miss initializing some struct members // if another entry in the varient has a struct with padding. Place an item that requires // everthing to be copied. SizedPlaceholder()> Placeholder; T0 V0; T1 V1; VTK_M_DEVICE VariantUnionNTD(vtkm::internal::NullType) { } VariantUnionNTD() = default; VTK_M_DEVICE ~VariantUnionNTD() { } }; template union VariantUnionTD { // Work around issue where CUDA sometimes seems to miss initializing some struct members // if another entry in the varient has a struct with padding. Place an item that requires // everthing to be copied. SizedPlaceholder()> Placeholder; T0 V0; T1 V1; T2 V2; VTK_M_DEVICE VariantUnionTD(vtkm::internal::NullType) { } VariantUnionTD() = default; }; template union VariantUnionNTD { // Work around issue where CUDA sometimes seems to miss initializing some struct members // if another entry in the varient has a struct with padding. Place an item that requires // everthing to be copied. SizedPlaceholder()> Placeholder; T0 V0; T1 V1; T2 V2; VTK_M_DEVICE VariantUnionNTD(vtkm::internal::NullType) { } VariantUnionNTD() = default; VTK_M_DEVICE ~VariantUnionNTD() { } }; template union VariantUnionTD { // Work around issue where CUDA sometimes seems to miss initializing some struct members // if another entry in the varient has a struct with padding. Place an item that requires // everthing to be copied. SizedPlaceholder()> Placeholder; T0 V0; T1 V1; T2 V2; T3 V3; VTK_M_DEVICE VariantUnionTD(vtkm::internal::NullType) { } VariantUnionTD() = default; }; template union VariantUnionNTD { // Work around issue where CUDA sometimes seems to miss initializing some struct members // if another entry in the varient has a struct with padding. Place an item that requires // everthing to be copied. SizedPlaceholder()> Placeholder; T0 V0; T1 V1; T2 V2; T3 V3; VTK_M_DEVICE VariantUnionNTD(vtkm::internal::NullType) { } VariantUnionNTD() = default; VTK_M_DEVICE ~VariantUnionNTD() { } }; template union VariantUnionTD { // Work around issue where CUDA sometimes seems to miss initializing some struct members // if another entry in the varient has a struct with padding. Place an item that requires // everthing to be copied. SizedPlaceholder()> Placeholder; T0 V0; T1 V1; T2 V2; T3 V3; T4 V4; VTK_M_DEVICE VariantUnionTD(vtkm::internal::NullType) { } VariantUnionTD() = default; }; template union VariantUnionNTD { // Work around issue where CUDA sometimes seems to miss initializing some struct members // if another entry in the varient has a struct with padding. Place an item that requires // everthing to be copied. SizedPlaceholder()> Placeholder; T0 V0; T1 V1; T2 V2; T3 V3; T4 V4; VTK_M_DEVICE VariantUnionNTD(vtkm::internal::NullType) { } VariantUnionNTD() = default; VTK_M_DEVICE ~VariantUnionNTD() { } }; template union VariantUnionTD { // Work around issue where CUDA sometimes seems to miss initializing some struct members // if another entry in the varient has a struct with padding. Place an item that requires // everthing to be copied. SizedPlaceholder()> Placeholder; T0 V0; T1 V1; T2 V2; T3 V3; T4 V4; T5 V5; VTK_M_DEVICE VariantUnionTD(vtkm::internal::NullType) { } VariantUnionTD() = default; }; template union VariantUnionNTD { // Work around issue where CUDA sometimes seems to miss initializing some struct members // if another entry in the varient has a struct with padding. Place an item that requires // everthing to be copied. SizedPlaceholder()> Placeholder; T0 V0; T1 V1; T2 V2; T3 V3; T4 V4; T5 V5; VTK_M_DEVICE VariantUnionNTD(vtkm::internal::NullType) { } VariantUnionNTD() = default; VTK_M_DEVICE ~VariantUnionNTD() { } }; template union VariantUnionTD { // Work around issue where CUDA sometimes seems to miss initializing some struct members // if another entry in the varient has a struct with padding. Place an item that requires // everthing to be copied. SizedPlaceholder()> Placeholder; T0 V0; T1 V1; T2 V2; T3 V3; T4 V4; T5 V5; T6 V6; VTK_M_DEVICE VariantUnionTD(vtkm::internal::NullType) { } VariantUnionTD() = default; }; template union VariantUnionNTD { // Work around issue where CUDA sometimes seems to miss initializing some struct members // if another entry in the varient has a struct with padding. Place an item that requires // everthing to be copied. SizedPlaceholder()> Placeholder; T0 V0; T1 V1; T2 V2; T3 V3; T4 V4; T5 V5; T6 V6; VTK_M_DEVICE VariantUnionNTD(vtkm::internal::NullType) { } VariantUnionNTD() = default; VTK_M_DEVICE ~VariantUnionNTD() { } }; template union VariantUnionTD { // Work around issue where CUDA sometimes seems to miss initializing some struct members // if another entry in the varient has a struct with padding. Place an item that requires // everthing to be copied. SizedPlaceholder()> Placeholder; T0 V0; T1 V1; T2 V2; T3 V3; T4 V4; T5 V5; T6 V6; T7 V7; VTK_M_DEVICE VariantUnionTD(vtkm::internal::NullType) { } VariantUnionTD() = default; }; template union VariantUnionNTD { // Work around issue where CUDA sometimes seems to miss initializing some struct members // if another entry in the varient has a struct with padding. Place an item that requires // everthing to be copied. SizedPlaceholder()> Placeholder; T0 V0; T1 V1; T2 V2; T3 V3; T4 V4; T5 V5; T6 V6; T7 V7; VTK_M_DEVICE VariantUnionNTD(vtkm::internal::NullType) { } VariantUnionNTD() = default; VTK_M_DEVICE ~VariantUnionNTD() { } }; template union VariantUnionTD { // Work around issue where CUDA sometimes seems to miss initializing some struct members // if another entry in the varient has a struct with padding. Place an item that requires // everthing to be copied. SizedPlaceholder()> Placeholder; T0 V0; T1 V1; T2 V2; T3 V3; T4 V4; T5 V5; T6 V6; T7 V7; VariantUnionTD Remaining; VTK_M_DEVICE VariantUnionTD(vtkm::internal::NullType) { } VariantUnionTD() = default; }; template union VariantUnionNTD { // Work around issue where CUDA sometimes seems to miss initializing some struct members // if another entry in the varient has a struct with padding. Place an item that requires // everthing to be copied. SizedPlaceholder()> Placeholder; T0 V0; T1 V1; T2 V2; T3 V3; T4 V4; T5 V5; T6 V6; T7 V7; VariantUnionNTD Remaining; VTK_M_DEVICE VariantUnionNTD(vtkm::internal::NullType) { } VariantUnionNTD() = default; VTK_M_DEVICE ~VariantUnionNTD() { } }; //clang-format on template struct VariantUnionFinder; template struct VariantUnionFinder { using type = VariantUnionTD; }; template struct VariantUnionFinder { using type = VariantUnionNTD; }; template using VariantUnion = typename VariantUnionFinder::value, Ts...>::type; // -------------------------------------------------------------------------------- // Methods to get values out of the variant union template struct VariantUnionGetImpl; template struct VariantUnionGetImpl<0, UnionType> { using ReturnType = decltype(std::declval().V0); VTK_M_DEVICE static ReturnType& Get(UnionType& storage) noexcept { return storage.V0; } VTK_M_DEVICE static const ReturnType& Get(const UnionType& storage) noexcept { return storage.V0; } }; template struct VariantUnionGetImpl<1, UnionType> { using ReturnType = decltype(std::declval().V1); VTK_M_DEVICE static ReturnType& Get(UnionType& storage) noexcept { return storage.V1; } VTK_M_DEVICE static const ReturnType& Get(const UnionType& storage) noexcept { return storage.V1; } }; template struct VariantUnionGetImpl<2, UnionType> { using ReturnType = decltype(std::declval().V2); VTK_M_DEVICE static ReturnType& Get(UnionType& storage) noexcept { return storage.V2; } VTK_M_DEVICE static const ReturnType& Get(const UnionType& storage) noexcept { return storage.V2; } }; template struct VariantUnionGetImpl<3, UnionType> { using ReturnType = decltype(std::declval().V3); VTK_M_DEVICE static ReturnType& Get(UnionType& storage) noexcept { return storage.V3; } VTK_M_DEVICE static const ReturnType& Get(const UnionType& storage) noexcept { return storage.V3; } }; template struct VariantUnionGetImpl<4, UnionType> { using ReturnType = decltype(std::declval().V4); VTK_M_DEVICE static ReturnType& Get(UnionType& storage) noexcept { return storage.V4; } VTK_M_DEVICE static const ReturnType& Get(const UnionType& storage) noexcept { return storage.V4; } }; template struct VariantUnionGetImpl<5, UnionType> { using ReturnType = decltype(std::declval().V5); VTK_M_DEVICE static ReturnType& Get(UnionType& storage) noexcept { return storage.V5; } VTK_M_DEVICE static const ReturnType& Get(const UnionType& storage) noexcept { return storage.V5; } }; template struct VariantUnionGetImpl<6, UnionType> { using ReturnType = decltype(std::declval().V6); VTK_M_DEVICE static ReturnType& Get(UnionType& storage) noexcept { return storage.V6; } VTK_M_DEVICE static const ReturnType& Get(const UnionType& storage) noexcept { return storage.V6; } }; template struct VariantUnionGetImpl<7, UnionType> { using ReturnType = decltype(std::declval().V7); VTK_M_DEVICE static ReturnType& Get(UnionType& storage) noexcept { return storage.V7; } VTK_M_DEVICE static const ReturnType& Get(const UnionType& storage) noexcept { return storage.V7; } }; template struct VariantUnionGetImpl { VTKM_STATIC_ASSERT(I >= 8); using RecursiveGet = VariantUnionGetImpl().Remaining)>; using ReturnType = typename RecursiveGet::ReturnType; VTK_M_DEVICE static ReturnType& Get(UnionType& storage) noexcept { return RecursiveGet::Get(storage.Remaining); } VTK_M_DEVICE static const ReturnType& Get(const UnionType& storage) noexcept { return RecursiveGet::Get(storage.Remaining); } }; template VTK_M_DEVICE auto VariantUnionGet(UnionType& storage) noexcept -> decltype(VariantUnionGetImpl::type>::Get(storage))& { return VariantUnionGetImpl::type>::Get(storage); } // -------------------------------------------------------------------------------- // Internal implementation of CastAndCall for Variant template struct VariantCases { template VTK_M_DEVICE static #ifdef VTKM_HIP // this is a temporary solution to improve Kokkos/HIP compile times for // ConnectivityTracer in Rendering. // // This function currently gets inlined many times, which dramatically increases // both compile time and the size of the resulting code-object __attribute__((noinline)) #else inline #endif auto CastAndCall( vtkm::IdComponent index, Functor&& f, UnionType& storage, Args&&... args) noexcept(noexcept(f(storage.V0, args...))) -> decltype(f(storage.V0, args...)) { VTKM_ASSERT((index >= 0) && (index < static_cast(NumCases))); switch (index) { case 0: // If you get a compile error here, it probably means that you have called // Variant::CastAndCall with a functor that does not accept one of the types in the // Variant. The functor you provide must be callable with all types in the Variant, not // just the one that it currently holds. return f(storage.V0, std::forward(args)...); case 1: // If you get a compile error here, it probably means that you have called // Variant::CastAndCall with a functor that does not accept one of the types in the // Variant. The functor you provide must be callable with all types in the Variant, not // just the one that it currently holds. return f(storage.V1, std::forward(args)...); case 2: // If you get a compile error here, it probably means that you have called // Variant::CastAndCall with a functor that does not accept one of the types in the // Variant. The functor you provide must be callable with all types in the Variant, not // just the one that it currently holds. return f(storage.V2, std::forward(args)...); case 3: // If you get a compile error here, it probably means that you have called // Variant::CastAndCall with a functor that does not accept one of the types in the // Variant. The functor you provide must be callable with all types in the Variant, not // just the one that it currently holds. return f(storage.V3, std::forward(args)...); case 4: // If you get a compile error here, it probably means that you have called // Variant::CastAndCall with a functor that does not accept one of the types in the // Variant. The functor you provide must be callable with all types in the Variant, not // just the one that it currently holds. return f(storage.V4, std::forward(args)...); case 5: // If you get a compile error here, it probably means that you have called // Variant::CastAndCall with a functor that does not accept one of the types in the // Variant. The functor you provide must be callable with all types in the Variant, not // just the one that it currently holds. return f(storage.V5, std::forward(args)...); case 6: // If you get a compile error here, it probably means that you have called // Variant::CastAndCall with a functor that does not accept one of the types in the // Variant. The functor you provide must be callable with all types in the Variant, not // just the one that it currently holds. return f(storage.V6, std::forward(args)...); case 7: // If you get a compile error here, it probably means that you have called // Variant::CastAndCall with a functor that does not accept one of the types in the // Variant. The functor you provide must be callable with all types in the Variant, not // just the one that it currently holds. return f(storage.V7, std::forward(args)...); default: return VariantCases::template CastAndCall( index - 8, std::forward(f), storage.Remaining, std::forward(args)...); } } }; template<> struct VariantCases<1> { template VTK_M_DEVICE static inline auto CastAndCall( vtkm::IdComponent index, Functor&& f, UnionType& storage, Args&&... args) noexcept(noexcept(f(storage.V0, args...))) -> decltype(f(storage.V0, args...)) { // Assume index is 0. Saves us some conditionals. VTKM_ASSERT(index == 0); (void)index; return f(storage.V0, std::forward(args)...); } }; template<> struct VariantCases<2> { template VTK_M_DEVICE static #ifdef VTKM_HIP // this is a temporary solution to improve Kokkos/HIP compile times for // ConnectivityTracer in Rendering. // // This function currently gets inlined many times, which dramatically increases // both compile time and the size of the resulting code-object __attribute__((noinline)) #else inline #endif auto CastAndCall( vtkm::IdComponent index, Functor&& f, UnionType& storage, Args&&... args) noexcept(noexcept(f(storage.V0, args...))) -> decltype(f(storage.V0, args...)) { // Assume index is 0. Saves us some conditionals. VTKM_ASSERT((index >= 0) && (index < 2)); switch (index) { default: case 0: // If you get a compile error here, it probably means that you have called // Variant::CastAndCall with a functor that does not accept one of the types in the // Variant. The functor you provide must be callable with all types in the Variant, not // just the one that it currently holds. return f(storage.V0, std::forward(args)...); case 1: // If you get a compile error here, it probably means that you have called // Variant::CastAndCall with a functor that does not accept one of the types in the // Variant. The functor you provide must be callable with all types in the Variant, not // just the one that it currently holds. return f(storage.V1, std::forward(args)...); } } }; template<> struct VariantCases<3> { template VTK_M_DEVICE static #ifdef VTKM_HIP // this is a temporary solution to improve Kokkos/HIP compile times for // ConnectivityTracer in Rendering. // // This function currently gets inlined many times, which dramatically increases // both compile time and the size of the resulting code-object __attribute__((noinline)) #else inline #endif auto CastAndCall( vtkm::IdComponent index, Functor&& f, UnionType& storage, Args&&... args) noexcept(noexcept(f(storage.V0, args...))) -> decltype(f(storage.V0, args...)) { // Assume index is 0. Saves us some conditionals. VTKM_ASSERT((index >= 0) && (index < 3)); switch (index) { default: case 0: // If you get a compile error here, it probably means that you have called // Variant::CastAndCall with a functor that does not accept one of the types in the // Variant. The functor you provide must be callable with all types in the Variant, not // just the one that it currently holds. return f(storage.V0, std::forward(args)...); case 1: // If you get a compile error here, it probably means that you have called // Variant::CastAndCall with a functor that does not accept one of the types in the // Variant. The functor you provide must be callable with all types in the Variant, not // just the one that it currently holds. return f(storage.V1, std::forward(args)...); case 2: // If you get a compile error here, it probably means that you have called // Variant::CastAndCall with a functor that does not accept one of the types in the // Variant. The functor you provide must be callable with all types in the Variant, not // just the one that it currently holds. return f(storage.V2, std::forward(args)...); } } }; template<> struct VariantCases<4> { template VTK_M_DEVICE static #ifdef VTKM_HIP // this is a temporary solution to improve Kokkos/HIP compile times for // ConnectivityTracer in Rendering. // // This function currently gets inlined many times, which dramatically increases // both compile time and the size of the resulting code-object __attribute__((noinline)) #else inline #endif auto CastAndCall( vtkm::IdComponent index, Functor&& f, UnionType& storage, Args&&... args) noexcept(noexcept(f(storage.V0, args...))) -> decltype(f(storage.V0, args...)) { // Assume index is 0. Saves us some conditionals. VTKM_ASSERT((index >= 0) && (index < 4)); switch (index) { default: case 0: // If you get a compile error here, it probably means that you have called // Variant::CastAndCall with a functor that does not accept one of the types in the // Variant. The functor you provide must be callable with all types in the Variant, not // just the one that it currently holds. return f(storage.V0, std::forward(args)...); case 1: // If you get a compile error here, it probably means that you have called // Variant::CastAndCall with a functor that does not accept one of the types in the // Variant. The functor you provide must be callable with all types in the Variant, not // just the one that it currently holds. return f(storage.V1, std::forward(args)...); case 2: // If you get a compile error here, it probably means that you have called // Variant::CastAndCall with a functor that does not accept one of the types in the // Variant. The functor you provide must be callable with all types in the Variant, not // just the one that it currently holds. return f(storage.V2, std::forward(args)...); case 3: // If you get a compile error here, it probably means that you have called // Variant::CastAndCall with a functor that does not accept one of the types in the // Variant. The functor you provide must be callable with all types in the Variant, not // just the one that it currently holds. return f(storage.V3, std::forward(args)...); } } }; template<> struct VariantCases<5> { template VTK_M_DEVICE static #ifdef VTKM_HIP // this is a temporary solution to improve Kokkos/HIP compile times for // ConnectivityTracer in Rendering. // // This function currently gets inlined many times, which dramatically increases // both compile time and the size of the resulting code-object __attribute__((noinline)) #else inline #endif auto CastAndCall( vtkm::IdComponent index, Functor&& f, UnionType& storage, Args&&... args) noexcept(noexcept(f(storage.V0, args...))) -> decltype(f(storage.V0, args...)) { // Assume index is 0. Saves us some conditionals. VTKM_ASSERT((index >= 0) && (index < 5)); switch (index) { default: case 0: // If you get a compile error here, it probably means that you have called // Variant::CastAndCall with a functor that does not accept one of the types in the // Variant. The functor you provide must be callable with all types in the Variant, not // just the one that it currently holds. return f(storage.V0, std::forward(args)...); case 1: // If you get a compile error here, it probably means that you have called // Variant::CastAndCall with a functor that does not accept one of the types in the // Variant. The functor you provide must be callable with all types in the Variant, not // just the one that it currently holds. return f(storage.V1, std::forward(args)...); case 2: // If you get a compile error here, it probably means that you have called // Variant::CastAndCall with a functor that does not accept one of the types in the // Variant. The functor you provide must be callable with all types in the Variant, not // just the one that it currently holds. return f(storage.V2, std::forward(args)...); case 3: // If you get a compile error here, it probably means that you have called // Variant::CastAndCall with a functor that does not accept one of the types in the // Variant. The functor you provide must be callable with all types in the Variant, not // just the one that it currently holds. return f(storage.V3, std::forward(args)...); case 4: // If you get a compile error here, it probably means that you have called // Variant::CastAndCall with a functor that does not accept one of the types in the // Variant. The functor you provide must be callable with all types in the Variant, not // just the one that it currently holds. return f(storage.V4, std::forward(args)...); } } }; template<> struct VariantCases<6> { template VTK_M_DEVICE static #ifdef VTKM_HIP // this is a temporary solution to improve Kokkos/HIP compile times for // ConnectivityTracer in Rendering. // // This function currently gets inlined many times, which dramatically increases // both compile time and the size of the resulting code-object __attribute__((noinline)) #else inline #endif auto CastAndCall( vtkm::IdComponent index, Functor&& f, UnionType& storage, Args&&... args) noexcept(noexcept(f(storage.V0, args...))) -> decltype(f(storage.V0, args...)) { // Assume index is 0. Saves us some conditionals. VTKM_ASSERT((index >= 0) && (index < 6)); switch (index) { default: case 0: // If you get a compile error here, it probably means that you have called // Variant::CastAndCall with a functor that does not accept one of the types in the // Variant. The functor you provide must be callable with all types in the Variant, not // just the one that it currently holds. return f(storage.V0, std::forward(args)...); case 1: // If you get a compile error here, it probably means that you have called // Variant::CastAndCall with a functor that does not accept one of the types in the // Variant. The functor you provide must be callable with all types in the Variant, not // just the one that it currently holds. return f(storage.V1, std::forward(args)...); case 2: // If you get a compile error here, it probably means that you have called // Variant::CastAndCall with a functor that does not accept one of the types in the // Variant. The functor you provide must be callable with all types in the Variant, not // just the one that it currently holds. return f(storage.V2, std::forward(args)...); case 3: // If you get a compile error here, it probably means that you have called // Variant::CastAndCall with a functor that does not accept one of the types in the // Variant. The functor you provide must be callable with all types in the Variant, not // just the one that it currently holds. return f(storage.V3, std::forward(args)...); case 4: // If you get a compile error here, it probably means that you have called // Variant::CastAndCall with a functor that does not accept one of the types in the // Variant. The functor you provide must be callable with all types in the Variant, not // just the one that it currently holds. return f(storage.V4, std::forward(args)...); case 5: // If you get a compile error here, it probably means that you have called // Variant::CastAndCall with a functor that does not accept one of the types in the // Variant. The functor you provide must be callable with all types in the Variant, not // just the one that it currently holds. return f(storage.V5, std::forward(args)...); } } }; template<> struct VariantCases<7> { template VTK_M_DEVICE static #ifdef VTKM_HIP // this is a temporary solution to improve Kokkos/HIP compile times for // ConnectivityTracer in Rendering. // // This function currently gets inlined many times, which dramatically increases // both compile time and the size of the resulting code-object __attribute__((noinline)) #else inline #endif auto CastAndCall( vtkm::IdComponent index, Functor&& f, UnionType& storage, Args&&... args) noexcept(noexcept(f(storage.V0, args...))) -> decltype(f(storage.V0, args...)) { // Assume index is 0. Saves us some conditionals. VTKM_ASSERT((index >= 0) && (index < 7)); switch (index) { default: case 0: // If you get a compile error here, it probably means that you have called // Variant::CastAndCall with a functor that does not accept one of the types in the // Variant. The functor you provide must be callable with all types in the Variant, not // just the one that it currently holds. return f(storage.V0, std::forward(args)...); case 1: // If you get a compile error here, it probably means that you have called // Variant::CastAndCall with a functor that does not accept one of the types in the // Variant. The functor you provide must be callable with all types in the Variant, not // just the one that it currently holds. return f(storage.V1, std::forward(args)...); case 2: // If you get a compile error here, it probably means that you have called // Variant::CastAndCall with a functor that does not accept one of the types in the // Variant. The functor you provide must be callable with all types in the Variant, not // just the one that it currently holds. return f(storage.V2, std::forward(args)...); case 3: // If you get a compile error here, it probably means that you have called // Variant::CastAndCall with a functor that does not accept one of the types in the // Variant. The functor you provide must be callable with all types in the Variant, not // just the one that it currently holds. return f(storage.V3, std::forward(args)...); case 4: // If you get a compile error here, it probably means that you have called // Variant::CastAndCall with a functor that does not accept one of the types in the // Variant. The functor you provide must be callable with all types in the Variant, not // just the one that it currently holds. return f(storage.V4, std::forward(args)...); case 5: // If you get a compile error here, it probably means that you have called // Variant::CastAndCall with a functor that does not accept one of the types in the // Variant. The functor you provide must be callable with all types in the Variant, not // just the one that it currently holds. return f(storage.V5, std::forward(args)...); case 6: // If you get a compile error here, it probably means that you have called // Variant::CastAndCall with a functor that does not accept one of the types in the // Variant. The functor you provide must be callable with all types in the Variant, not // just the one that it currently holds. return f(storage.V6, std::forward(args)...); } } }; template<> struct VariantCases<8> { template VTK_M_DEVICE static #ifdef VTKM_HIP // this is a temporary solution to improve Kokkos/HIP compile times for // ConnectivityTracer in Rendering. // // This function currently gets inlined many times, which dramatically increases // both compile time and the size of the resulting code-object __attribute__((noinline)) #else inline #endif auto CastAndCall( vtkm::IdComponent index, Functor&& f, UnionType& storage, Args&&... args) noexcept(noexcept(f(storage.V0, args...))) -> decltype(f(storage.V0, args...)) { // Assume index is 0. Saves us some conditionals. VTKM_ASSERT((index >= 0) && (index < 8)); switch (index) { default: case 0: // If you get a compile error here, it probably means that you have called // Variant::CastAndCall with a functor that does not accept one of the types in the // Variant. The functor you provide must be callable with all types in the Variant, not // just the one that it currently holds. return f(storage.V0, std::forward(args)...); case 1: // If you get a compile error here, it probably means that you have called // Variant::CastAndCall with a functor that does not accept one of the types in the // Variant. The functor you provide must be callable with all types in the Variant, not // just the one that it currently holds. return f(storage.V1, std::forward(args)...); case 2: // If you get a compile error here, it probably means that you have called // Variant::CastAndCall with a functor that does not accept one of the types in the // Variant. The functor you provide must be callable with all types in the Variant, not // just the one that it currently holds. return f(storage.V2, std::forward(args)...); case 3: // If you get a compile error here, it probably means that you have called // Variant::CastAndCall with a functor that does not accept one of the types in the // Variant. The functor you provide must be callable with all types in the Variant, not // just the one that it currently holds. return f(storage.V3, std::forward(args)...); case 4: // If you get a compile error here, it probably means that you have called // Variant::CastAndCall with a functor that does not accept one of the types in the // Variant. The functor you provide must be callable with all types in the Variant, not // just the one that it currently holds. return f(storage.V4, std::forward(args)...); case 5: // If you get a compile error here, it probably means that you have called // Variant::CastAndCall with a functor that does not accept one of the types in the // Variant. The functor you provide must be callable with all types in the Variant, not // just the one that it currently holds. return f(storage.V5, std::forward(args)...); case 6: // If you get a compile error here, it probably means that you have called // Variant::CastAndCall with a functor that does not accept one of the types in the // Variant. The functor you provide must be callable with all types in the Variant, not // just the one that it currently holds. return f(storage.V6, std::forward(args)...); case 7: // If you get a compile error here, it probably means that you have called // Variant::CastAndCall with a functor that does not accept one of the types in the // Variant. The functor you provide must be callable with all types in the Variant, not // just the one that it currently holds. return f(storage.V7, std::forward(args)...); } } }; template VTK_M_DEVICE inline auto VariantCastAndCallImpl( vtkm::IdComponent index, Functor&& f, UnionType& storage, Args&&... args) noexcept(noexcept(f(storage.V0, args...))) -> decltype(f(storage.V0, args...)) { return VariantCases::CastAndCall( index, std::forward(f), storage, std::forward(args)...); } } } } // vtkm::VTK_M_NAMESPACE::detail