Merge topic 'variant-trivial-copy'

7518d0675 Try to fix uninitialized anonymous variable warning
5b18ffd77 Register Variant as trivially copyable if possible
16305bd83 Add tests of ArrayHandleMultiplexer on multiple devices

Acked-by: Kitware Robot <kwrobot@kitware.com>
Acked-by: Robert Maynard <robert.maynard@kitware.com>
Merge-request: !1898
This commit is contained in:
Kenneth Moreland 2019-10-29 15:04:36 +00:00 committed by Kitware Robot
commit 291f3527b1
3 changed files with 305 additions and 83 deletions

@ -22,6 +22,7 @@
#include <vtkm/cont/ArrayHandleGroupVecVariable.h>
#include <vtkm/cont/ArrayHandleImplicit.h>
#include <vtkm/cont/ArrayHandleIndex.h>
#include <vtkm/cont/ArrayHandleMultiplexer.h>
#include <vtkm/cont/ArrayHandlePermutation.h>
#include <vtkm/cont/ArrayHandleSOA.h>
#include <vtkm/cont/ArrayHandleTransform.h>
@ -891,6 +892,64 @@ private:
}
};
struct TestMultiplexerAsInput
{
vtkm::cont::Invoker Invoke;
template <typename T>
VTKM_CONT void operator()(T vtkmNotUsed(type)) const
{
using InputArrayType = vtkm::cont::ArrayHandleCounting<T>;
InputArrayType input(T(1), T(2), ARRAY_SIZE);
vtkm::cont::ArrayHandleMultiplexer<
vtkm::cont::ArrayHandle<T>,
InputArrayType,
vtkm::cont::ArrayHandleCast<T, vtkm::cont::ArrayHandleIndex>>
multiplexArray(input);
vtkm::cont::ArrayHandle<T> result;
this->Invoke(PassThrough{}, multiplexArray, result);
vtkm::cont::printSummary_ArrayHandle(multiplexArray, std::cout);
std::cout << std::endl;
// verify results
VTKM_TEST_ASSERT(
test_equal_portals(result.GetPortalConstControl(), input.GetPortalConstControl()),
"CastingArrayHandle failed");
}
};
struct TestMultiplexerAsOutput
{
vtkm::cont::Invoker Invoke;
template <typename CastFromType>
VTKM_CONT void operator()(CastFromType vtkmNotUsed(type)) const
{
using InputArrayType = vtkm::cont::ArrayHandleIndex;
using ResultArrayType = vtkm::cont::ArrayHandle<CastFromType>;
InputArrayType input(ARRAY_SIZE);
ResultArrayType result;
vtkm::cont::ArrayHandleMultiplexer<vtkm::cont::ArrayHandle<vtkm::Id>,
vtkm::cont::ArrayHandleCast<vtkm::Id, ResultArrayType>>
multiplexerArray = vtkm::cont::make_ArrayHandleCast<vtkm::Id>(result);
this->Invoke(PassThrough{}, input, multiplexerArray);
vtkm::cont::printSummary_ArrayHandle(multiplexerArray, std::cout);
std::cout << std::endl;
// verify results
VTKM_TEST_ASSERT(
test_equal_portals(input.GetPortalConstControl(), result.GetPortalConstControl()),
"Multiplexing ArrayHandle failed");
}
};
template <vtkm::IdComponent NUM_COMPONENTS>
struct TestGroupVecAsInput
{
@ -1511,6 +1570,16 @@ private:
vtkm::testing::Testing::TryTypes(
TestingFancyArrayHandles<DeviceAdapterTag>::TestCastAsOutput(), CastTypesToTest());
std::cout << "-------------------------------------------" << std::endl;
std::cout << "Testing ArrayHandleMultiplexer as Input" << std::endl;
vtkm::testing::Testing::TryTypes(
TestingFancyArrayHandles<DeviceAdapterTag>::TestMultiplexerAsInput(), CastTypesToTest());
std::cout << "-------------------------------------------" << std::endl;
std::cout << "Testing ArrayHandleMultiplexer as Output" << std::endl;
vtkm::testing::Testing::TryTypes(
TestingFancyArrayHandles<DeviceAdapterTag>::TestMultiplexerAsOutput(), CastTypesToTest());
std::cout << "-------------------------------------------" << std::endl;
std::cout << "Testing ArrayHandleGroupVec<3> as Input" << std::endl;
vtkm::testing::Testing::TryTypes(

@ -72,6 +72,10 @@ namespace vtkm
namespace internal
{
// Forward declaration
template <typename... Ts>
class Variant;
namespace detail
{
@ -95,40 +99,206 @@ struct VariantDestroyFunctor
}
};
} // namespace detail
template <typename... Ts>
struct AllTriviallyCopyable;
template <>
struct AllTriviallyCopyable<> : std::true_type
{
};
template <typename T0>
struct AllTriviallyCopyable<T0>
: std::integral_constant<bool, (std::is_trivially_copyable<T0>::value)>
{
};
template <typename T0, typename T1>
struct AllTriviallyCopyable<T0, T1>
: std::integral_constant<bool,
(std::is_trivially_copyable<T0>::value &&
std::is_trivially_copyable<T1>::value)>
{
};
template <typename T0, typename T1, typename T2>
struct AllTriviallyCopyable<T0, T1, T2>
: std::integral_constant<bool,
(std::is_trivially_copyable<T0>::value &&
std::is_trivially_copyable<T1>::value &&
std::is_trivially_copyable<T2>::value)>
{
};
template <typename T0, typename T1, typename T2, typename T3>
struct AllTriviallyCopyable<T0, T1, T2, T3>
: std::integral_constant<bool,
(std::is_trivially_copyable<T0>::value &&
std::is_trivially_copyable<T1>::value &&
std::is_trivially_copyable<T2>::value &&
std::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,
(std::is_trivially_copyable<T0>::value &&
std::is_trivially_copyable<T1>::value &&
std::is_trivially_copyable<T2>::value &&
std::is_trivially_copyable<T3>::value &&
std::is_trivially_copyable<T4>::value &&
AllTriviallyCopyable<Ts...>::value)>
{
};
template <typename VariantType>
struct VariantTriviallyCopyable;
template <typename... Ts>
class Variant
struct VariantTriviallyCopyable<vtkm::internal::Variant<Ts...>> : AllTriviallyCopyable<Ts...>
{
struct ListTag : vtkm::ListTagBase<Ts...>
{
};
};
template <typename... Ts>
struct VariantStorageImpl
{
typename vtkmstd::aligned_union<0, Ts...>::type Storage;
vtkm::IdComponent Index = -1;
template <vtkm::IdComponent Index>
using TypeAt = typename vtkm::ListTypeAt<vtkm::ListTagBase<Ts...>, Index>::type;
VTKM_EXEC_CONT void* GetPointer() { return reinterpret_cast<void*>(&this->Storage); }
VTKM_EXEC_CONT const void* GetPointer() const
{
return reinterpret_cast<const void*>(&this->Storage);
}
vtkm::IdComponent Index = -1;
VTKM_EXEC_CONT vtkm::IdComponent GetIndex() const noexcept { return this->Index; }
VTKM_EXEC_CONT bool IsValid() const noexcept { return this->GetIndex() >= 0; }
VTKM_EXEC_CONT void Reset() noexcept
{
if (this->IsValid())
{
this->CastAndCall(detail::VariantDestroyFunctor{});
this->Index = -1;
}
}
template <typename Functor, typename... Args>
VTKM_EXEC_CONT auto CastAndCall(Functor&& f, Args&&... args) const
noexcept(noexcept(f(std::declval<const TypeAt<0>&>(), args...)))
-> 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)...);
}
template <typename Functor, typename... Args>
VTKM_EXEC_CONT auto CastAndCall(Functor&& f, Args&&... args) noexcept(
noexcept(f(std::declval<const TypeAt<0>&>(), args...)))
-> 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)...);
}
};
template <typename VariantType,
typename TriviallyCopyable = typename VariantTriviallyCopyable<VariantType>::type>
struct VariantConstructorImpl;
template <typename... Ts>
struct VariantConstructorImpl<vtkm::internal::Variant<Ts...>, std::true_type>
: VariantStorageImpl<Ts...>
{
VariantConstructorImpl() = default;
~VariantConstructorImpl() = default;
VariantConstructorImpl(const VariantConstructorImpl&) = default;
VariantConstructorImpl(VariantConstructorImpl&&) = default;
VariantConstructorImpl& operator=(const VariantConstructorImpl&) = default;
VariantConstructorImpl& operator=(VariantConstructorImpl&&) = default;
};
template <typename... Ts>
struct VariantConstructorImpl<vtkm::internal::Variant<Ts...>, std::false_type>
: VariantStorageImpl<Ts...>
{
VariantConstructorImpl() = default;
VTKM_EXEC_CONT ~VariantConstructorImpl() { this->Reset(); }
VTKM_EXEC_CONT VariantConstructorImpl(const VariantConstructorImpl& src) noexcept
{
src.CastAndCall(VariantCopyFunctor{}, this->GetPointer());
this->Index = src.Index;
}
VTKM_EXEC_CONT VariantConstructorImpl(VariantConstructorImpl&& rhs) noexcept
{
this->Storage = std::move(rhs.Storage);
this->Index = std::move(rhs.Index);
rhs.Index = -1;
}
VTKM_EXEC_CONT VariantConstructorImpl& operator=(const VariantConstructorImpl& src) noexcept
{
this->Reset();
src.CastAndCall(detail::VariantCopyFunctor{}, this->GetPointer());
this->Index = src.Index;
return *this;
}
VTKM_EXEC_CONT VariantConstructorImpl& operator=(VariantConstructorImpl&& rhs) noexcept
{
this->Reset();
this->Storage = std::move(rhs.Storage);
this->Index = std::move(rhs.Index);
rhs.Index = -1;
return *this;
}
};
} // namespace detail
template <typename... Ts>
class Variant : detail::VariantConstructorImpl<Variant<Ts...>>
{
using Superclass = detail::VariantConstructorImpl<Variant<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), -1 is returned.
///
VTKM_EXEC_CONT vtkm::IdComponent GetIndex() const noexcept { return this->Index; }
VTKM_EXEC_CONT 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.
///
VTKM_EXEC_CONT bool IsValid() const noexcept { return this->GetIndex() >= 0; }
VTKM_EXEC_CONT 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>
using IndexOf = std::integral_constant<vtkm::IdComponent, vtkm::ListIndexOf<ListTag, T>::value>;
using IndexOf = std::integral_constant<vtkm::IdComponent,
vtkm::ListIndexOf<vtkm::ListTagBase<Ts...>, T>::value>;
/// Returns the index for the given type (or -1 if that type is not in the list).
///
@ -141,13 +311,18 @@ public:
/// Type that converts to the type at the given index.
///
template <vtkm::IdComponent Index>
using TypeAt = typename vtkm::ListTypeAt<ListTag, Index>::type;
using TypeAt = typename Superclass::template TypeAt<Index>;
/// The number of types representable by this Variant.
///
static constexpr vtkm::IdComponent NumberOfTypes = vtkm::IdComponent{ sizeof...(Ts) };
Variant() = default;
~Variant() = default;
Variant(const Variant&) = default;
Variant(Variant&&) = default;
Variant& operator=(const Variant&) = default;
Variant& operator=(Variant&&) = default;
template <typename T>
VTKM_EXEC_CONT Variant(const T& src) noexcept
@ -171,38 +346,6 @@ public:
this->Index = index;
}
VTKM_EXEC_CONT Variant(Variant&& rhs) noexcept
{
this->Storage = std::move(rhs.Storage);
this->Index = std::move(rhs.Index);
rhs.Index = -1;
}
VTKM_EXEC_CONT Variant(const Variant& src) noexcept
{
src.CastAndCall(detail::VariantCopyFunctor{}, this->GetPointer());
this->Index = src.GetIndex();
}
VTKM_EXEC_CONT ~Variant() { this->Reset(); }
VTKM_EXEC_CONT Variant& operator=(Variant&& rhs) noexcept
{
this->Reset();
this->Storage = std::move(rhs.Storage);
this->Index = std::move(rhs.Index);
rhs.Index = -1;
return *this;
}
VTKM_EXEC_CONT Variant& operator=(const Variant& src) noexcept
{
this->Reset();
src.CastAndCall(detail::VariantCopyFunctor{}, this->GetPointer());
this->Index = src.GetIndex();
return *this;
}
template <typename T, typename... Args>
VTKM_EXEC_CONT T& Emplace(Args&&... args)
{
@ -305,13 +448,7 @@ public:
noexcept(noexcept(f(std::declval<const TypeAt<0>&>(), args...)))
-> decltype(f(std::declval<const TypeAt<0>&>(), args...))
{
VTKM_ASSERT(this->IsValid());
return detail::VariantCastAndCallImpl<decltype(f(std::declval<const TypeAt<0>&>(), args...))>(
vtkm::internal::ListTagAsBrigandList<ListTag>(),
this->GetIndex(),
std::forward<Functor>(f),
this->GetPointer(),
std::forward<Args>(args)...);
return this->Superclass::CastAndCall(std::forward<Functor>(f), std::forward<Args>(args)...);
}
template <typename Functor, typename... Args>
@ -319,26 +456,13 @@ public:
noexcept(f(std::declval<const TypeAt<0>&>(), args...)))
-> decltype(f(std::declval<TypeAt<0>&>(), args...))
{
VTKM_ASSERT(this->IsValid());
return detail::VariantCastAndCallImpl<decltype(f(std::declval<TypeAt<0>&>(), args...))>(
vtkm::internal::ListTagAsBrigandList<ListTag>(),
this->GetIndex(),
std::forward<Functor>(f),
this->GetPointer(),
std::forward<Args>(args)...);
return this->Superclass::CastAndCall(std::forward<Functor>(f), 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.
///
VTKM_EXEC_CONT void Reset() noexcept
{
if (this->IsValid())
{
this->CastAndCall(detail::VariantDestroyFunctor{});
this->Index = -1;
}
}
VTKM_EXEC_CONT void Reset() noexcept { this->Superclass::Reset(); }
};
/// \brief Convert a ListTag to a Variant.

@ -12,9 +12,10 @@
#include <vtkm/testing/Testing.h>
#include <memory>
#include <vector>
namespace
namespace test_variant
{
template <vtkm::IdComponent Index>
@ -60,6 +61,32 @@ void TestIndexing()
VTKM_STATIC_ASSERT((std::is_same<VariantType::TypeAt<3>, TypePlaceholder<3>>::value));
}
void TestTriviallyCopyable()
{
// Make sure base types are behaving as expected
VTKM_STATIC_ASSERT(std::is_trivially_copyable<float>::value);
VTKM_STATIC_ASSERT(std::is_trivially_copyable<int>::value);
VTKM_STATIC_ASSERT(!std::is_trivially_copyable<std::shared_ptr<float>>::value);
// A variant of trivially copyable things should be trivially copyable
VTKM_STATIC_ASSERT((vtkm::internal::detail::AllTriviallyCopyable<float, int>::value));
VTKM_STATIC_ASSERT((std::is_trivially_copyable<vtkm::internal::Variant<float, int>>::value));
// A variant of any non-trivially copyable things is not trivially copyable
VTKM_STATIC_ASSERT(
(!vtkm::internal::detail::AllTriviallyCopyable<std::shared_ptr<float>, float, int>::value));
VTKM_STATIC_ASSERT(
(!vtkm::internal::detail::AllTriviallyCopyable<float, std::shared_ptr<float>, int>::value));
VTKM_STATIC_ASSERT(
(!vtkm::internal::detail::AllTriviallyCopyable<float, int, std::shared_ptr<float>>::value));
VTKM_STATIC_ASSERT((!std::is_trivially_copyable<
vtkm::internal::Variant<std::shared_ptr<float>, float, int>>::value));
VTKM_STATIC_ASSERT((!std::is_trivially_copyable<
vtkm::internal::Variant<float, std::shared_ptr<float>, int>>::value));
VTKM_STATIC_ASSERT((!std::is_trivially_copyable<
vtkm::internal::Variant<float, int, std::shared_ptr<float>>>::value));
}
struct TestFunctor
{
template <vtkm::IdComponent Index>
@ -114,31 +141,32 @@ void TestCastAndCall()
VTKM_TEST_ASSERT(test_equal(result, TestValue(3, vtkm::FloatDefault{})));
}
struct CountConstructDestruct
{
vtkm::Id* Count;
CountConstructDestruct(vtkm::Id* count)
: Count(count)
{
++(*this->Count);
}
CountConstructDestruct(const CountConstructDestruct& src)
: Count(src.Count)
{
++(*this->Count);
}
~CountConstructDestruct() { --(*this->Count); }
};
void TestCopyDestroy()
{
std::cout << "Test copy destroy" << std::endl;
struct CountConstructDestruct
{
vtkm::Id* Count;
CountConstructDestruct(vtkm::Id* count)
: Count(count)
{
++(*this->Count);
}
CountConstructDestruct(const CountConstructDestruct& src)
: Count(src.Count)
{
++(*this->Count);
}
~CountConstructDestruct() { --(*this->Count); }
};
using VariantType = vtkm::internal::Variant<TypePlaceholder<0>,
TypePlaceholder<1>,
CountConstructDestruct,
TypePlaceholder<2>,
TypePlaceholder<3>>;
VTKM_STATIC_ASSERT(!std::is_trivially_copyable<VariantType>::value);
vtkm::Id count = 0;
VariantType variant1 = CountConstructDestruct(&count);
@ -218,15 +246,16 @@ void RunTest()
{
TestSize();
TestIndexing();
TestTriviallyCopyable();
TestGet();
TestCastAndCall();
TestCopyDestroy();
TestEmplace();
}
} // anonymous namespace
} // namespace test_variant
int UnitTestVariant(int argc, char* argv[])
{
return vtkm::testing::Testing::Run(RunTest, argc, argv);
return vtkm::testing::Testing::Run(test_variant::RunTest, argc, argv);
}