Commit cb3d6e5c authored by Kenneth Moreland's avatar Kenneth Moreland Committed by Bolea Sanchez, Vicente Adolfo
Browse files

Variant as trivially copyable

7518d067 Try to fix uninitialized anonymous variable warning
5b18ffd7 Register Variant as trivially copyable if possible
16305bd8

 Add tests of ArrayHandleMultiplexer on multiple devices

Acked-by: default avatarKitware Robot <kwrobot@kitware.com>
Acked-by: Maynard, Robert's avatarRobert Maynard <robert.maynard@kitware.com>
Merge-request: !1898
parent 8b2f4677
...@@ -22,6 +22,7 @@ ...@@ -22,6 +22,7 @@
#include <vtkm/cont/ArrayHandleGroupVecVariable.h> #include <vtkm/cont/ArrayHandleGroupVecVariable.h>
#include <vtkm/cont/ArrayHandleImplicit.h> #include <vtkm/cont/ArrayHandleImplicit.h>
#include <vtkm/cont/ArrayHandleIndex.h> #include <vtkm/cont/ArrayHandleIndex.h>
#include <vtkm/cont/ArrayHandleMultiplexer.h>
#include <vtkm/cont/ArrayHandlePermutation.h> #include <vtkm/cont/ArrayHandlePermutation.h>
#include <vtkm/cont/ArrayHandleSOA.h> #include <vtkm/cont/ArrayHandleSOA.h>
#include <vtkm/cont/ArrayHandleTransform.h> #include <vtkm/cont/ArrayHandleTransform.h>
...@@ -891,6 +892,64 @@ private: ...@@ -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> template <vtkm::IdComponent NUM_COMPONENTS>
struct TestGroupVecAsInput struct TestGroupVecAsInput
{ {
...@@ -1511,6 +1570,16 @@ private: ...@@ -1511,6 +1570,16 @@ private:
vtkm::testing::Testing::TryTypes( vtkm::testing::Testing::TryTypes(
TestingFancyArrayHandles<DeviceAdapterTag>::TestCastAsOutput(), CastTypesToTest()); 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 << "-------------------------------------------" << std::endl;
std::cout << "Testing ArrayHandleGroupVec<3> as Input" << std::endl; std::cout << "Testing ArrayHandleGroupVec<3> as Input" << std::endl;
vtkm::testing::Testing::TryTypes( vtkm::testing::Testing::TryTypes(
......
...@@ -81,6 +81,10 @@ namespace vtkm ...@@ -81,6 +81,10 @@ namespace vtkm
namespace internal namespace internal
{ {
// Forward declaration
template <typename... Ts>
class Variant;
namespace detail namespace detail
{ {
...@@ -104,40 +108,206 @@ struct VariantDestroyFunctor ...@@ -104,40 +108,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> 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; 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 void* GetPointer() { return reinterpret_cast<void*>(&this->Storage); }
VTKM_EXEC_CONT const void* GetPointer() const VTKM_EXEC_CONT const void* GetPointer() const
{ {
return reinterpret_cast<const void*>(&this->Storage); 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: public:
/// Returns the index of the type of object this variant is storing. If no object is currently /// 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. /// 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 /// Returns true if this Variant is storing an object from one of the types in the template
/// list, false otherwise. /// 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 /// 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). /// -1 if that type is not in the list).
template <typename T> 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). /// Returns the index for the given type (or -1 if that type is not in the list).
/// ///
...@@ -150,13 +320,18 @@ public: ...@@ -150,13 +320,18 @@ public:
/// Type that converts to the type at the given index. /// Type that converts to the type at the given index.
/// ///
template <vtkm::IdComponent 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. /// The number of types representable by this Variant.
/// ///
static constexpr vtkm::IdComponent NumberOfTypes = vtkm::IdComponent{ sizeof...(Ts) }; static constexpr vtkm::IdComponent NumberOfTypes = vtkm::IdComponent{ sizeof...(Ts) };
Variant() = default; Variant() = default;
~Variant() = default;
Variant(const Variant&) = default;
Variant(Variant&&) = default;
Variant& operator=(const Variant&) = default;
Variant& operator=(Variant&&) = default;
template <typename T> template <typename T>
VTKM_EXEC_CONT Variant(const T& src) noexcept VTKM_EXEC_CONT Variant(const T& src) noexcept
...@@ -180,38 +355,6 @@ public: ...@@ -180,38 +355,6 @@ public:
this->Index = index; 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> template <typename T, typename... Args>
VTKM_EXEC_CONT T& Emplace(Args&&... args) VTKM_EXEC_CONT T& Emplace(Args&&... args)
{ {
...@@ -314,13 +457,7 @@ public: ...@@ -314,13 +457,7 @@ public:
noexcept(noexcept(f(std::declval<const TypeAt<0>&>(), args...))) noexcept(noexcept(f(std::declval<const TypeAt<0>&>(), args...)))
-> decltype(f(std::declval<const TypeAt<0>&>(), args...)) -> decltype(f(std::declval<const TypeAt<0>&>(), args...))
{ {
VTKM_ASSERT(this->IsValid()); return this->Superclass::CastAndCall(std::forward<Functor>(f), std::forward<Args>(args)...);
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)...);
} }
template <typename Functor, typename... Args> template <typename Functor, typename... Args>
...@@ -328,26 +465,13 @@ public: ...@@ -328,26 +465,13 @@ public:
noexcept(f(std::declval<const TypeAt<0>&>(), args...))) noexcept(f(std::declval<const TypeAt<0>&>(), args...)))
-> decltype(f(std::declval<TypeAt<0>&>(), args...)) -> decltype(f(std::declval<TypeAt<0>&>(), args...))
{ {
VTKM_ASSERT(this->IsValid()); return this->Superclass::CastAndCall(std::forward<Functor>(f), std::forward<Args>(args)...);
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)...);
} }
/// Destroys any object the Variant is holding and sets the Variant to an invalid state. This /// Destroys any object the Variant is holding and sets the Variant to an invalid state. This
/// method is not thread safe. /// method is not thread safe.
/// ///
VTKM_EXEC_CONT void Reset() noexcept VTKM_EXEC_CONT void Reset() noexcept { this->Superclass::Reset(); }
{
if (this->IsValid())
{
this->CastAndCall(detail::VariantDestroyFunctor{});
this->Index = -1;
}
}
}; };
/// \brief Convert a ListTag to a Variant. /// \brief Convert a ListTag to a Variant.
......
...@@ -12,9 +12,10 @@ ...@@ -12,9 +12,10 @@
#include <vtkm/testing/Testing.h> #include <vtkm/testing/Testing.h>
#include <memory>
#include <vector> #include <vector>
namespace namespace test_variant
{ {
template <vtkm::IdComponent Index> template <vtkm::IdComponent Index>
...@@ -60,6 +61,32 @@ void TestIndexing() ...@@ -60,6 +61,32 @@ void TestIndexing()
VTKM_STATIC_ASSERT((std::is_same<VariantType::TypeAt<3>, TypePlaceholder<3>>::value)); 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 struct TestFunctor
{ {
template <vtkm::IdComponent Index> template <vtkm::IdComponent Index>
...@@ -114,31 +141,32 @@ void TestCastAndCall() ...@@ -114,31 +141,32 @@ void TestCastAndCall()
VTKM_TEST_ASSERT(test_equal(result, TestValue(3, vtkm::FloatDefault{}))); 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() void TestCopyDestroy()
{ {
std::cout << "Test copy destroy" << std::endl; 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>, using VariantType = vtkm::internal::Variant<TypePlaceholder<0>,
TypePlaceholder<1>, TypePlaceholder<1>,
CountConstructDestruct, CountConstructDestruct,
TypePlaceholder<2>, TypePlaceholder<2>,
TypePlaceholder<3>>; TypePlaceholder<3>>;
VTKM_STATIC_ASSERT(!std::is_trivially_copyable<VariantType>::value);
vtkm::Id count = 0; vtkm::Id count = 0;
VariantType variant1 = CountConstructDestruct(&count); VariantType variant1 = CountConstructDestruct(&count);
...@@ -218,15 +246,16 @@ void RunTest() ...@@ -218,15 +246,16 @@ void RunTest()
{ {
TestSize(); TestSize();
TestIndexing();