Commit cb3d6e5c authored by Kenneth Moreland's avatar Kenneth Moreland Committed by Vicente Bolea
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: Kitware Robot's avatarKitware Robot <kwrobot@kitware.com>
Acked-by: default avatarRobert Maynard <robert.maynard@kitware.com>
Merge-request: !1898
parent 8b2f4677
......@@ -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(
......
......@@ -81,6 +81,10 @@ namespace vtkm
namespace internal
{
// Forward declaration
template <typename... Ts>
class Variant;
namespace detail
{
......@@ -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>
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).
///
......@@ -150,13 +320,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
......@@ -180,38 +355,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)
{
......@@ -314,13 +457,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>
......@@ -328,26 +465,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);
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment