2019-07-22 19:56:35 +00:00
|
|
|
//============================================================================
|
|
|
|
// 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.
|
|
|
|
//============================================================================
|
|
|
|
$# This file uses the pyexpander macro processing utility to build the
|
|
|
|
$# FunctionInterface facilities that use a variable number of arguments.
|
|
|
|
$# Information, documentation, and downloads for pyexpander can be found at:
|
|
|
|
$#
|
|
|
|
$# http://pyexpander.sourceforge.net/
|
|
|
|
$#
|
|
|
|
$# To build the source code, execute the following (after installing
|
|
|
|
$# pyexpander, of course):
|
|
|
|
$#
|
|
|
|
$# expander.py VariantDetail.h.in > VariantDetail.h
|
|
|
|
$#
|
|
|
|
$# Ignore the following comment. It is meant for the generated file.
|
|
|
|
// **** DO NOT EDIT THIS FILE!!! ****
|
|
|
|
// This file is automatically generated by VariantDetail.h.in
|
|
|
|
|
2020-10-06 21:57:04 +00:00
|
|
|
#if !defined(VTK_M_DEVICE) || !defined(VTK_M_NAMESPACE)
|
|
|
|
#error VarianImplDetail.h must be included from VariantImpl.h
|
2020-10-08 18:02:27 +00:00
|
|
|
// Some defines to make my IDE happy.
|
|
|
|
#define VTK_M_DEVICE
|
|
|
|
#define VTK_M_NAMESPACE tmp
|
2019-07-22 19:56:35 +00:00
|
|
|
#endif
|
|
|
|
|
|
|
|
#include <vtkm/Types.h>
|
|
|
|
|
2021-03-17 20:38:33 +00:00
|
|
|
#include <vtkm/internal/Assume.h>
|
|
|
|
|
|
|
|
#include <vtkmstd/is_trivial.h>
|
2019-07-22 19:56:35 +00:00
|
|
|
|
|
|
|
#include <type_traits>
|
|
|
|
|
|
|
|
$py(max_expanded=20)\
|
|
|
|
|
|
|
|
$# Python commands used in template expansion.
|
|
|
|
$py(
|
|
|
|
def type_list(num_params):
|
|
|
|
if num_params < 0:
|
|
|
|
return ''
|
|
|
|
result = 'T0'
|
|
|
|
for param in range(1, num_params + 1):
|
|
|
|
result += ', T%d' % param
|
|
|
|
return result
|
2021-03-17 20:38:33 +00:00
|
|
|
|
|
|
|
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
|
2019-07-22 19:56:35 +00:00
|
|
|
)\
|
|
|
|
$#
|
2021-03-17 20:38:33 +00:00
|
|
|
$extend(type_list, typename_list)\
|
2019-07-22 19:56:35 +00:00
|
|
|
|
|
|
|
namespace vtkm
|
|
|
|
{
|
2020-10-06 21:57:04 +00:00
|
|
|
namespace VTK_M_NAMESPACE
|
|
|
|
{
|
2019-07-22 19:56:35 +00:00
|
|
|
namespace internal
|
|
|
|
{
|
|
|
|
namespace detail
|
|
|
|
{
|
|
|
|
|
|
|
|
template <typename ReturnType>
|
|
|
|
struct VariantDummyReturn
|
|
|
|
{
|
2020-10-06 21:57:04 +00:00
|
|
|
VTK_M_DEVICE static inline ReturnType F() noexcept { return ReturnType{}; }
|
2019-07-22 19:56:35 +00:00
|
|
|
};
|
|
|
|
template <>
|
|
|
|
struct VariantDummyReturn<void>
|
|
|
|
{
|
2020-10-06 21:57:04 +00:00
|
|
|
VTK_M_DEVICE static inline void F() noexcept {}
|
2019-07-22 19:56:35 +00:00
|
|
|
};
|
|
|
|
|
2021-03-17 20:38:33 +00:00
|
|
|
// clang-format off
|
|
|
|
|
|
|
|
// --------------------------------------------------------------------------------
|
|
|
|
// Helper classes to determine if all Variant types are trivial.
|
|
|
|
template <typename... Ts>
|
|
|
|
struct AllTriviallyCopyable;
|
|
|
|
|
|
|
|
$for(num_params in range(max_expanded))\
|
|
|
|
template <$typename_list(num_params)>
|
|
|
|
struct AllTriviallyCopyable<$type_list(num_params)>
|
|
|
|
: std::integral_constant<bool, (vtkmstd::is_trivially_copyable<T0>::value &&
|
|
|
|
$for(param_index in range(1, num_params + 1))\
|
|
|
|
vtkmstd::is_trivially_copyable<T$(param_index)>::value &&
|
|
|
|
$endfor\
|
|
|
|
true)> { };
|
|
|
|
$endfor\
|
|
|
|
template <$typename_list(max_expanded), typename... Ts>
|
|
|
|
struct AllTriviallyCopyable<$type_list(max_expanded), Ts...>
|
|
|
|
: std::integral_constant<bool, (vtkmstd::is_trivially_copyable<T0>::value &&
|
|
|
|
$for(param_index in range(1, max_expanded))\
|
|
|
|
vtkmstd::is_trivially_copyable<T$(param_index)>::value &&
|
|
|
|
$endfor\
|
|
|
|
AllTriviallyCopyable<T$(max_expanded), Ts...>::value)> { };
|
|
|
|
|
|
|
|
template <typename... Ts>
|
|
|
|
struct AllTriviallyConstructible;
|
|
|
|
|
|
|
|
$for(num_params in range(max_expanded))\
|
|
|
|
template <$typename_list(num_params)>
|
|
|
|
struct AllTriviallyConstructible<$type_list(num_params)>
|
|
|
|
: std::integral_constant<bool, (vtkmstd::is_trivially_constructible<T0>::value &&
|
|
|
|
$for(param_index in range(1, num_params + 1))\
|
|
|
|
vtkmstd::is_trivially_constructible<T$(param_index)>::value &&
|
|
|
|
$endfor\
|
|
|
|
true)> { };
|
|
|
|
$endfor\
|
|
|
|
template <$typename_list(max_expanded), typename... Ts>
|
|
|
|
struct AllTriviallyConstructible<$type_list(max_expanded), Ts...>
|
|
|
|
: std::integral_constant<bool, (vtkmstd::is_trivially_constructible<T0>::value &&
|
|
|
|
$for(param_index in range(1, max_expanded))\
|
|
|
|
vtkmstd::is_trivially_constructible<T$(param_index)>::value &&
|
|
|
|
$endfor\
|
|
|
|
AllTriviallyConstructible<T$(max_expanded), Ts...>::value)> { };
|
|
|
|
|
|
|
|
template <typename... Ts>
|
|
|
|
struct AllTriviallyDestructible;
|
|
|
|
|
|
|
|
$for(num_params in range(max_expanded))\
|
|
|
|
template <$typename_list(num_params)>
|
|
|
|
struct AllTriviallyDestructible<$type_list(num_params)>
|
|
|
|
: std::integral_constant<bool, (vtkmstd::is_trivially_destructible<T0>::value &&
|
|
|
|
$for(param_index in range(1, num_params + 1))\
|
|
|
|
vtkmstd::is_trivially_destructible<T$(param_index)>::value &&
|
|
|
|
$endfor\
|
|
|
|
true)> { };
|
|
|
|
$endfor\
|
|
|
|
template <$typename_list(max_expanded), typename... Ts>
|
|
|
|
struct AllTriviallyDestructible<$type_list(max_expanded), Ts...>
|
|
|
|
: std::integral_constant<bool, (vtkmstd::is_trivially_destructible<T0>::value &&
|
|
|
|
$for(param_index in range(1, max_expanded))\
|
|
|
|
vtkmstd::is_trivially_destructible<T$(param_index)>::value &&
|
|
|
|
$endfor\
|
|
|
|
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. 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 trick. 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... Ts>
|
|
|
|
union VariantUnionTD;
|
|
|
|
|
|
|
|
// NTD = non-trivially deconstructible
|
|
|
|
template <typename... Ts>
|
|
|
|
union VariantUnionNTD;
|
|
|
|
|
|
|
|
$for(num_params in range(max_expanded))\
|
|
|
|
template <$typename_list(num_params)>
|
|
|
|
union VariantUnionTD<$type_list(num_params)>
|
2019-07-22 19:56:35 +00:00
|
|
|
{
|
2021-03-17 20:38:33 +00:00
|
|
|
$for(param_index in range(num_params + 1))\
|
|
|
|
T$(param_index) V$(param_index);
|
|
|
|
$endfor\
|
|
|
|
VTK_M_DEVICE VariantUnionTD(vtkm::internal::NullType) { }
|
|
|
|
VariantUnionTD() = default;
|
|
|
|
};
|
2019-07-22 19:56:35 +00:00
|
|
|
|
2021-03-17 20:38:33 +00:00
|
|
|
template <$typename_list(num_params)>
|
|
|
|
union VariantUnionNTD<$type_list(num_params)>
|
|
|
|
{
|
|
|
|
$for(param_index in range(num_params + 1))\
|
|
|
|
T$(param_index) V$(param_index);
|
|
|
|
$endfor\
|
|
|
|
VTK_M_DEVICE VariantUnionNTD(vtkm::internal::NullType) { }
|
|
|
|
VariantUnionNTD() = default;
|
|
|
|
VTK_M_DEVICE ~VariantUnionNTD() { }
|
|
|
|
};
|
2019-07-22 19:56:35 +00:00
|
|
|
|
|
|
|
$endfor\
|
2021-03-17 20:38:33 +00:00
|
|
|
|
|
|
|
template <$typename_list(max_expanded), typename... Ts>
|
|
|
|
union VariantUnionTD<$type_list(max_expanded), Ts...>
|
2019-07-22 19:56:35 +00:00
|
|
|
{
|
2021-03-17 20:38:33 +00:00
|
|
|
vtkm::internal::NullType Dummy;
|
|
|
|
$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...>
|
|
|
|
{
|
|
|
|
vtkm::internal::NullType Dummy;
|
|
|
|
$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>
|
|
|
|
{
|
2021-03-23 19:30:55 +00:00
|
|
|
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
|
2019-07-22 19:56:35 +00:00
|
|
|
{
|
2021-03-17 20:38:33 +00:00
|
|
|
return storage.V$(param_index);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2019-07-22 19:56:35 +00:00
|
|
|
$endfor\
|
2021-03-17 20:38:33 +00:00
|
|
|
|
|
|
|
template <vtkm::IdComponent I, typename UnionType>
|
|
|
|
struct VariantUnionGetImpl
|
|
|
|
{
|
|
|
|
VTKM_STATIC_ASSERT(I >= $(max_expanded));
|
2021-03-23 19:30:55 +00:00
|
|
|
using RecursiveGet = VariantUnionGetImpl<I - $(max_expanded), decltype(std::declval<UnionType&>().Remaining)>;
|
2021-03-17 20:38:33 +00:00
|
|
|
using ReturnType = typename RecursiveGet::ReturnType;
|
2021-03-23 19:30:55 +00:00
|
|
|
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
|
2021-03-17 20:38:33 +00:00
|
|
|
{
|
|
|
|
return RecursiveGet::Get(storage.Remaining);
|
2019-07-22 19:56:35 +00:00
|
|
|
}
|
2021-03-17 20:38:33 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
template <vtkm::IdComponent I, typename UnionType>
|
2021-03-23 19:30:55 +00:00
|
|
|
VTK_M_DEVICE auto VariantUnionGet(UnionType& storage) noexcept
|
|
|
|
-> decltype(VariantUnionGetImpl<I, typename std::decay<UnionType>::type>::Get(storage))&
|
2021-03-17 20:38:33 +00:00
|
|
|
{
|
2021-03-23 19:30:55 +00:00
|
|
|
return VariantUnionGetImpl<I, typename std::decay<UnionType>::type>::Get(storage);
|
2019-07-22 19:56:35 +00:00
|
|
|
}
|
|
|
|
|
2021-03-17 20:38:33 +00:00
|
|
|
// --------------------------------------------------------------------------------
|
|
|
|
// Internal implementation of CastAndCall for Variant
|
|
|
|
$for(num_params in range(max_expanded))\
|
|
|
|
template <typename Functor,
|
|
|
|
typename UnionType,
|
2019-07-22 19:56:35 +00:00
|
|
|
typename... Args>
|
2021-03-17 20:38:33 +00:00
|
|
|
VTK_M_DEVICE inline auto VariantCastAndCallImpl(
|
|
|
|
std::integral_constant<vtkm::IdComponent, $(num_params + 1)>,
|
2019-07-22 19:56:35 +00:00
|
|
|
vtkm::IdComponent index,
|
|
|
|
Functor&& f,
|
2021-03-17 20:38:33 +00:00
|
|
|
UnionType& storage,
|
|
|
|
Args&&... args) noexcept(noexcept(f(storage.V0, args...)))
|
|
|
|
-> decltype(f(storage.V0, args...))
|
2019-07-22 19:56:35 +00:00
|
|
|
{
|
|
|
|
switch (index)
|
|
|
|
{
|
2021-03-17 20:38:33 +00:00
|
|
|
$for(param_index in range(num_params + 1))\
|
2019-07-22 19:56:35 +00:00
|
|
|
case $(param_index):
|
2021-03-17 20:38:33 +00:00
|
|
|
return f(storage.V$(param_index), std::forward<Args>(args)...);
|
2019-07-22 19:56:35 +00:00
|
|
|
$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.");
|
2021-03-17 20:38:33 +00:00
|
|
|
return VariantDummyReturn<decltype(f(storage.V0, args...))>::F();
|
2019-07-22 19:56:35 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
$endfor\
|
|
|
|
//clang-format on
|
|
|
|
|
|
|
|
// Recurse for cases where Variant has more than $(max_expanded) types
|
2021-03-17 20:38:33 +00:00
|
|
|
template <vtkm::IdComponent N,
|
2019-07-22 19:56:35 +00:00
|
|
|
typename Functor,
|
2021-03-17 20:38:33 +00:00
|
|
|
typename UnionType,
|
2019-07-22 19:56:35 +00:00
|
|
|
typename... Args>
|
2021-03-17 20:38:33 +00:00
|
|
|
VTK_M_DEVICE inline auto VariantCastAndCallImpl(
|
|
|
|
std::integral_constant<vtkm::IdComponent, N>,
|
2019-07-22 19:56:35 +00:00
|
|
|
vtkm::IdComponent index,
|
|
|
|
Functor&& f,
|
2021-03-17 20:38:33 +00:00
|
|
|
UnionType& storage,
|
|
|
|
Args&&... args) noexcept(noexcept(f(storage.V0, args...)))
|
|
|
|
-> decltype(f(storage.V0, args...))
|
2019-07-22 19:56:35 +00:00
|
|
|
{
|
2021-03-17 20:38:33 +00:00
|
|
|
switch (index)
|
2019-07-22 19:56:35 +00:00
|
|
|
{
|
2021-03-17 20:38:33 +00:00
|
|
|
$for(param_index in range(max_expanded))\
|
|
|
|
case $(param_index):
|
|
|
|
return f(storage.V$(param_index), std::forward<Args>(args)...);
|
2019-07-22 19:56:35 +00:00
|
|
|
$endfor\
|
2021-03-17 20:38:33 +00:00
|
|
|
default:
|
|
|
|
return VariantCastAndCallImpl(std::integral_constant<vtkm::IdComponent, N - $(max_expanded)>{},
|
|
|
|
index - $(max_expanded),
|
|
|
|
std::forward<Functor>(f),
|
|
|
|
storage.Remaining,
|
|
|
|
std::forward<Args>(args)...);
|
2019-07-22 19:56:35 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
2020-10-06 21:57:04 +00:00
|
|
|
}
|
|
|
|
} // vtkm::VTK_M_NAMESPACE::internal::detail
|