//============================================================================ // 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 namespace vtkm { namespace VTK_M_NAMESPACE { namespace internal { namespace detail { template struct VariantDummyReturn { VTK_M_DEVICE static inline ReturnType F() noexcept { return ReturnType{}; } }; template <> struct VariantDummyReturn { VTK_M_DEVICE static inline void F() noexcept {} }; // clang-format off // -------------------------------------------------------------------------------- // Helper classes to determine if all Variant types are trivial. template struct AllTriviallyCopyable; template struct AllTriviallyCopyable : std::integral_constant::value && vtkmstd::is_trivially_copyable::value && vtkmstd::is_trivially_copyable::value && vtkmstd::is_trivially_copyable::value && vtkmstd::is_trivially_copyable::value && vtkmstd::is_trivially_copyable::value && vtkmstd::is_trivially_copyable::value && vtkmstd::is_trivially_copyable::value && vtkmstd::is_trivially_copyable::value && vtkmstd::is_trivially_copyable::value && vtkmstd::is_trivially_copyable::value && vtkmstd::is_trivially_copyable::value && vtkmstd::is_trivially_copyable::value && vtkmstd::is_trivially_copyable::value && vtkmstd::is_trivially_copyable::value && vtkmstd::is_trivially_copyable::value && vtkmstd::is_trivially_copyable::value && vtkmstd::is_trivially_copyable::value && vtkmstd::is_trivially_copyable::value && vtkmstd::is_trivially_copyable::value)> { }; template struct AllTriviallyCopyable : std::integral_constant::value && AllTriviallyCopyable::value)> { }; template struct AllTriviallyConstructible; template struct AllTriviallyConstructible : std::integral_constant::value && vtkmstd::is_trivially_constructible::value && vtkmstd::is_trivially_constructible::value && vtkmstd::is_trivially_constructible::value && vtkmstd::is_trivially_constructible::value && vtkmstd::is_trivially_constructible::value && vtkmstd::is_trivially_constructible::value && vtkmstd::is_trivially_constructible::value && vtkmstd::is_trivially_constructible::value && vtkmstd::is_trivially_constructible::value && vtkmstd::is_trivially_constructible::value && vtkmstd::is_trivially_constructible::value && vtkmstd::is_trivially_constructible::value && vtkmstd::is_trivially_constructible::value && vtkmstd::is_trivially_constructible::value && vtkmstd::is_trivially_constructible::value && vtkmstd::is_trivially_constructible::value && vtkmstd::is_trivially_constructible::value && vtkmstd::is_trivially_constructible::value && vtkmstd::is_trivially_constructible::value)> { }; template struct AllTriviallyConstructible : std::integral_constant::value && AllTriviallyConstructible::value)> { }; template struct AllTriviallyDestructible; template struct AllTriviallyDestructible : std::integral_constant::value && vtkmstd::is_trivially_destructible::value && vtkmstd::is_trivially_destructible::value && vtkmstd::is_trivially_destructible::value && vtkmstd::is_trivially_destructible::value && vtkmstd::is_trivially_destructible::value && vtkmstd::is_trivially_destructible::value && vtkmstd::is_trivially_destructible::value && vtkmstd::is_trivially_destructible::value && vtkmstd::is_trivially_destructible::value && vtkmstd::is_trivially_destructible::value && vtkmstd::is_trivially_destructible::value && vtkmstd::is_trivially_destructible::value && vtkmstd::is_trivially_destructible::value && vtkmstd::is_trivially_destructible::value && vtkmstd::is_trivially_destructible::value && vtkmstd::is_trivially_destructible::value && vtkmstd::is_trivially_destructible::value && vtkmstd::is_trivially_destructible::value && vtkmstd::is_trivially_destructible::value)> { }; template struct AllTriviallyDestructible : std::integral_constant::value && AllTriviallyDestructible::value)> { }; // -------------------------------------------------------------------------------- // 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 { T0 V0; T1 V1; T2 V2; T3 V3; T4 V4; T5 V5; T6 V6; T7 V7; T8 V8; T9 V9; T10 V10; T11 V11; T12 V12; T13 V13; T14 V14; T15 V15; T16 V16; T17 V17; T18 V18; T19 V19; vtkm::internal::NullType Remaining; VTK_M_DEVICE VariantUnionTD(vtkm::internal::NullType) { } VariantUnionTD() = default; }; template union VariantUnionNTD { T0 V0; T1 V1; T2 V2; T3 V3; T4 V4; T5 V5; T6 V6; T7 V7; T8 V8; T9 V9; T10 V10; T11 V11; T12 V12; T13 V13; T14 V14; T15 V15; T16 V16; T17 V17; T18 V18; T19 V19; vtkm::internal::NullType Remaining; VTK_M_DEVICE VariantUnionNTD(vtkm::internal::NullType) { } VariantUnionNTD() = default; VTK_M_DEVICE ~VariantUnionNTD() { } }; template union VariantUnionTD { T0 V0; T1 V1; T2 V2; T3 V3; T4 V4; T5 V5; T6 V6; T7 V7; T8 V8; T9 V9; T10 V10; T11 V11; T12 V12; T13 V13; T14 V14; T15 V15; T16 V16; T17 V17; T18 V18; T19 V19; VariantUnionTD Remaining; VTK_M_DEVICE VariantUnionTD(vtkm::internal::NullType) { } VariantUnionTD() = default; }; template union VariantUnionNTD { T0 V0; T1 V1; T2 V2; T3 V3; T4 V4; T5 V5; T6 V6; T7 V7; T8 V8; T9 V9; T10 V10; T11 V11; T12 V12; T13 V13; T14 V14; T15 V15; T16 V16; T17 V17; T18 V18; T19 V19; VariantUnionNTD Remaining; VTK_M_DEVICE VariantUnionNTD(vtkm::internal::NullType) { } VariantUnionNTD() = default; VTK_M_DEVICE ~VariantUnionNTD() { } }; 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<8, UnionType> { using ReturnType = decltype(std::declval().V8); VTK_M_DEVICE static ReturnType& Get(UnionType& storage) noexcept { return storage.V8; } VTK_M_DEVICE static const ReturnType& Get(const UnionType& storage) noexcept { return storage.V8; } }; template struct VariantUnionGetImpl<9, UnionType> { using ReturnType = decltype(std::declval().V9); VTK_M_DEVICE static ReturnType& Get(UnionType& storage) noexcept { return storage.V9; } VTK_M_DEVICE static const ReturnType& Get(const UnionType& storage) noexcept { return storage.V9; } }; template struct VariantUnionGetImpl<10, UnionType> { using ReturnType = decltype(std::declval().V10); VTK_M_DEVICE static ReturnType& Get(UnionType& storage) noexcept { return storage.V10; } VTK_M_DEVICE static const ReturnType& Get(const UnionType& storage) noexcept { return storage.V10; } }; template struct VariantUnionGetImpl<11, UnionType> { using ReturnType = decltype(std::declval().V11); VTK_M_DEVICE static ReturnType& Get(UnionType& storage) noexcept { return storage.V11; } VTK_M_DEVICE static const ReturnType& Get(const UnionType& storage) noexcept { return storage.V11; } }; template struct VariantUnionGetImpl<12, UnionType> { using ReturnType = decltype(std::declval().V12); VTK_M_DEVICE static ReturnType& Get(UnionType& storage) noexcept { return storage.V12; } VTK_M_DEVICE static const ReturnType& Get(const UnionType& storage) noexcept { return storage.V12; } }; template struct VariantUnionGetImpl<13, UnionType> { using ReturnType = decltype(std::declval().V13); VTK_M_DEVICE static ReturnType& Get(UnionType& storage) noexcept { return storage.V13; } VTK_M_DEVICE static const ReturnType& Get(const UnionType& storage) noexcept { return storage.V13; } }; template struct VariantUnionGetImpl<14, UnionType> { using ReturnType = decltype(std::declval().V14); VTK_M_DEVICE static ReturnType& Get(UnionType& storage) noexcept { return storage.V14; } VTK_M_DEVICE static const ReturnType& Get(const UnionType& storage) noexcept { return storage.V14; } }; template struct VariantUnionGetImpl<15, UnionType> { using ReturnType = decltype(std::declval().V15); VTK_M_DEVICE static ReturnType& Get(UnionType& storage) noexcept { return storage.V15; } VTK_M_DEVICE static const ReturnType& Get(const UnionType& storage) noexcept { return storage.V15; } }; template struct VariantUnionGetImpl<16, UnionType> { using ReturnType = decltype(std::declval().V16); VTK_M_DEVICE static ReturnType& Get(UnionType& storage) noexcept { return storage.V16; } VTK_M_DEVICE static const ReturnType& Get(const UnionType& storage) noexcept { return storage.V16; } }; template struct VariantUnionGetImpl<17, UnionType> { using ReturnType = decltype(std::declval().V17); VTK_M_DEVICE static ReturnType& Get(UnionType& storage) noexcept { return storage.V17; } VTK_M_DEVICE static const ReturnType& Get(const UnionType& storage) noexcept { return storage.V17; } }; template struct VariantUnionGetImpl<18, UnionType> { using ReturnType = decltype(std::declval().V18); VTK_M_DEVICE static ReturnType& Get(UnionType& storage) noexcept { return storage.V18; } VTK_M_DEVICE static const ReturnType& Get(const UnionType& storage) noexcept { return storage.V18; } }; template struct VariantUnionGetImpl<19, UnionType> { using ReturnType = decltype(std::declval().V19); VTK_M_DEVICE static ReturnType& Get(UnionType& storage) noexcept { return storage.V19; } VTK_M_DEVICE static const ReturnType& Get(const UnionType& storage) noexcept { return storage.V19; } }; template struct VariantUnionGetImpl { VTKM_STATIC_ASSERT(I >= 20); 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); } //clang-format on // -------------------------------------------------------------------------------- // Internal implementation of CastAndCall for Variant template VTK_M_DEVICE inline ReturnType VariantCallFunctor( std::false_type, Functor&& f, CastMember& value, Args&&... args) noexcept(noexcept(f(value, args...))) { // 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(value, std::forward(args)...); } template VTK_M_DEVICE inline ReturnType VariantCallFunctor( std::true_type, Functor&&, vtkm::internal::NullType, Args&&...) noexcept { // If we are here, it means a Variant had an inappropriate index. VTKM_ASSERT(false && "Internal error, bad Variant state."); return VariantDummyReturn::F(); } // Terminating condition in recursive template template VTK_M_DEVICE inline ReturnType VariantCastAndCallImplR( std::true_type, vtkm::IdComponent vtkmNotUsed(index), Functor&& vtkmNotUsed(f), vtkm::internal::NullType, Args&&... vtkmNotUsed(args)) noexcept { // If we are here, it means a Variant had an inappropriate index. VTKM_ASSERT(false && "Internal error, bad Variant state."); return VariantDummyReturn::F(); } template VTK_M_DEVICE inline ReturnType VariantCastAndCallImplR( std::false_type, vtkm::IdComponent index, Functor&& f, UnionType& storage, Args&&... args) noexcept(noexcept(f(storage.V0, args...))) { switch (index) { case 0: return VariantCallFunctor( typename std::is_same::type{}, std::forward(f), storage.V0, std::forward(args)...); case 1: return VariantCallFunctor( typename std::is_same::type{}, std::forward(f), storage.V1, std::forward(args)...); case 2: return VariantCallFunctor( typename std::is_same::type{}, std::forward(f), storage.V2, std::forward(args)...); case 3: return VariantCallFunctor( typename std::is_same::type{}, std::forward(f), storage.V3, std::forward(args)...); case 4: return VariantCallFunctor( typename std::is_same::type{}, std::forward(f), storage.V4, std::forward(args)...); case 5: return VariantCallFunctor( typename std::is_same::type{}, std::forward(f), storage.V5, std::forward(args)...); case 6: return VariantCallFunctor( typename std::is_same::type{}, std::forward(f), storage.V6, std::forward(args)...); case 7: return VariantCallFunctor( typename std::is_same::type{}, std::forward(f), storage.V7, std::forward(args)...); case 8: return VariantCallFunctor( typename std::is_same::type{}, std::forward(f), storage.V8, std::forward(args)...); case 9: return VariantCallFunctor( typename std::is_same::type{}, std::forward(f), storage.V9, std::forward(args)...); case 10: return VariantCallFunctor( typename std::is_same::type{}, std::forward(f), storage.V10, std::forward(args)...); case 11: return VariantCallFunctor( typename std::is_same::type{}, std::forward(f), storage.V11, std::forward(args)...); case 12: return VariantCallFunctor( typename std::is_same::type{}, std::forward(f), storage.V12, std::forward(args)...); case 13: return VariantCallFunctor( typename std::is_same::type{}, std::forward(f), storage.V13, std::forward(args)...); case 14: return VariantCallFunctor( typename std::is_same::type{}, std::forward(f), storage.V14, std::forward(args)...); case 15: return VariantCallFunctor( typename std::is_same::type{}, std::forward(f), storage.V15, std::forward(args)...); case 16: return VariantCallFunctor( typename std::is_same::type{}, std::forward(f), storage.V16, std::forward(args)...); case 17: return VariantCallFunctor( typename std::is_same::type{}, std::forward(f), storage.V17, std::forward(args)...); case 18: return VariantCallFunctor( typename std::is_same::type{}, std::forward(f), storage.V18, std::forward(args)...); case 19: return VariantCallFunctor( typename std::is_same::type{}, std::forward(f), storage.V19, std::forward(args)...); default: return VariantCastAndCallImplR( typename std::is_same::type{}, index - 20, std::forward(f), storage.Remaining, 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 VariantCastAndCallImplR( std::false_type{}, index, std::forward(f), storage, std::forward(args)...); } } } } } // vtkm::VTK_M_NAMESPACE::internal::detail