mirror of
https://gitlab.kitware.com/vtk/vtk-m
synced 2024-10-05 01:49:02 +00:00
Merge topic 'variant-safe-punning2'
6921b5cc3 Minor style changes in UnitTestVariant 6ccb32d27 Slight comment changes 647bc94fe Reduce the number of lines required to implement Variant::CastAndCall 991eeba9f Reduce the number of lines required to implement VariantUnion 7607736ef Reduce the number of lines required to implement AllTrivially* 9816c422b Add padding to Grid struct in CellLocatorTwoLevel e480fd7a2 Support copying a Variant to itself d2d9ba332 Make connectivity structures trivially copyable ... Acked-by: Kitware Robot <kwrobot@kitware.com> Merge-request: !2444
This commit is contained in:
commit
2bd4805fe0
@ -36,6 +36,10 @@ using FloatVec3 = vtkm::Vec3f;
|
||||
struct Grid
|
||||
{
|
||||
DimVec3 Dimensions;
|
||||
// Bug in CUDA 9.2 where having this gap for alignment was for some reason setting garbage
|
||||
// in a union with other cell locators (or perhaps not properly copying data). This appears
|
||||
// to be fixed by CUDA 10.2.
|
||||
DimensionType Padding;
|
||||
FloatVec3 Origin;
|
||||
FloatVec3 BinSize;
|
||||
};
|
||||
@ -54,6 +58,7 @@ VTKM_EXEC inline vtkm::Id ComputeFlatIndex(const DimVec3& idx, const DimVec3 dim
|
||||
VTKM_EXEC inline Grid ComputeLeafGrid(const DimVec3& idx, const DimVec3& dim, const Grid& l1Grid)
|
||||
{
|
||||
return { dim,
|
||||
0,
|
||||
l1Grid.Origin + (static_cast<FloatVec3>(idx) * l1Grid.BinSize),
|
||||
l1Grid.BinSize / static_cast<FloatVec3>(dim) };
|
||||
}
|
||||
|
@ -27,13 +27,7 @@ class ConnectivityPermutedVisitCellsWithPoints
|
||||
public:
|
||||
using SchedulingRangeType = typename OriginalConnectivity::SchedulingRangeType;
|
||||
|
||||
VTKM_SUPPRESS_EXEC_WARNINGS
|
||||
VTKM_EXEC_CONT
|
||||
ConnectivityPermutedVisitCellsWithPoints()
|
||||
: Portal()
|
||||
, Connectivity()
|
||||
{
|
||||
}
|
||||
ConnectivityPermutedVisitCellsWithPoints() = default;
|
||||
|
||||
VTKM_EXEC_CONT
|
||||
ConnectivityPermutedVisitCellsWithPoints(const PermutationPortal& portal,
|
||||
@ -43,12 +37,8 @@ public:
|
||||
{
|
||||
}
|
||||
|
||||
VTKM_EXEC_CONT
|
||||
ConnectivityPermutedVisitCellsWithPoints(const ConnectivityPermutedVisitCellsWithPoints& src)
|
||||
: Portal(src.Portal)
|
||||
, Connectivity(src.Connectivity)
|
||||
{
|
||||
}
|
||||
ConnectivityPermutedVisitCellsWithPoints(const ConnectivityPermutedVisitCellsWithPoints& src) =
|
||||
default;
|
||||
|
||||
ConnectivityPermutedVisitCellsWithPoints& operator=(
|
||||
const ConnectivityPermutedVisitCellsWithPoints& src) = default;
|
||||
|
@ -34,11 +34,7 @@ class ConnectivityStructured
|
||||
public:
|
||||
using SchedulingRangeType = typename InternalsType::SchedulingRangeType;
|
||||
|
||||
VTKM_EXEC_CONT
|
||||
ConnectivityStructured()
|
||||
: Internals()
|
||||
{
|
||||
}
|
||||
ConnectivityStructured() = default;
|
||||
|
||||
VTKM_EXEC_CONT
|
||||
ConnectivityStructured(const InternalsType& src)
|
||||
@ -46,11 +42,7 @@ public:
|
||||
{
|
||||
}
|
||||
|
||||
VTKM_EXEC_CONT
|
||||
ConnectivityStructured(const ConnectivityStructured& src)
|
||||
: Internals(src.Internals)
|
||||
{
|
||||
}
|
||||
ConnectivityStructured(const ConnectivityStructured& src) = default;
|
||||
|
||||
VTKM_EXEC_CONT
|
||||
ConnectivityStructured(
|
||||
|
@ -34,7 +34,7 @@ static vtkm::Id g_NonTrivialCount;
|
||||
// A class that must is not trivial to copy nor construct.
|
||||
struct NonTrivial
|
||||
{
|
||||
vtkm::Id Value = 12345;
|
||||
vtkm::Id Value;
|
||||
NonTrivial* Self;
|
||||
|
||||
void CheckState() const
|
||||
@ -44,17 +44,19 @@ struct NonTrivial
|
||||
}
|
||||
|
||||
NonTrivial()
|
||||
: Self(this)
|
||||
: Value(12345)
|
||||
, Self(this)
|
||||
{
|
||||
this->CheckState();
|
||||
++g_NonTrivialCount;
|
||||
}
|
||||
|
||||
NonTrivial(const NonTrivial& src)
|
||||
: Self(this)
|
||||
: Value(src.Value)
|
||||
{
|
||||
this->CheckState();
|
||||
src.CheckState();
|
||||
this->Self = this;
|
||||
this->CheckState();
|
||||
++g_NonTrivialCount;
|
||||
}
|
||||
|
||||
@ -234,65 +236,66 @@ void TestTriviallyCopyable()
|
||||
{
|
||||
#ifdef VTKM_USE_STD_IS_TRIVIAL
|
||||
// Make sure base types are behaving as expected
|
||||
VTKM_STATIC_ASSERT(std::is_trivially_constructible<float>::value);
|
||||
VTKM_STATIC_ASSERT(std::is_trivially_copyable<float>::value);
|
||||
VTKM_STATIC_ASSERT(std::is_trivial<float>::value);
|
||||
VTKM_STATIC_ASSERT(std::is_trivially_constructible<int>::value);
|
||||
VTKM_STATIC_ASSERT(std::is_trivially_copyable<int>::value);
|
||||
VTKM_STATIC_ASSERT(std::is_trivial<int>::value);
|
||||
VTKM_STATIC_ASSERT(!std::is_trivially_constructible<NonTrivial>::value);
|
||||
VTKM_STATIC_ASSERT(!std::is_trivially_copyable<NonTrivial>::value);
|
||||
VTKM_STATIC_ASSERT(!std::is_trivial<NonTrivial>::value);
|
||||
VTKM_STATIC_ASSERT(!std::is_trivially_constructible<TrivialCopy>::value);
|
||||
VTKM_STATIC_ASSERT(std::is_trivially_copyable<TrivialCopy>::value);
|
||||
VTKM_STATIC_ASSERT(!std::is_trivial<TrivialCopy>::value);
|
||||
VTKM_STATIC_ASSERT(vtkmstd::is_trivially_constructible<float>::value);
|
||||
VTKM_STATIC_ASSERT(vtkmstd::is_trivially_copyable<float>::value);
|
||||
VTKM_STATIC_ASSERT(vtkmstd::is_trivial<float>::value);
|
||||
VTKM_STATIC_ASSERT(vtkmstd::is_trivially_constructible<int>::value);
|
||||
VTKM_STATIC_ASSERT(vtkmstd::is_trivially_copyable<int>::value);
|
||||
VTKM_STATIC_ASSERT(vtkmstd::is_trivial<int>::value);
|
||||
VTKM_STATIC_ASSERT(!vtkmstd::is_trivially_constructible<NonTrivial>::value);
|
||||
VTKM_STATIC_ASSERT(!vtkmstd::is_trivially_copyable<NonTrivial>::value);
|
||||
VTKM_STATIC_ASSERT(!vtkmstd::is_trivial<NonTrivial>::value);
|
||||
VTKM_STATIC_ASSERT(!vtkmstd::is_trivially_constructible<TrivialCopy>::value);
|
||||
VTKM_STATIC_ASSERT(vtkmstd::is_trivially_copyable<TrivialCopy>::value);
|
||||
VTKM_STATIC_ASSERT(!vtkmstd::is_trivial<TrivialCopy>::value);
|
||||
|
||||
// A variant of trivially constructable things should be trivially constructable
|
||||
VTKM_STATIC_ASSERT((vtkm::exec::internal::detail::AllTriviallyConstructible<float, int>::value));
|
||||
VTKM_STATIC_ASSERT((vtkmstd::is_trivially_constructible<
|
||||
vtkm::exec::internal::detail::VariantUnion<float, int>>::value));
|
||||
VTKM_STATIC_ASSERT(
|
||||
(std::is_trivially_constructible<vtkm::exec::internal::Variant<float, int>>::value));
|
||||
(vtkmstd::is_trivially_constructible<vtkm::exec::internal::Variant<float, int>>::value));
|
||||
|
||||
// A variant of trivially copyable things should be trivially copyable
|
||||
VTKM_STATIC_ASSERT(
|
||||
(vtkm::exec::internal::detail::AllTriviallyCopyable<float, int, TrivialCopy>::value));
|
||||
VTKM_STATIC_ASSERT(
|
||||
(std::is_trivially_copyable<vtkm::exec::internal::Variant<float, int, TrivialCopy>>::value));
|
||||
VTKM_STATIC_ASSERT((vtkmstd::is_trivially_copyable<
|
||||
vtkm::exec::internal::detail::VariantUnion<float, int, TrivialCopy>>::value));
|
||||
VTKM_STATIC_ASSERT((
|
||||
vtkmstd::is_trivially_copyable<vtkm::exec::internal::Variant<float, int, TrivialCopy>>::value));
|
||||
|
||||
// A variant of any non-trivially constructable things is not trivially copyable
|
||||
VTKM_STATIC_ASSERT(
|
||||
(!vtkm::exec::internal::detail::AllTriviallyConstructible<NonTrivial, float, int>::value));
|
||||
VTKM_STATIC_ASSERT(
|
||||
(!vtkm::exec::internal::detail::AllTriviallyConstructible<float, NonTrivial, int>::value));
|
||||
VTKM_STATIC_ASSERT(
|
||||
(!vtkm::exec::internal::detail::AllTriviallyConstructible<float, int, NonTrivial>::value));
|
||||
VTKM_STATIC_ASSERT((!std::is_trivially_constructible<
|
||||
VTKM_STATIC_ASSERT((!vtkmstd::is_trivially_constructible<
|
||||
vtkm::exec::internal::detail::VariantUnion<NonTrivial, float, int>>::value));
|
||||
VTKM_STATIC_ASSERT((!vtkmstd::is_trivially_constructible<
|
||||
vtkm::exec::internal::detail::VariantUnion<float, NonTrivial, int>>::value));
|
||||
VTKM_STATIC_ASSERT((!vtkmstd::is_trivially_constructible<
|
||||
vtkm::exec::internal::detail::VariantUnion<float, int, NonTrivial>>::value));
|
||||
VTKM_STATIC_ASSERT((!vtkmstd::is_trivially_constructible<
|
||||
vtkm::exec::internal::Variant<NonTrivial, float, int>>::value));
|
||||
VTKM_STATIC_ASSERT((!std::is_trivially_constructible<
|
||||
VTKM_STATIC_ASSERT((!vtkmstd::is_trivially_constructible<
|
||||
vtkm::exec::internal::Variant<float, NonTrivial, int>>::value));
|
||||
VTKM_STATIC_ASSERT((!std::is_trivially_constructible<
|
||||
VTKM_STATIC_ASSERT((!vtkmstd::is_trivially_constructible<
|
||||
vtkm::exec::internal::Variant<float, int, NonTrivial>>::value));
|
||||
|
||||
// A variant of any non-trivially copyable things is not trivially copyable
|
||||
VTKM_STATIC_ASSERT(
|
||||
(!vtkm::exec::internal::detail::AllTriviallyCopyable<NonTrivial, float, int>::value));
|
||||
VTKM_STATIC_ASSERT(
|
||||
(!vtkm::exec::internal::detail::AllTriviallyCopyable<float, NonTrivial, int>::value));
|
||||
VTKM_STATIC_ASSERT(
|
||||
(!vtkm::exec::internal::detail::AllTriviallyCopyable<float, int, NonTrivial>::value));
|
||||
VTKM_STATIC_ASSERT(
|
||||
(!std::is_trivially_copyable<vtkm::exec::internal::Variant<NonTrivial, float, int>>::value));
|
||||
VTKM_STATIC_ASSERT(
|
||||
(!std::is_trivially_copyable<vtkm::exec::internal::Variant<float, NonTrivial, int>>::value));
|
||||
VTKM_STATIC_ASSERT(
|
||||
(!std::is_trivially_copyable<vtkm::exec::internal::Variant<float, int, NonTrivial>>::value));
|
||||
VTKM_STATIC_ASSERT((!vtkmstd::is_trivially_copyable<
|
||||
vtkm::exec::internal::detail::VariantUnion<NonTrivial, float, int>>::value));
|
||||
VTKM_STATIC_ASSERT((!vtkmstd::is_trivially_copyable<
|
||||
vtkm::exec::internal::detail::VariantUnion<float, NonTrivial, int>>::value));
|
||||
VTKM_STATIC_ASSERT((!vtkmstd::is_trivially_copyable<
|
||||
vtkm::exec::internal::detail::VariantUnion<float, int, NonTrivial>>::value));
|
||||
VTKM_STATIC_ASSERT((
|
||||
!vtkmstd::is_trivially_copyable<vtkm::exec::internal::Variant<NonTrivial, float, int>>::value));
|
||||
VTKM_STATIC_ASSERT((
|
||||
!vtkmstd::is_trivially_copyable<vtkm::exec::internal::Variant<float, NonTrivial, int>>::value));
|
||||
VTKM_STATIC_ASSERT((
|
||||
!vtkmstd::is_trivially_copyable<vtkm::exec::internal::Variant<float, int, NonTrivial>>::value));
|
||||
|
||||
// A variant of trivial things should be trivial
|
||||
VTKM_STATIC_ASSERT((std::is_trivial<vtkm::exec::internal::Variant<float, int>>::value));
|
||||
VTKM_STATIC_ASSERT((vtkmstd::is_trivial<vtkm::exec::internal::Variant<float, int>>::value));
|
||||
VTKM_STATIC_ASSERT(
|
||||
(!std::is_trivial<vtkm::exec::internal::Variant<float, int, TrivialCopy>>::value));
|
||||
(!vtkmstd::is_trivial<vtkm::exec::internal::Variant<float, int, TrivialCopy>>::value));
|
||||
VTKM_STATIC_ASSERT(
|
||||
(!std::is_trivial<vtkm::exec::internal::Variant<float, int, NonTrivial>>::value));
|
||||
#endif // !VTKM_USING_GLIBCXX_4
|
||||
(!vtkmstd::is_trivial<vtkm::exec::internal::Variant<float, int, NonTrivial>>::value));
|
||||
#endif // VTKM_USE_STD_IS_TRIVIAL
|
||||
}
|
||||
|
||||
struct TestFunctor
|
||||
@ -434,6 +437,7 @@ struct CountConstructDestruct
|
||||
++(*this->Count);
|
||||
}
|
||||
~CountConstructDestruct() { --(*this->Count); }
|
||||
CountConstructDestruct& operator=(const CountConstructDestruct&) = delete;
|
||||
};
|
||||
|
||||
void TestCopyDestroy()
|
||||
@ -443,11 +447,11 @@ void TestCopyDestroy()
|
||||
using VariantType = vtkm::exec::internal::Variant<TypePlaceholder<0>,
|
||||
TypePlaceholder<1>,
|
||||
CountConstructDestruct,
|
||||
TypePlaceholder<2>,
|
||||
TypePlaceholder<3>>;
|
||||
#ifndef VTKM_USING_GLIBCXX_4
|
||||
VTKM_STATIC_ASSERT(!std::is_trivially_copyable<VariantType>::value);
|
||||
#endif // !VTKM_USING_GLIBCXX_4
|
||||
TypePlaceholder<3>,
|
||||
TypePlaceholder<4>>;
|
||||
#ifdef VTKM_USE_STD_IS_TRIVIAL
|
||||
VTKM_STATIC_ASSERT(!vtkmstd::is_trivially_copyable<VariantType>::value);
|
||||
#endif // VTKM_USE_STD_IS_TRIVIAL
|
||||
vtkm::Id count = 0;
|
||||
|
||||
VariantType variant1 = CountConstructDestruct(&count);
|
||||
@ -545,6 +549,19 @@ void TestConstructDestruct()
|
||||
VTKM_TEST_ASSERT(g_NonTrivialCount == 0);
|
||||
}
|
||||
|
||||
void TestCopySelf()
|
||||
{
|
||||
std::cout << "Make sure copying a Variant to itself works" << std::endl;
|
||||
|
||||
using VariantType =
|
||||
vtkm::exec::internal::Variant<TypePlaceholder<0>, NonTrivial, TypePlaceholder<2>>;
|
||||
|
||||
VariantType variant{ NonTrivial{} };
|
||||
VariantType& variantRef = variant;
|
||||
variant = variantRef;
|
||||
variant = variant.Get<NonTrivial>();
|
||||
}
|
||||
|
||||
void RunTest()
|
||||
{
|
||||
TestSize();
|
||||
@ -555,6 +572,7 @@ void RunTest()
|
||||
TestCopyDestroy();
|
||||
TestEmplace();
|
||||
TestConstructDestruct();
|
||||
TestCopySelf();
|
||||
}
|
||||
|
||||
} // namespace test_variant
|
||||
|
@ -20,8 +20,7 @@
|
||||
#include <vtkm/Deprecated.h>
|
||||
#include <vtkm/List.h>
|
||||
|
||||
#include <vtkmstd/aligned_union.h>
|
||||
#include <vtkmstd/is_trivial.h>
|
||||
#include <vtkm/internal/Assume.h>
|
||||
|
||||
namespace vtkm
|
||||
{
|
||||
@ -37,12 +36,67 @@ class Variant;
|
||||
namespace detail
|
||||
{
|
||||
|
||||
// --------------------------------------------------------------------------------
|
||||
// Helper classes for Variant
|
||||
|
||||
template <typename UnionType>
|
||||
struct VariantUnionToListImpl;
|
||||
template <typename... Ts>
|
||||
struct VariantUnionToListImpl<detail::VariantUnionTD<Ts...>>
|
||||
{
|
||||
using type = vtkm::List<Ts...>;
|
||||
};
|
||||
template <typename... Ts>
|
||||
struct VariantUnionToListImpl<detail::VariantUnionNTD<Ts...>>
|
||||
{
|
||||
using type = vtkm::List<Ts...>;
|
||||
};
|
||||
|
||||
template <typename UnionType>
|
||||
using VariantUnionToList =
|
||||
typename VariantUnionToListImpl<typename std::decay<UnionType>::type>::type;
|
||||
|
||||
struct VariantCopyConstructFunctor
|
||||
{
|
||||
template <typename T, typename UnionType>
|
||||
VTK_M_DEVICE void operator()(const T& src, UnionType& destUnion) const noexcept
|
||||
{
|
||||
constexpr vtkm::IdComponent Index = vtkm::ListIndexOf<VariantUnionToList<UnionType>, T>::value;
|
||||
// If we are using this functor, we can assume the union does not hold a valid type.
|
||||
new (&VariantUnionGet<Index>(destUnion)) T(src);
|
||||
}
|
||||
};
|
||||
|
||||
struct VariantCopyFunctor
|
||||
{
|
||||
template <typename T>
|
||||
VTK_M_DEVICE void operator()(const T& src, void* destPointer) const noexcept
|
||||
template <typename T, typename UnionType>
|
||||
VTK_M_DEVICE void operator()(const T& src, UnionType& destUnion) const noexcept
|
||||
{
|
||||
new (destPointer) T(src);
|
||||
constexpr vtkm::IdComponent Index = vtkm::ListIndexOf<VariantUnionToList<UnionType>, T>::value;
|
||||
// If we are using this functor, we can assume the union holds type T.
|
||||
this->DoCopy(
|
||||
src, VariantUnionGet<Index>(destUnion), typename std::is_copy_assignable<T>::type{});
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
VTK_M_DEVICE void DoCopy(const T& src, T& dest, std::true_type) const noexcept
|
||||
{
|
||||
dest = src;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
VTK_M_DEVICE void DoCopy(const T& src, T& dest, std::false_type) const noexcept
|
||||
{
|
||||
if (&src != &dest)
|
||||
{
|
||||
// Do not have an assignment operator, so destroy the old object and create a new one.
|
||||
dest.~T();
|
||||
new (&dest) T(src);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Objects are already the same.
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@ -68,56 +122,6 @@ struct VariantCheckType
|
||||
VTKM_STATIC_ASSERT_MSG(!std::is_pointer<T>::value, "Pointers are not allowed in VTK-m Variant.");
|
||||
};
|
||||
|
||||
template <typename... Ts>
|
||||
struct AllTriviallyCopyable;
|
||||
|
||||
template <>
|
||||
struct AllTriviallyCopyable<> : std::true_type
|
||||
{
|
||||
};
|
||||
|
||||
template <typename T0>
|
||||
struct AllTriviallyCopyable<T0>
|
||||
: std::integral_constant<bool, (vtkmstd::is_trivially_copyable<T0>::value)>
|
||||
{
|
||||
};
|
||||
|
||||
template <typename T0, typename T1>
|
||||
struct AllTriviallyCopyable<T0, T1>
|
||||
: std::integral_constant<bool,
|
||||
(vtkmstd::is_trivially_copyable<T0>::value &&
|
||||
vtkmstd::is_trivially_copyable<T1>::value)>
|
||||
{
|
||||
};
|
||||
|
||||
template <typename T0, typename T1, typename T2>
|
||||
struct AllTriviallyCopyable<T0, T1, T2>
|
||||
: std::integral_constant<bool,
|
||||
(vtkmstd::is_trivially_copyable<T0>::value &&
|
||||
vtkmstd::is_trivially_copyable<T1>::value &&
|
||||
vtkmstd::is_trivially_copyable<T2>::value)>
|
||||
{
|
||||
};
|
||||
|
||||
template <typename T0, typename T1, typename T2, typename T3>
|
||||
struct AllTriviallyCopyable<T0, T1, T2, T3>
|
||||
: std::integral_constant<
|
||||
bool,
|
||||
(vtkmstd::is_trivially_copyable<T0>::value && vtkmstd::is_trivially_copyable<T1>::value &&
|
||||
vtkmstd::is_trivially_copyable<T2>::value && vtkmstd::is_trivially_copyable<T3>::value)>
|
||||
{
|
||||
};
|
||||
|
||||
template <typename T0, typename T1, typename T2, typename T3, typename T4, typename... Ts>
|
||||
struct AllTriviallyCopyable<T0, T1, T2, T3, T4, Ts...>
|
||||
: std::integral_constant<
|
||||
bool,
|
||||
(vtkmstd::is_trivially_copyable<T0>::value && vtkmstd::is_trivially_copyable<T1>::value &&
|
||||
vtkmstd::is_trivially_copyable<T2>::value && vtkmstd::is_trivially_copyable<T3>::value &&
|
||||
vtkmstd::is_trivially_copyable<T4>::value && AllTriviallyCopyable<Ts...>::value)>
|
||||
{
|
||||
};
|
||||
|
||||
template <typename VariantType>
|
||||
struct VariantTriviallyCopyable;
|
||||
|
||||
@ -127,59 +131,6 @@ struct VariantTriviallyCopyable<vtkm::VTK_M_NAMESPACE::internal::Variant<Ts...>>
|
||||
{
|
||||
};
|
||||
|
||||
template <typename... Ts>
|
||||
struct AllTriviallyConstructible;
|
||||
|
||||
template <>
|
||||
struct AllTriviallyConstructible<> : std::true_type
|
||||
{
|
||||
};
|
||||
|
||||
template <typename T0>
|
||||
struct AllTriviallyConstructible<T0>
|
||||
: std::integral_constant<bool, (vtkmstd::is_trivially_constructible<T0>::value)>
|
||||
{
|
||||
};
|
||||
|
||||
template <typename T0, typename T1>
|
||||
struct AllTriviallyConstructible<T0, T1>
|
||||
: std::integral_constant<bool,
|
||||
(vtkmstd::is_trivially_constructible<T0>::value &&
|
||||
vtkmstd::is_trivially_constructible<T1>::value)>
|
||||
{
|
||||
};
|
||||
|
||||
template <typename T0, typename T1, typename T2>
|
||||
struct AllTriviallyConstructible<T0, T1, T2>
|
||||
: std::integral_constant<bool,
|
||||
(vtkmstd::is_trivially_constructible<T0>::value &&
|
||||
vtkmstd::is_trivially_constructible<T1>::value &&
|
||||
vtkmstd::is_trivially_constructible<T2>::value)>
|
||||
{
|
||||
};
|
||||
|
||||
template <typename T0, typename T1, typename T2, typename T3>
|
||||
struct AllTriviallyConstructible<T0, T1, T2, T3>
|
||||
: std::integral_constant<bool,
|
||||
(vtkmstd::is_trivially_constructible<T0>::value &&
|
||||
vtkmstd::is_trivially_constructible<T1>::value &&
|
||||
vtkmstd::is_trivially_constructible<T2>::value &&
|
||||
vtkmstd::is_trivially_constructible<T3>::value)>
|
||||
{
|
||||
};
|
||||
|
||||
template <typename T0, typename T1, typename T2, typename T3, typename T4, typename... Ts>
|
||||
struct AllTriviallyConstructible<T0, T1, T2, T3, T4, Ts...>
|
||||
: std::integral_constant<bool,
|
||||
(vtkmstd::is_trivially_constructible<T0>::value &&
|
||||
vtkmstd::is_trivially_constructible<T1>::value &&
|
||||
vtkmstd::is_trivially_constructible<T2>::value &&
|
||||
vtkmstd::is_trivially_constructible<T3>::value &&
|
||||
vtkmstd::is_trivially_constructible<T4>::value &&
|
||||
AllTriviallyConstructible<Ts...>::value)>
|
||||
{
|
||||
};
|
||||
|
||||
template <typename VariantType>
|
||||
struct VariantTriviallyConstructible;
|
||||
|
||||
@ -189,22 +140,24 @@ struct VariantTriviallyConstructible<vtkm::VTK_M_NAMESPACE::internal::Variant<Ts
|
||||
{
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------------
|
||||
// Variant superclass that defines its storage
|
||||
template <typename... Ts>
|
||||
struct VariantStorageImpl
|
||||
{
|
||||
typename vtkmstd::aligned_union<0, Ts...>::type Storage;
|
||||
|
||||
VariantUnion<Ts...> Storage;
|
||||
vtkm::IdComponent Index;
|
||||
|
||||
VariantStorageImpl() = default;
|
||||
|
||||
VTK_M_DEVICE VariantStorageImpl(vtkm::internal::NullType dummy)
|
||||
: Storage({ dummy })
|
||||
{
|
||||
}
|
||||
|
||||
template <vtkm::IdComponent Index>
|
||||
using TypeAt = typename vtkm::ListAt<vtkm::List<Ts...>, Index>;
|
||||
|
||||
VTK_M_DEVICE void* GetPointer() { return reinterpret_cast<void*>(&this->Storage); }
|
||||
VTK_M_DEVICE const void* GetPointer() const
|
||||
{
|
||||
return reinterpret_cast<const void*>(&this->Storage);
|
||||
}
|
||||
|
||||
VTK_M_DEVICE vtkm::IdComponent GetIndex() const noexcept { return this->Index; }
|
||||
VTK_M_DEVICE bool IsValid() const noexcept
|
||||
{
|
||||
@ -226,12 +179,8 @@ struct VariantStorageImpl
|
||||
-> decltype(f(std::declval<const TypeAt<0>&>(), args...))
|
||||
{
|
||||
VTKM_ASSERT(this->IsValid());
|
||||
return detail::VariantCastAndCallImpl<decltype(f(std::declval<const TypeAt<0>&>(), args...))>(
|
||||
brigand::list<Ts...>{},
|
||||
this->GetIndex(),
|
||||
std::forward<Functor>(f),
|
||||
this->GetPointer(),
|
||||
std::forward<Args>(args)...);
|
||||
return detail::VariantCastAndCallImpl(
|
||||
this->GetIndex(), std::forward<Functor>(f), this->Storage, std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template <typename Functor, typename... Args>
|
||||
@ -240,15 +189,14 @@ struct VariantStorageImpl
|
||||
-> decltype(f(std::declval<TypeAt<0>&>(), args...))
|
||||
{
|
||||
VTKM_ASSERT(this->IsValid());
|
||||
return detail::VariantCastAndCallImpl<decltype(f(std::declval<TypeAt<0>&>(), args...))>(
|
||||
brigand::list<Ts...>{},
|
||||
this->GetIndex(),
|
||||
std::forward<Functor>(f),
|
||||
this->GetPointer(),
|
||||
std::forward<Args>(args)...);
|
||||
return detail::VariantCastAndCallImpl(
|
||||
this->GetIndex(), std::forward<Functor>(f), this->Storage, std::forward<Args>(args)...);
|
||||
}
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------------
|
||||
// Variant superclass that helps preserve trivially copyable and trivially constructable
|
||||
// properties where possible.
|
||||
template <typename VariantType,
|
||||
typename TriviallyConstructible =
|
||||
typename VariantTriviallyConstructible<VariantType>::type,
|
||||
@ -277,7 +225,11 @@ struct VariantConstructorImpl<vtkm::VTK_M_NAMESPACE::internal::Variant<Ts...>,
|
||||
std::false_type,
|
||||
std::true_type> : VariantStorageImpl<Ts...>
|
||||
{
|
||||
VTK_M_DEVICE VariantConstructorImpl() { this->Index = -1; }
|
||||
VTK_M_DEVICE VariantConstructorImpl()
|
||||
: VariantStorageImpl<Ts...>(vtkm::internal::NullType{})
|
||||
{
|
||||
this->Index = -1;
|
||||
}
|
||||
|
||||
// Any trivially copyable class is trivially destructable.
|
||||
~VariantConstructorImpl() = default;
|
||||
@ -294,20 +246,32 @@ struct VariantConstructorImpl<vtkm::VTK_M_NAMESPACE::internal::Variant<Ts...>,
|
||||
construct_type,
|
||||
std::false_type> : VariantStorageImpl<Ts...>
|
||||
{
|
||||
VTK_M_DEVICE VariantConstructorImpl() { this->Index = -1; }
|
||||
VTK_M_DEVICE VariantConstructorImpl()
|
||||
: VariantStorageImpl<Ts...>(vtkm::internal::NullType{})
|
||||
{
|
||||
this->Index = -1;
|
||||
}
|
||||
VTK_M_DEVICE ~VariantConstructorImpl() { this->Reset(); }
|
||||
|
||||
VTK_M_DEVICE VariantConstructorImpl(const VariantConstructorImpl& src) noexcept
|
||||
: VariantStorageImpl<Ts...>(vtkm::internal::NullType{})
|
||||
{
|
||||
src.CastAndCall(VariantCopyFunctor{}, this->GetPointer());
|
||||
src.CastAndCall(VariantCopyConstructFunctor{}, this->Storage);
|
||||
this->Index = src.Index;
|
||||
}
|
||||
|
||||
VTK_M_DEVICE VariantConstructorImpl& operator=(const VariantConstructorImpl& src) noexcept
|
||||
{
|
||||
this->Reset();
|
||||
src.CastAndCall(detail::VariantCopyFunctor{}, this->GetPointer());
|
||||
this->Index = src.Index;
|
||||
if (this->GetIndex() == src.GetIndex())
|
||||
{
|
||||
src.CastAndCall(detail::VariantCopyFunctor{}, this->Storage);
|
||||
}
|
||||
else
|
||||
{
|
||||
this->Reset();
|
||||
src.CastAndCall(detail::VariantCopyConstructFunctor{}, this->Storage);
|
||||
this->Index = src.Index;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
@ -323,20 +287,6 @@ class Variant : detail::VariantConstructorImpl<Variant<Ts...>>
|
||||
using CheckTypes = vtkm::List<detail::VariantCheckType<Ts>...>;
|
||||
|
||||
public:
|
||||
/// Returns the index of the type of object this variant is storing. If no object is currently
|
||||
/// stored (i.e. the `Variant` is invalid), an invalid is returned.
|
||||
///
|
||||
VTK_M_DEVICE vtkm::IdComponent GetIndex() const noexcept { return this->Superclass::GetIndex(); }
|
||||
|
||||
/// Returns true if this `Variant` is storing an object from one of the types in the template
|
||||
/// list, false otherwise.
|
||||
///
|
||||
/// Note that if this `Variant` was not initialized with an object, the result of `IsValid`
|
||||
/// is undefined. The `Variant` could report itself as validly containing an object that
|
||||
/// is trivially constructed.
|
||||
///
|
||||
VTK_M_DEVICE bool IsValid() const noexcept { return this->Superclass::IsValid(); }
|
||||
|
||||
/// Type that converts to a std::integral_constant containing the index of the given type (or
|
||||
/// -1 if that type is not in the list).
|
||||
template <typename T>
|
||||
@ -353,12 +303,29 @@ public:
|
||||
/// Type that converts to the type at the given index.
|
||||
///
|
||||
template <vtkm::IdComponent Index>
|
||||
using TypeAt = typename Superclass::template TypeAt<Index>;
|
||||
using TypeAt = typename vtkm::ListAt<vtkm::List<Ts...>, Index>;
|
||||
|
||||
/// The number of types representable by this Variant.
|
||||
///
|
||||
static constexpr vtkm::IdComponent NumberOfTypes = vtkm::IdComponent{ sizeof...(Ts) };
|
||||
|
||||
/// Returns the index of the type of object this variant is storing. If no object is currently
|
||||
/// stored (i.e. the `Variant` is invalid), an invalid is returned.
|
||||
///
|
||||
VTK_M_DEVICE vtkm::IdComponent GetIndex() const noexcept { return this->Index; }
|
||||
|
||||
/// Returns true if this `Variant` is storing an object from one of the types in the template
|
||||
/// list, false otherwise.
|
||||
///
|
||||
/// Note that if this `Variant` was not initialized with an object, the result of `IsValid`
|
||||
/// is undefined. The `Variant` could report itself as validly containing an object that
|
||||
/// is trivially constructed.
|
||||
///
|
||||
VTK_M_DEVICE bool IsValid() const noexcept
|
||||
{
|
||||
return (this->Index >= 0) && (this->Index < NumberOfTypes);
|
||||
}
|
||||
|
||||
Variant() = default;
|
||||
~Variant() = default;
|
||||
Variant(const Variant&) = default;
|
||||
@ -373,19 +340,22 @@ public:
|
||||
// Might be a way to use an enable_if to enforce a proper type.
|
||||
VTKM_STATIC_ASSERT_MSG(index >= 0, "Attempting to put invalid type into a Variant");
|
||||
|
||||
new (this->GetPointer()) T(src);
|
||||
this->Index = index;
|
||||
new (&this->Get<index>()) T(src);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
VTK_M_DEVICE Variant(const T&& src) noexcept
|
||||
VTK_M_DEVICE Variant& operator=(const T& src)
|
||||
{
|
||||
constexpr vtkm::IdComponent index = IndexOf<T>::value;
|
||||
// Might be a way to use an enable_if to enforce a proper type.
|
||||
VTKM_STATIC_ASSERT_MSG(index >= 0, "Attempting to put invalid type into a Variant");
|
||||
|
||||
new (this->GetPointer()) T(std::move(src));
|
||||
this->Index = index;
|
||||
if (this->GetIndex() == this->GetIndexOf<T>())
|
||||
{
|
||||
this->Get<T>() = src;
|
||||
}
|
||||
else
|
||||
{
|
||||
this->Emplace<T>(src);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename T, typename... Args>
|
||||
@ -425,18 +395,16 @@ private:
|
||||
VTK_M_DEVICE T& EmplaceImpl(Args&&... args)
|
||||
{
|
||||
this->Reset();
|
||||
T* value = new (this->GetPointer()) T{ args... };
|
||||
this->Index = I;
|
||||
return *value;
|
||||
return *(new (&this->Get<I>()) T{ args... });
|
||||
}
|
||||
|
||||
template <typename T, vtkm::IdComponent I, typename U, typename... Args>
|
||||
VTK_M_DEVICE T& EmplaceImpl(std::initializer_list<U> il, Args&&... args)
|
||||
{
|
||||
this->Reset();
|
||||
T* value = new (this->GetPointer()) T(il, args...);
|
||||
this->Index = I;
|
||||
return *value;
|
||||
return *(new (&this->Get<I>()) T(il, args...));
|
||||
}
|
||||
|
||||
public:
|
||||
@ -448,14 +416,14 @@ public:
|
||||
VTK_M_DEVICE TypeAt<I>& Get() noexcept
|
||||
{
|
||||
VTKM_ASSERT(I == this->GetIndex());
|
||||
return *reinterpret_cast<TypeAt<I>*>(this->GetPointer());
|
||||
return detail::VariantUnionGet<I>(this->Storage);
|
||||
}
|
||||
|
||||
template <vtkm::IdComponent I>
|
||||
VTK_M_DEVICE const TypeAt<I>& Get() const noexcept
|
||||
{
|
||||
VTKM_ASSERT(I == this->GetIndex());
|
||||
return *reinterpret_cast<const TypeAt<I>*>(this->GetPointer());
|
||||
return detail::VariantUnionGet<I>(this->Storage);
|
||||
}
|
||||
//@}
|
||||
|
||||
@ -467,14 +435,14 @@ public:
|
||||
VTK_M_DEVICE T& Get() noexcept
|
||||
{
|
||||
VTKM_ASSERT(this->GetIndexOf<T>() == this->GetIndex());
|
||||
return *reinterpret_cast<T*>(this->GetPointer());
|
||||
return detail::VariantUnionGet<IndexOf<T>::value>(this->Storage);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
VTK_M_DEVICE const T& Get() const noexcept
|
||||
{
|
||||
VTKM_ASSERT(this->GetIndexOf<T>() == this->GetIndex());
|
||||
return *reinterpret_cast<const T*>(this->GetPointer());
|
||||
return detail::VariantUnionGet<IndexOf<T>::value>(this->Storage);
|
||||
}
|
||||
//@}
|
||||
|
||||
@ -490,7 +458,9 @@ public:
|
||||
noexcept(noexcept(f(std::declval<const TypeAt<0>&>(), args...)))
|
||||
-> decltype(f(std::declval<const TypeAt<0>&>(), args...))
|
||||
{
|
||||
return this->Superclass::CastAndCall(std::forward<Functor>(f), std::forward<Args>(args)...);
|
||||
VTKM_ASSERT(this->IsValid());
|
||||
return detail::VariantCastAndCallImpl(
|
||||
this->GetIndex(), std::forward<Functor>(f), this->Storage, std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template <typename Functor, typename... Args>
|
||||
@ -498,13 +468,22 @@ public:
|
||||
noexcept(f(std::declval<const TypeAt<0>&>(), args...)))
|
||||
-> decltype(f(std::declval<TypeAt<0>&>(), args...))
|
||||
{
|
||||
return this->Superclass::CastAndCall(std::forward<Functor>(f), std::forward<Args>(args)...);
|
||||
VTKM_ASSERT(this->IsValid());
|
||||
return detail::VariantCastAndCallImpl(
|
||||
this->GetIndex(), std::forward<Functor>(f), this->Storage, std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
/// Destroys any object the Variant is holding and sets the Variant to an invalid state. This
|
||||
/// method is not thread safe.
|
||||
///
|
||||
VTK_M_DEVICE void Reset() noexcept { this->Superclass::Reset(); }
|
||||
VTK_M_DEVICE void Reset() noexcept
|
||||
{
|
||||
if (this->IsValid())
|
||||
{
|
||||
this->CastAndCall(detail::VariantDestroyFunctor{});
|
||||
this->Index = -1;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/// \brief Convert a ListTag to a Variant.
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -31,7 +31,9 @@ $# Ignore the following comment. It is meant for the generated file.
|
||||
|
||||
#include <vtkm/Types.h>
|
||||
|
||||
#include <vtkm/internal/brigand.hpp>
|
||||
#include <vtkm/internal/Assume.h>
|
||||
|
||||
#include <vtkmstd/is_trivial.h>
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
@ -46,9 +48,17 @@ def type_list(num_params):
|
||||
for param in range(1, num_params + 1):
|
||||
result += ', T%d' % param
|
||||
return result
|
||||
|
||||
def typename_list(num_params):
|
||||
if num_params < 0:
|
||||
return ''
|
||||
result = 'typename T0'
|
||||
for param in range(1, num_params + 1):
|
||||
result += ', typename T%d' % param
|
||||
return result
|
||||
)\
|
||||
$#
|
||||
$extend(type_list)\
|
||||
$extend(type_list, typename_list)\
|
||||
|
||||
namespace vtkm
|
||||
{
|
||||
@ -70,135 +80,315 @@ struct VariantDummyReturn<void>
|
||||
VTK_M_DEVICE static inline void F() noexcept {}
|
||||
};
|
||||
|
||||
template <typename ReturnType, typename Functor, typename... Args>
|
||||
VTK_M_DEVICE inline ReturnType VariantCastAndCallImpl(brigand::list<>,
|
||||
vtkm::IdComponent,
|
||||
Functor&&,
|
||||
const void*,
|
||||
Args&&...) noexcept
|
||||
// clang-format off
|
||||
|
||||
// --------------------------------------------------------------------------------
|
||||
// Helper classes to determine if all Variant types are trivial.
|
||||
template <typename T0 = vtkm::internal::NullType,
|
||||
$for(param_index in range(1, max_expanded))\
|
||||
typename T$(param_index) = vtkm::internal::NullType,
|
||||
$endfor\
|
||||
typename... Ts>
|
||||
struct AllTriviallyCopyable;
|
||||
|
||||
template <$typename_list(max_expanded - 1)>
|
||||
struct AllTriviallyCopyable<$type_list(max_expanded - 1)>
|
||||
: std::integral_constant<bool, (vtkmstd::is_trivially_copyable<T0>::value &&
|
||||
$for(param_index in range(1, max_expanded - 1))\
|
||||
vtkmstd::is_trivially_copyable<T$(param_index)>::value &&
|
||||
$endfor\
|
||||
vtkmstd::is_trivially_copyable<T$(max_expanded - 1)>::value)> { };
|
||||
|
||||
template <$typename_list(max_expanded), typename... Ts>
|
||||
struct AllTriviallyCopyable<$type_list(max_expanded), Ts...>
|
||||
: std::integral_constant<bool, (
|
||||
AllTriviallyCopyable<$type_list(max_expanded - 1)>::value &&
|
||||
AllTriviallyCopyable<T$(max_expanded), Ts...>::value)> { };
|
||||
|
||||
template <typename T0 = vtkm::internal::NullType,
|
||||
$for(param_index in range(1, max_expanded))\
|
||||
typename T$(param_index) = vtkm::internal::NullType,
|
||||
$endfor\
|
||||
typename... Ts>
|
||||
struct AllTriviallyConstructible;
|
||||
|
||||
template <$typename_list(max_expanded - 1)>
|
||||
struct AllTriviallyConstructible<$type_list(max_expanded - 1)>
|
||||
: std::integral_constant<bool, (vtkmstd::is_trivially_constructible<T0>::value &&
|
||||
$for(param_index in range(1, max_expanded - 1))\
|
||||
vtkmstd::is_trivially_constructible<T$(param_index)>::value &&
|
||||
$endfor\
|
||||
vtkmstd::is_trivially_constructible<T$(max_expanded - 1)>::value)> { };
|
||||
|
||||
template <$typename_list(max_expanded), typename... Ts>
|
||||
struct AllTriviallyConstructible<$type_list(max_expanded), Ts...>
|
||||
: std::integral_constant<bool, (
|
||||
AllTriviallyConstructible<$type_list(max_expanded - 1)>::value &&
|
||||
AllTriviallyConstructible<T$(max_expanded), Ts...>::value)> { };
|
||||
|
||||
template <typename T0 = vtkm::internal::NullType,
|
||||
$for(param_index in range(1, max_expanded))\
|
||||
typename T$(param_index) = vtkm::internal::NullType,
|
||||
$endfor\
|
||||
typename... Ts>
|
||||
struct AllTriviallyDestructible;
|
||||
|
||||
template <$typename_list(max_expanded - 1)>
|
||||
struct AllTriviallyDestructible<$type_list(max_expanded - 1)>
|
||||
: std::integral_constant<bool, (vtkmstd::is_trivially_destructible<T0>::value &&
|
||||
$for(param_index in range(1, max_expanded - 1))\
|
||||
vtkmstd::is_trivially_destructible<T$(param_index)>::value &&
|
||||
$endfor\
|
||||
vtkmstd::is_trivially_destructible<T$(max_expanded - 1)>::value)> { };
|
||||
|
||||
template <$typename_list(max_expanded), typename... Ts>
|
||||
struct AllTriviallyDestructible<$type_list(max_expanded), Ts...>
|
||||
: std::integral_constant<bool, (
|
||||
AllTriviallyDestructible<$type_list(max_expanded - 1)>::value &&
|
||||
AllTriviallyDestructible<T$(max_expanded), Ts...>::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 <typename T0 = vtkm::internal::NullType,
|
||||
$for(param_index in range(1, max_expanded))\
|
||||
typename T$(param_index) = vtkm::internal::NullType,
|
||||
$endfor\
|
||||
typename... Ts>
|
||||
union VariantUnionTD;
|
||||
|
||||
// NTD = non-trivially deconstructible
|
||||
template <typename T0 = vtkm::internal::NullType,
|
||||
$for(param_index in range(1, max_expanded))\
|
||||
typename T$(param_index) = vtkm::internal::NullType,
|
||||
$endfor\
|
||||
typename... Ts>
|
||||
union VariantUnionNTD;
|
||||
|
||||
template <$typename_list(max_expanded - 1)>
|
||||
union VariantUnionTD<$type_list(max_expanded - 1)>
|
||||
{
|
||||
// If we are here, it means we failed to find the appropriate type in a variant
|
||||
$for(param_index in range(max_expanded))\
|
||||
T$(param_index) V$(param_index);
|
||||
$endfor\
|
||||
vtkm::internal::NullType Remaining;
|
||||
|
||||
VTK_M_DEVICE VariantUnionTD(vtkm::internal::NullType) { }
|
||||
VariantUnionTD() = default;
|
||||
};
|
||||
|
||||
template <$typename_list(max_expanded - 1)>
|
||||
union VariantUnionNTD<$type_list(max_expanded - 1)>
|
||||
{
|
||||
$for(param_index in range(max_expanded))\
|
||||
T$(param_index) V$(param_index);
|
||||
$endfor\
|
||||
vtkm::internal::NullType Remaining;
|
||||
|
||||
VTK_M_DEVICE VariantUnionNTD(vtkm::internal::NullType) { }
|
||||
VariantUnionNTD() = default;
|
||||
VTK_M_DEVICE ~VariantUnionNTD() { }
|
||||
};
|
||||
|
||||
template <$typename_list(max_expanded), typename... Ts>
|
||||
union VariantUnionTD<$type_list(max_expanded), Ts...>
|
||||
{
|
||||
$for(param_index in range(max_expanded))\
|
||||
T$(param_index) V$(param_index);
|
||||
$endfor\
|
||||
VariantUnionTD<T$(max_expanded), Ts...> Remaining;
|
||||
|
||||
VTK_M_DEVICE VariantUnionTD(vtkm::internal::NullType) { }
|
||||
VariantUnionTD() = default;
|
||||
};
|
||||
|
||||
template <$typename_list(max_expanded), typename... Ts>
|
||||
union VariantUnionNTD<$type_list(max_expanded), Ts...>
|
||||
{
|
||||
$for(param_index in range(max_expanded))\
|
||||
T$(param_index) V$(param_index);
|
||||
$endfor\
|
||||
VariantUnionNTD<T$(max_expanded), Ts...> Remaining;
|
||||
|
||||
VTK_M_DEVICE VariantUnionNTD(vtkm::internal::NullType) { }
|
||||
VariantUnionNTD() = default;
|
||||
VTK_M_DEVICE ~VariantUnionNTD() { }
|
||||
};
|
||||
|
||||
template <bool TrivialConstructor, typename... Ts>
|
||||
struct VariantUnionFinder;
|
||||
|
||||
template <typename... Ts>
|
||||
struct VariantUnionFinder<true, Ts...>
|
||||
{
|
||||
using type = VariantUnionTD<Ts...>;
|
||||
};
|
||||
template <typename... Ts>
|
||||
struct VariantUnionFinder<false, Ts...>
|
||||
{
|
||||
using type = VariantUnionNTD<Ts...>;
|
||||
};
|
||||
|
||||
template <typename... Ts>
|
||||
using VariantUnion =
|
||||
typename VariantUnionFinder<AllTriviallyDestructible<Ts...>::value, Ts...>::type;
|
||||
|
||||
// --------------------------------------------------------------------------------
|
||||
// Methods to get values out of the variant union
|
||||
template <vtkm::IdComponent I, typename UnionType>
|
||||
struct VariantUnionGetImpl;
|
||||
|
||||
$for(param_index in range(max_expanded))\
|
||||
template <typename UnionType>
|
||||
struct VariantUnionGetImpl<$(param_index), UnionType>
|
||||
{
|
||||
using ReturnType = decltype(std::declval<UnionType>().V$(param_index));
|
||||
VTK_M_DEVICE static ReturnType& Get(UnionType& storage) noexcept
|
||||
{
|
||||
return storage.V$(param_index);
|
||||
}
|
||||
VTK_M_DEVICE static const ReturnType& Get(const UnionType& storage) noexcept
|
||||
{
|
||||
return storage.V$(param_index);
|
||||
}
|
||||
};
|
||||
|
||||
$endfor\
|
||||
|
||||
template <vtkm::IdComponent I, typename UnionType>
|
||||
struct VariantUnionGetImpl
|
||||
{
|
||||
VTKM_STATIC_ASSERT(I >= $(max_expanded));
|
||||
using RecursiveGet = VariantUnionGetImpl<I - $(max_expanded), decltype(std::declval<UnionType&>().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 <vtkm::IdComponent I, typename UnionType>
|
||||
VTK_M_DEVICE auto VariantUnionGet(UnionType& storage) noexcept
|
||||
-> decltype(VariantUnionGetImpl<I, typename std::decay<UnionType>::type>::Get(storage))&
|
||||
{
|
||||
return VariantUnionGetImpl<I, typename std::decay<UnionType>::type>::Get(storage);
|
||||
}
|
||||
|
||||
//clang-format on
|
||||
|
||||
// --------------------------------------------------------------------------------
|
||||
// Internal implementation of CastAndCall for Variant
|
||||
template <typename ReturnType,
|
||||
typename Functor,
|
||||
typename CastMember,
|
||||
typename... Args>
|
||||
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>(args)...);
|
||||
}
|
||||
|
||||
template <typename ReturnType,
|
||||
typename Functor,
|
||||
typename... Args>
|
||||
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<ReturnType>::F();
|
||||
}
|
||||
|
||||
// clang-format off
|
||||
// Terminating condition in recursive template
|
||||
template <typename ReturnType, typename Functor, typename... Args>
|
||||
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<ReturnType>::F();
|
||||
}
|
||||
|
||||
$for(num_params in range(0, max_expanded))\
|
||||
template <typename ReturnType,
|
||||
$for(param_index in range(0, num_params + 1))\
|
||||
typename T$(param_index),
|
||||
$endfor\
|
||||
typename Functor,
|
||||
typename... Args>
|
||||
VTK_M_DEVICE inline ReturnType VariantCastAndCallImpl(
|
||||
brigand::list<$type_list(num_params)>,
|
||||
template <typename ReturnType, typename Functor, typename UnionType, typename... Args>
|
||||
VTK_M_DEVICE inline ReturnType VariantCastAndCallImplR(
|
||||
std::false_type,
|
||||
vtkm::IdComponent index,
|
||||
Functor&& f,
|
||||
const void* storage,
|
||||
Args&&... args) noexcept(noexcept(f(std::declval<const T0&>(), args...)))
|
||||
UnionType& storage,
|
||||
Args&&... args) noexcept(noexcept(f(storage.V0, args...)))
|
||||
{
|
||||
switch (index)
|
||||
{
|
||||
$for(param_index in range(0, num_params + 1))\
|
||||
$for(param_index in range(max_expanded))\
|
||||
case $(param_index):
|
||||
return f(*reinterpret_cast<const T$(param_index)*>(storage), std::forward<Args>(args)...);
|
||||
return VariantCallFunctor<ReturnType>(
|
||||
typename std::is_same<decltype(storage.V$(param_index)), vtkm::internal::NullType>::type{},
|
||||
std::forward<Functor>(f),
|
||||
storage.V$(param_index),
|
||||
std::forward<Args>(args)...);
|
||||
$endfor\
|
||||
default:
|
||||
// If we are here, it means we failed to find the appropriate type in a variant
|
||||
VTKM_ASSERT(false && "Internal error, bad Variant state.");
|
||||
return VariantDummyReturn<ReturnType>::F();
|
||||
return VariantCastAndCallImplR<ReturnType>(
|
||||
typename std::is_same<decltype(storage.Remaining), vtkm::internal::NullType>::type{},
|
||||
index - $(max_expanded),
|
||||
std::forward<Functor>(f),
|
||||
storage.Remaining,
|
||||
std::forward<Args>(args)...);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename ReturnType,
|
||||
$for(param_index in range(0, num_params + 1))\
|
||||
typename T$(param_index),
|
||||
$endfor\
|
||||
typename Functor,
|
||||
typename... Args>
|
||||
VTK_M_DEVICE inline ReturnType VariantCastAndCallImpl(
|
||||
brigand::list<$type_list(num_params)>,
|
||||
template <typename Functor, typename UnionType, typename... Args>
|
||||
VTK_M_DEVICE inline auto VariantCastAndCallImpl(
|
||||
vtkm::IdComponent index,
|
||||
Functor&& f,
|
||||
void* storage,
|
||||
Args&&... args) noexcept(noexcept(f(std::declval<const T0&>(), args...)))
|
||||
UnionType& storage,
|
||||
Args&&... args) noexcept(noexcept(f(storage.V0, args...)))
|
||||
-> decltype(f(storage.V0, args...))
|
||||
{
|
||||
switch (index)
|
||||
{
|
||||
$for(param_index in range(0, num_params + 1))\
|
||||
case $(param_index):
|
||||
return f(*reinterpret_cast<T$(param_index)*>(storage), std::forward<Args>(args)...);
|
||||
$endfor\
|
||||
default:
|
||||
// If we are here, it means we failed to find the appropriate type in a variant
|
||||
VTKM_ASSERT(false && "Internal error, bad Variant state.");
|
||||
return VariantDummyReturn<ReturnType>::F();
|
||||
}
|
||||
}
|
||||
|
||||
$endfor\
|
||||
//clang-format on
|
||||
|
||||
// Recurse for cases where Variant has more than $(max_expanded) types
|
||||
template <typename ReturnType,
|
||||
$for(param_index in range(0, max_expanded + 1))\
|
||||
typename T$(param_index),
|
||||
$endfor\
|
||||
typename... RemainingT,
|
||||
typename Functor,
|
||||
typename... Args>
|
||||
VTK_M_DEVICE inline ReturnType VariantCastAndCallImpl(
|
||||
brigand::list<$type_list(max_expanded), RemainingT...>,
|
||||
vtkm::IdComponent index,
|
||||
Functor&& f,
|
||||
const void* storage,
|
||||
Args&&... args) noexcept(noexcept(f(std::declval<const T0&>(), args...)))
|
||||
{
|
||||
if (index < $(max_expanded))
|
||||
{
|
||||
return VariantCastAndCallImpl<ReturnType>(
|
||||
brigand::list<$type_list(max_expanded - 1)>{},
|
||||
index,
|
||||
f,
|
||||
storage,
|
||||
args...);
|
||||
}
|
||||
else
|
||||
{
|
||||
return VariantCastAndCallImpl<ReturnType>(
|
||||
brigand::list<T$(max_expanded), RemainingT...>{}, index - $(max_expanded), f, storage, args...);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename ReturnType,
|
||||
$for(param_index in range(0, max_expanded + 1))\
|
||||
typename T$(param_index),
|
||||
$endfor\
|
||||
typename... RemainingT,
|
||||
typename Functor,
|
||||
typename... Args>
|
||||
VTK_M_DEVICE inline ReturnType VariantCastAndCallImpl(
|
||||
brigand::list<$type_list(max_expanded), RemainingT...>,
|
||||
vtkm::IdComponent index,
|
||||
Functor&& f,
|
||||
void* storage,
|
||||
Args&&... args) noexcept(noexcept(f(std::declval<const T0&>(), args...)))
|
||||
{
|
||||
if (index < $(max_expanded))
|
||||
{
|
||||
return VariantCastAndCallImpl<ReturnType>(
|
||||
brigand::list<$type_list(max_expanded - 1)>{},
|
||||
index,
|
||||
f,
|
||||
storage,
|
||||
args...);
|
||||
}
|
||||
else
|
||||
{
|
||||
return VariantCastAndCallImpl<ReturnType>(
|
||||
brigand::list<T$(max_expanded), RemainingT...>{}, index - $(max_expanded), f, storage, args...);
|
||||
}
|
||||
return VariantCastAndCallImplR<decltype(f(storage.V0, args...))>(
|
||||
std::false_type{}, index, std::forward<Functor>(f), storage, std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user