mirror of
https://gitlab.kitware.com/vtk/vtk-m
synced 2024-09-08 13:23:51 +00:00
parent
5834c28521
commit
88bf38afe2
114
docs/changelog/decorator_resizing.md
Normal file
114
docs/changelog/decorator_resizing.md
Normal file
@ -0,0 +1,114 @@
|
||||
# ArrayHandleDecorator Allocate and Shrink Support
|
||||
|
||||
`ArrayHandleDecorator` can now be resized when given an appropriate
|
||||
decorator implementation.
|
||||
|
||||
Since the mapping between the size of an `ArrayHandleDecorator` and its source
|
||||
`ArrayHandle`s is not well defined, resize operations (such as `Shrink` and
|
||||
`Allocate`) are not defined by default, and will throw an exception if called.
|
||||
|
||||
However, by implementing the methods `AllocateSourceArrays` and/or
|
||||
`ShrinkSourceArrays` on the implementation class, resizing the decorator is
|
||||
allowed. These methods are passed in a new size along with each of the
|
||||
`ArrayHandleDecorator`'s source arrays, allowing developers to control how
|
||||
the resize operation should affect the source arrays.
|
||||
|
||||
For example, the following decorator implementation can be used to create a
|
||||
resizable `ArrayHandleDecorator` that is implemented using two arrays, which
|
||||
are combined to produce values via the expression:
|
||||
|
||||
```
|
||||
[decorator value i] = [source1 value i] * 10 + [source2 value i]
|
||||
```
|
||||
|
||||
Implementation:
|
||||
|
||||
```c++
|
||||
template <typename ValueType>
|
||||
struct DecompositionDecorImpl
|
||||
{
|
||||
template <typename Portal1T, typename Portal2T>
|
||||
struct Functor
|
||||
{
|
||||
Portal1T Portal1;
|
||||
Portal2T Portal2;
|
||||
|
||||
VTKM_EXEC_CONT
|
||||
ValueType operator()(vtkm::Id idx) const
|
||||
{
|
||||
return static_cast<ValueType>(this->Portal1.Get(idx) * 10 + this->Portal2.Get(idx));
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Portal1T, typename Portal2T>
|
||||
struct InverseFunctor
|
||||
{
|
||||
Portal1T Portal1;
|
||||
Portal2T Portal2;
|
||||
|
||||
VTKM_EXEC_CONT
|
||||
void operator()(vtkm::Id idx, const ValueType& val) const
|
||||
{
|
||||
this->Portal1.Set(idx, static_cast<ValueType>(std::floor(val / 10)));
|
||||
this->Portal2.Set(idx, static_cast<ValueType>(std::fmod(val, 10)));
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Portal1T, typename Portal2T>
|
||||
VTKM_CONT Functor<typename std::decay<Portal1T>::type, typename std::decay<Portal2T>::type>
|
||||
CreateFunctor(Portal1T&& p1, Portal2T&& p2) const
|
||||
{
|
||||
return { std::forward<Portal1T>(p1), std::forward<Portal2T>(p2) };
|
||||
}
|
||||
|
||||
template <typename Portal1T, typename Portal2T>
|
||||
VTKM_CONT InverseFunctor<typename std::decay<Portal1T>::type, typename std::decay<Portal2T>::type>
|
||||
CreateInverseFunctor(Portal1T&& p1, Portal2T&& p2) const
|
||||
{
|
||||
return { std::forward<Portal1T>(p1), std::forward<Portal2T>(p2) };
|
||||
}
|
||||
|
||||
// Resize methods:
|
||||
template <typename Array1T, typename Array2T>
|
||||
VTKM_CONT
|
||||
void AllocateSourceArrays(vtkm::Id numVals, Array1T&& array1, Array2T&& array2) const
|
||||
{
|
||||
array1.Allocate(numVals);
|
||||
array2.Allocate(numVals);
|
||||
}
|
||||
|
||||
template <typename Array1T, typename Array2T>
|
||||
VTKM_CONT
|
||||
void ShrinkSourceArrays(vtkm::Id numVals, Array1T&& array1, Array2T&& array2) const
|
||||
{
|
||||
array1.Shrink(numVals);
|
||||
array2.Shrink(numVals);
|
||||
}
|
||||
};
|
||||
|
||||
// Usage:
|
||||
vtkm::cont::ArrayHandle<ValueType> a1;
|
||||
vtkm::cont::ArrayHandle<ValueType> a2;
|
||||
auto decor = vtkm::cont::make_ArrayHandleDecorator(0, DecompositionDecorImpl<ValueType>{}, a1, a2);
|
||||
|
||||
decor.Allocate(5);
|
||||
{
|
||||
auto decorPortal = decor.GetPortalControl();
|
||||
decorPortal.Set(0, 13);
|
||||
decorPortal.Set(1, 8);
|
||||
decorPortal.Set(2, 43);
|
||||
decorPortal.Set(3, 92);
|
||||
decorPortal.Set(4, 117);
|
||||
}
|
||||
|
||||
// a1: { 1, 0, 4, 9, 11 }
|
||||
// a2: { 3, 8, 3, 2, 7 }
|
||||
// decor: { 13, 8, 43, 92, 117 }
|
||||
|
||||
decor.Shrink(3);
|
||||
|
||||
// a1: { 1, 0, 4 }
|
||||
// a2: { 3, 8, 3 }
|
||||
// decor: { 13, 8, 43 }
|
||||
|
||||
```
|
@ -11,6 +11,7 @@
|
||||
#define vtk_m_ArrayHandleDecorator_h
|
||||
|
||||
#include <vtkm/cont/ArrayHandle.h>
|
||||
#include <vtkm/cont/ErrorBadType.h>
|
||||
#include <vtkm/cont/Storage.h>
|
||||
|
||||
#include <vtkm/StaticAssert.h>
|
||||
@ -137,6 +138,44 @@ public:
|
||||
using type = decltype(InverseExistsTest<DecoratorImplT>(0));
|
||||
};
|
||||
|
||||
// Tests whether DecoratorImplT has an AllocateSourceArrays(size, Arrays...) method.
|
||||
template <typename DecoratorImplT, typename ArrayList>
|
||||
struct IsDecoratorAllocatableImpl;
|
||||
|
||||
template <typename DecoratorImplT, template <typename...> class List, typename... ArrayTs>
|
||||
struct IsDecoratorAllocatableImpl<DecoratorImplT, List<ArrayTs...>>
|
||||
{
|
||||
private:
|
||||
template <
|
||||
typename T,
|
||||
typename U = decltype(std::declval<T>().AllocateSourceArrays(0, std::declval<ArrayTs&>()...))>
|
||||
static std::true_type Exists(int);
|
||||
template <typename T>
|
||||
static std::false_type Exists(...);
|
||||
|
||||
public:
|
||||
using type = decltype(Exists<DecoratorImplT>(0));
|
||||
};
|
||||
|
||||
// Tests whether DecoratorImplT has a ShrinkSourceArrays(size, Arrays...) method.
|
||||
template <typename DecoratorImplT, typename ArrayList>
|
||||
struct IsDecoratorShrinkableImpl;
|
||||
|
||||
template <typename DecoratorImplT, template <typename...> class List, typename... ArrayTs>
|
||||
struct IsDecoratorShrinkableImpl<DecoratorImplT, List<ArrayTs...>>
|
||||
{
|
||||
private:
|
||||
template <
|
||||
typename T,
|
||||
typename U = decltype(std::declval<T>().ShrinkSourceArrays(0, std::declval<ArrayTs&>()...))>
|
||||
static std::true_type Exists(int);
|
||||
template <typename T>
|
||||
static std::false_type Exists(...);
|
||||
|
||||
public:
|
||||
using type = decltype(Exists<DecoratorImplT>(0));
|
||||
};
|
||||
|
||||
// Deduces the type returned by DecoratorImplT::CreateFunctor when given
|
||||
// the specified portals.
|
||||
template <typename DecoratorImplT, typename PortalList>
|
||||
@ -299,6 +338,18 @@ template <typename DecoratorImplT, typename PortalList>
|
||||
using IsFunctorInvertible =
|
||||
typename detail::IsFunctorInvertibleImpl<DecoratorImplT, PortalList>::type;
|
||||
|
||||
// Set to std::true_type if DecoratorImplT::AllocateSourceArrays can be called
|
||||
// with the supplied arrays, or std::false_type otherwise.
|
||||
template <typename DecoratorImplT, typename ArrayList>
|
||||
using IsDecoratorAllocatable =
|
||||
typename detail::IsDecoratorAllocatableImpl<DecoratorImplT, ArrayList>::type;
|
||||
|
||||
// Set to std::true_type if DecoratorImplT::ShrinkSourceArrays can be called
|
||||
// with the supplied arrays, or std::false_type otherwise.
|
||||
template <typename DecoratorImplT, typename ArrayList>
|
||||
using IsDecoratorShrinkable =
|
||||
typename detail::IsDecoratorShrinkableImpl<DecoratorImplT, ArrayList>::type;
|
||||
|
||||
// std::true_type/std::false_type depending on whether the decorator impl has a
|
||||
// CreateInversePortal method AND any of the arrays are writable.
|
||||
template <typename DecoratorImplT, typename PortalList>
|
||||
@ -368,6 +419,10 @@ struct DecoratorStorageTraits
|
||||
using IndexList = tao::seq::make_index_sequence<sizeof...(ArrayTs)>;
|
||||
#endif // VTKM_USE_TAO_SEQ
|
||||
|
||||
// true_type/false_type depending on whether the decorator supports Allocate/Shrink:
|
||||
using IsAllocatable = IsDecoratorAllocatable<DecoratorImplT, ArrayList>;
|
||||
using IsShrinkable = IsDecoratorShrinkable<DecoratorImplT, ArrayList>;
|
||||
|
||||
// Portal lists:
|
||||
// NOTE we have to pass the parameter pack here instead of using ArrayList
|
||||
// with brigand::transform, since that's causing MSVC 2015 to ice:
|
||||
@ -445,6 +500,41 @@ struct DecoratorStorageTraits
|
||||
return { impl.CreateFunctor(portals...), impl.CreateInverseFunctor(portals...), numVals };
|
||||
}
|
||||
|
||||
// Static dispatch for calling AllocateSourceArrays on supported implementations:
|
||||
VTKM_CONT[[noreturn]] static void CallAllocate(std::false_type,
|
||||
const DecoratorImplT&,
|
||||
vtkm::Id,
|
||||
ArrayTs&...)
|
||||
{
|
||||
throw vtkm::cont::ErrorBadType("Allocate not supported by this ArrayHandleDecorator.");
|
||||
}
|
||||
|
||||
VTKM_CONT static void CallAllocate(std::true_type,
|
||||
const DecoratorImplT& impl,
|
||||
vtkm::Id newSize,
|
||||
ArrayTs&... arrays)
|
||||
{
|
||||
impl.AllocateSourceArrays(newSize, arrays...);
|
||||
}
|
||||
|
||||
// Static dispatch for calling ShrinkSourceArrays on supported implementations.
|
||||
VTKM_CONT[[noreturn]] static void CallShrink(std::false_type,
|
||||
const DecoratorImplT&,
|
||||
vtkm::Id,
|
||||
ArrayTs&...)
|
||||
{
|
||||
throw vtkm::cont::ErrorBadType("Shrink not supported by this ArrayHandleDecorator.");
|
||||
}
|
||||
|
||||
VTKM_CONT static void CallShrink(std::true_type,
|
||||
const DecoratorImplT& impl,
|
||||
vtkm::Id newSize,
|
||||
ArrayTs&... arrays)
|
||||
{
|
||||
impl.ShrinkSourceArrays(newSize, arrays...);
|
||||
}
|
||||
|
||||
|
||||
#ifndef VTKM_USE_TAO_SEQ
|
||||
// Portal construction methods. These actually create portals.
|
||||
template <template <typename...> class List, typename... Indices>
|
||||
@ -526,7 +616,26 @@ struct DecoratorStorageTraits
|
||||
GetPortalOutput(vtkmstd::get<Indices{}.value>(arrays), dev)...);
|
||||
}
|
||||
|
||||
#else // VTKM_USE_TAO_SEQ
|
||||
template <template <typename...> class List, typename... Indices>
|
||||
VTKM_CONT static void AllocateSourceArrays(const DecoratorImplT& impl,
|
||||
ArrayTupleType& arrays,
|
||||
vtkm::Id numValues,
|
||||
List<Indices...>)
|
||||
{
|
||||
CallAllocate(IsAllocatable{}, impl, numValues, vtkmstd::get<Indices{}.value>(arrays)...);
|
||||
}
|
||||
|
||||
template <template <typename...> class List, typename... Indices>
|
||||
VTKM_CONT static void ShrinkSourceArrays(const DecoratorImplT& impl,
|
||||
ArrayTupleType& arrays,
|
||||
vtkm::Id numValues,
|
||||
List<Indices...>)
|
||||
{
|
||||
CallShrink(IsShrinkable{}, impl, numValues, vtkmstd::get<Indices{}.value>(arrays)...);
|
||||
}
|
||||
|
||||
#else // VTKM_USE_TAO_SEQ
|
||||
|
||||
// Portal construction methods. These actually create portals.
|
||||
template <template <typename, std::size_t...> class List, std::size_t... Indices>
|
||||
VTKM_CONT static PortalControlType MakePortalControl(const DecoratorImplT& impl,
|
||||
@ -580,6 +689,25 @@ struct DecoratorStorageTraits
|
||||
return CreatePortalDecorator<PortalExecutionType<Device>>(
|
||||
numValues, impl, GetPortalOutput(vtkmstd::get<Indices>(arrays), dev)...);
|
||||
}
|
||||
|
||||
template <template <typename, std::size_t...> class List, std::size_t... Indices>
|
||||
VTKM_CONT static void AllocateSourceArrays(const DecoratorImplT& impl,
|
||||
ArrayTupleType& arrays,
|
||||
vtkm::Id numValues,
|
||||
List<std::size_t, Indices...>)
|
||||
{
|
||||
CallAllocate(IsAllocatable{}, impl, numValues, vtkmstd::get<Indices>(arrays)...);
|
||||
}
|
||||
|
||||
template <template <typename, std::size_t...> class List, std::size_t... Indices>
|
||||
VTKM_CONT static void ShrinkSourceArrays(const DecoratorImplT& impl,
|
||||
ArrayTupleType& arrays,
|
||||
vtkm::Id numValues,
|
||||
List<std::size_t, Indices...>)
|
||||
{
|
||||
CallShrink(IsShrinkable{}, impl, numValues, vtkmstd::get<Indices>(arrays)...);
|
||||
}
|
||||
|
||||
#endif // VTKM_USE_TAO_SEQ
|
||||
};
|
||||
|
||||
@ -642,18 +770,21 @@ public:
|
||||
}
|
||||
|
||||
VTKM_CONT
|
||||
void Allocate(vtkm::Id)
|
||||
void Allocate(vtkm::Id numValues)
|
||||
{
|
||||
VTKM_ASSERT(this->Valid);
|
||||
// No-op. I suppose eventually we could pass numValues down to the
|
||||
// implementation class and let it do something intelligent.
|
||||
Traits::AllocateSourceArrays(this->Implementation, this->ArrayTuple, numValues, IndexList{});
|
||||
// If the above call doesn't throw, update our state.
|
||||
this->NumberOfValues = numValues;
|
||||
}
|
||||
|
||||
VTKM_CONT
|
||||
void Shrink(vtkm::Id)
|
||||
void Shrink(vtkm::Id numValues)
|
||||
{
|
||||
VTKM_ASSERT(this->Valid);
|
||||
// No-op. Again, could eventually be passed down to the implementation.
|
||||
Traits::ShrinkSourceArrays(this->Implementation, this->ArrayTuple, numValues, IndexList{});
|
||||
// If the above call doesn't throw, update our state.
|
||||
this->NumberOfValues = numValues;
|
||||
}
|
||||
|
||||
VTKM_CONT
|
||||
@ -778,10 +909,7 @@ public:
|
||||
}
|
||||
|
||||
VTKM_CONT
|
||||
void Shrink(vtkm::Id)
|
||||
{
|
||||
// no-op
|
||||
}
|
||||
void Shrink(vtkm::Id numValues) { this->Storage->Shrink(numValues); }
|
||||
|
||||
|
||||
VTKM_CONT
|
||||
@ -845,6 +973,31 @@ private:
|
||||
/// SomeInverseFunctor CreateInverseFunctor(Portal1Type portal1,
|
||||
/// Portal2Type portal2) const;
|
||||
///
|
||||
/// // Given a set of ArrayHandles and a size, implement what should happen
|
||||
/// // to the source ArrayHandles when Allocate() is called on the decorator
|
||||
/// // handle.
|
||||
/// //
|
||||
/// // AllocateSourceArrays is optional; if not provided, the
|
||||
/// // ArrayHandleDecorator will throw if its Allocate method is called. If
|
||||
/// // an implementation is present and doesn't throw, the
|
||||
/// // ArrayHandleDecorator's internal state is updated to show `size` as the
|
||||
/// // number of values.
|
||||
/// template <typename Array1Type, typename Array2Type>
|
||||
/// VTKM_CONT
|
||||
/// void AllocateSourceArrays(vtkm::Id size, Array1Type array1, Array2Type array2) const;
|
||||
///
|
||||
/// // Given a set of ArrayHandles and a size, implement what should happen to
|
||||
/// // the source ArrayHandles when Shrink() is called on the decorator handle.
|
||||
/// //
|
||||
/// // ShrinkSourceArrays is optional; if not provided, the
|
||||
/// // ArrayHandleDecorator will throw if its Shrink method is called. If
|
||||
/// // an implementation is present and doesn't throw, the
|
||||
/// // ArrayHandleDecorator's internal state is updated to show `size` as the
|
||||
/// // number of values.
|
||||
/// template <typename Array1Type, typename Array2Type>
|
||||
/// VTKM_CONT
|
||||
/// void ShrinkSourceArrays(vtkm::Id size, Array1Type array1, Array2Type array2) const;
|
||||
///
|
||||
/// };
|
||||
/// ```
|
||||
///
|
||||
|
@ -27,7 +27,7 @@ struct DecoratorTests
|
||||
{
|
||||
static constexpr vtkm::Id ARRAY_SIZE = 10;
|
||||
|
||||
// Decorator implemenation that demonstrates how to write invertible functors
|
||||
// Decorator implementation that demonstrates how to write invertible functors
|
||||
// that combine three array handles with complex access logic. The resulting
|
||||
// ArrayHandleDecorator can be both read from and written to.
|
||||
//
|
||||
@ -212,6 +212,69 @@ struct DecoratorTests
|
||||
}
|
||||
};
|
||||
|
||||
// Decorator implementation that combines two source arrays using the formula
|
||||
// `[source1] * 10 + [source2]` and supports resizing.
|
||||
template <typename ValueType>
|
||||
struct DecompositionDecorImpl
|
||||
{
|
||||
template <typename Portal1T, typename Portal2T>
|
||||
struct Functor
|
||||
{
|
||||
Portal1T Portal1;
|
||||
Portal2T Portal2;
|
||||
|
||||
VTKM_EXEC_CONT
|
||||
ValueType operator()(vtkm::Id idx) const
|
||||
{
|
||||
return static_cast<ValueType>(this->Portal1.Get(idx) * 10 + this->Portal2.Get(idx));
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Portal1T, typename Portal2T>
|
||||
struct InverseFunctor
|
||||
{
|
||||
Portal1T Portal1;
|
||||
Portal2T Portal2;
|
||||
|
||||
VTKM_EXEC_CONT
|
||||
void operator()(vtkm::Id idx, const ValueType& val) const
|
||||
{
|
||||
this->Portal1.Set(idx, static_cast<ValueType>(std::floor(val / 10)));
|
||||
this->Portal2.Set(idx, static_cast<ValueType>(std::fmod(val, 10)));
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Portal1T, typename Portal2T>
|
||||
VTKM_CONT Functor<typename std::decay<Portal1T>::type, typename std::decay<Portal2T>::type>
|
||||
CreateFunctor(Portal1T&& p1, Portal2T&& p2) const
|
||||
{
|
||||
return { std::forward<Portal1T>(p1), std::forward<Portal2T>(p2) };
|
||||
}
|
||||
|
||||
template <typename Portal1T, typename Portal2T>
|
||||
VTKM_CONT
|
||||
InverseFunctor<typename std::decay<Portal1T>::type, typename std::decay<Portal2T>::type>
|
||||
CreateInverseFunctor(Portal1T&& p1, Portal2T&& p2) const
|
||||
{
|
||||
return { std::forward<Portal1T>(p1), std::forward<Portal2T>(p2) };
|
||||
}
|
||||
|
||||
// Resize methods:
|
||||
template <typename Array1T, typename Array2T>
|
||||
VTKM_CONT void AllocateSourceArrays(vtkm::Id numVals, Array1T&& array1, Array2T&& array2) const
|
||||
{
|
||||
array1.Allocate(numVals);
|
||||
array2.Allocate(numVals);
|
||||
}
|
||||
|
||||
template <typename Array1T, typename Array2T>
|
||||
VTKM_CONT void ShrinkSourceArrays(vtkm::Id numVals, Array1T&& array1, Array2T&& array2) const
|
||||
{
|
||||
array1.Shrink(numVals);
|
||||
array2.Shrink(numVals);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename ValueType>
|
||||
void InversionTest() const
|
||||
{
|
||||
@ -374,24 +437,210 @@ struct DecoratorTests
|
||||
}
|
||||
}
|
||||
|
||||
template <typename ValueType>
|
||||
void DecompositionTest() const
|
||||
{
|
||||
vtkm::cont::ArrayHandle<ValueType> a1;
|
||||
vtkm::cont::ArrayHandle<ValueType> a2;
|
||||
auto decor =
|
||||
vtkm::cont::make_ArrayHandleDecorator(0, DecompositionDecorImpl<ValueType>{}, a1, a2);
|
||||
|
||||
VTKM_TEST_ASSERT(decor.GetNumberOfValues() == 0);
|
||||
|
||||
decor.Allocate(5);
|
||||
VTKM_TEST_ASSERT(decor.GetNumberOfValues() == 5);
|
||||
{
|
||||
auto decorPortal = decor.GetPortalControl();
|
||||
decorPortal.Set(0, 13);
|
||||
decorPortal.Set(1, 8);
|
||||
decorPortal.Set(2, 43);
|
||||
decorPortal.Set(3, 92);
|
||||
decorPortal.Set(4, 117);
|
||||
}
|
||||
|
||||
VTKM_TEST_ASSERT(a1.GetNumberOfValues() == 5);
|
||||
{
|
||||
auto a1Portal = a1.GetPortalConstControl();
|
||||
VTKM_TEST_ASSERT(test_equal(a1Portal.Get(0), 1));
|
||||
VTKM_TEST_ASSERT(test_equal(a1Portal.Get(1), 0));
|
||||
VTKM_TEST_ASSERT(test_equal(a1Portal.Get(2), 4));
|
||||
VTKM_TEST_ASSERT(test_equal(a1Portal.Get(3), 9));
|
||||
VTKM_TEST_ASSERT(test_equal(a1Portal.Get(4), 11));
|
||||
}
|
||||
|
||||
VTKM_TEST_ASSERT(a2.GetNumberOfValues() == 5);
|
||||
{
|
||||
auto a2Portal = a2.GetPortalConstControl();
|
||||
VTKM_TEST_ASSERT(test_equal(a2Portal.Get(0), 3));
|
||||
VTKM_TEST_ASSERT(test_equal(a2Portal.Get(1), 8));
|
||||
VTKM_TEST_ASSERT(test_equal(a2Portal.Get(2), 3));
|
||||
VTKM_TEST_ASSERT(test_equal(a2Portal.Get(3), 2));
|
||||
VTKM_TEST_ASSERT(test_equal(a2Portal.Get(4), 7));
|
||||
}
|
||||
|
||||
decor.Shrink(3);
|
||||
VTKM_TEST_ASSERT(decor.GetNumberOfValues() == 3);
|
||||
{
|
||||
auto decorPortal = decor.GetPortalConstControl();
|
||||
VTKM_TEST_ASSERT(test_equal(decorPortal.Get(0), 13));
|
||||
VTKM_TEST_ASSERT(test_equal(decorPortal.Get(1), 8));
|
||||
VTKM_TEST_ASSERT(test_equal(decorPortal.Get(2), 43));
|
||||
}
|
||||
|
||||
VTKM_TEST_ASSERT(a1.GetNumberOfValues() == 3);
|
||||
{
|
||||
auto a1Portal = a1.GetPortalConstControl();
|
||||
VTKM_TEST_ASSERT(test_equal(a1Portal.Get(0), 1));
|
||||
VTKM_TEST_ASSERT(test_equal(a1Portal.Get(1), 0));
|
||||
VTKM_TEST_ASSERT(test_equal(a1Portal.Get(2), 4));
|
||||
}
|
||||
|
||||
VTKM_TEST_ASSERT(a2.GetNumberOfValues() == 3);
|
||||
{
|
||||
auto a2Portal = a2.GetPortalConstControl();
|
||||
VTKM_TEST_ASSERT(test_equal(a2Portal.Get(0), 3));
|
||||
VTKM_TEST_ASSERT(test_equal(a2Portal.Get(1), 8));
|
||||
VTKM_TEST_ASSERT(test_equal(a2Portal.Get(2), 3));
|
||||
}
|
||||
}
|
||||
|
||||
template <typename ValueType>
|
||||
void operator()(const ValueType) const
|
||||
{
|
||||
InversionTest<ValueType>();
|
||||
this->InversionTest<ValueType>();
|
||||
|
||||
BinaryOperatorTest<ValueType, vtkm::Maximum>();
|
||||
BinaryOperatorTest<ValueType, vtkm::Minimum>();
|
||||
BinaryOperatorTest<ValueType, vtkm::Add>();
|
||||
BinaryOperatorTest<ValueType, vtkm::Subtract>();
|
||||
BinaryOperatorTest<ValueType, vtkm::Multiply>();
|
||||
this->BinaryOperatorTest<ValueType, vtkm::Maximum>();
|
||||
this->BinaryOperatorTest<ValueType, vtkm::Minimum>();
|
||||
this->BinaryOperatorTest<ValueType, vtkm::Add>();
|
||||
this->BinaryOperatorTest<ValueType, vtkm::Subtract>();
|
||||
this->BinaryOperatorTest<ValueType, vtkm::Multiply>();
|
||||
|
||||
ScanExtendedToNumIndicesTest<ValueType>();
|
||||
this->ScanExtendedToNumIndicesTest<ValueType>();
|
||||
|
||||
this->DecompositionTest<ValueType>();
|
||||
}
|
||||
};
|
||||
|
||||
// ArrayHandleDecorator that implements AllocateSourceArrays and ShrinkSourceArrays, thus allowing
|
||||
// it to be resized.
|
||||
struct ResizableDecorImpl
|
||||
{
|
||||
// We don't actually read/write from this, so use a dummy functor:
|
||||
struct Functor
|
||||
{
|
||||
VTKM_EXEC_CONT vtkm::Id operator()(vtkm::Id) const { return 0; }
|
||||
};
|
||||
|
||||
template <typename... PortalTs>
|
||||
VTKM_CONT Functor CreateFunctor(PortalTs...) const
|
||||
{
|
||||
return Functor{};
|
||||
}
|
||||
|
||||
template <typename Array1T, typename Array2T>
|
||||
void ShrinkSourceArrays(vtkm::Id newSize, Array1T& a1, Array2T& a2) const
|
||||
{
|
||||
VTKM_IS_ARRAY_HANDLE(Array1T);
|
||||
VTKM_IS_ARRAY_HANDLE(Array2T);
|
||||
|
||||
// Resize each to 2*newSize:
|
||||
a1.Shrink(2 * newSize);
|
||||
a2.Shrink(2 * newSize);
|
||||
}
|
||||
|
||||
template <typename Array1T, typename Array2T>
|
||||
void AllocateSourceArrays(vtkm::Id newSize, Array1T& a1, Array2T& a2) const
|
||||
{
|
||||
VTKM_IS_ARRAY_HANDLE(Array1T);
|
||||
VTKM_IS_ARRAY_HANDLE(Array2T);
|
||||
|
||||
// Resize each to 3*newSize:
|
||||
a1.Allocate(3 * newSize);
|
||||
a2.Allocate(3 * newSize);
|
||||
}
|
||||
};
|
||||
|
||||
// ArrayHandleDecorator that implements AllocateSourceArrays and ShrinkSourceArrays, thus allowing
|
||||
// it to be resized.
|
||||
struct NonResizableDecorImpl
|
||||
{
|
||||
// We don't actually read/write from this, so use a dummy functor:
|
||||
struct Functor
|
||||
{
|
||||
VTKM_EXEC_CONT vtkm::Id operator()(vtkm::Id) const { return 0; }
|
||||
};
|
||||
|
||||
template <typename... PortalTs>
|
||||
VTKM_CONT Functor CreateFunctor(PortalTs...) const
|
||||
{
|
||||
return Functor{};
|
||||
}
|
||||
};
|
||||
|
||||
void ResizeTest()
|
||||
{
|
||||
{
|
||||
vtkm::cont::ArrayHandle<vtkm::Id> a1;
|
||||
vtkm::cont::ArrayHandle<vtkm::Id> a2;
|
||||
ResizableDecorImpl impl;
|
||||
|
||||
auto decor = vtkm::cont::make_ArrayHandleDecorator(5, impl, a1, a2);
|
||||
VTKM_TEST_ASSERT(decor.GetNumberOfValues() == 5);
|
||||
|
||||
decor.Allocate(10); // Should allocate a1&a2 to have 30 values:
|
||||
VTKM_TEST_ASSERT(a1.GetNumberOfValues() == 30);
|
||||
VTKM_TEST_ASSERT(a2.GetNumberOfValues() == 30);
|
||||
VTKM_TEST_ASSERT(decor.GetNumberOfValues() == 10);
|
||||
decor.Shrink(3); // Should resize a1&a2 to have 6 values:
|
||||
VTKM_TEST_ASSERT(a1.GetNumberOfValues() == 6);
|
||||
VTKM_TEST_ASSERT(a2.GetNumberOfValues() == 6);
|
||||
VTKM_TEST_ASSERT(decor.GetNumberOfValues() == 3);
|
||||
}
|
||||
|
||||
{
|
||||
vtkm::cont::ArrayHandle<vtkm::Id> a1;
|
||||
a1.Allocate(20);
|
||||
vtkm::cont::ArrayHandle<vtkm::Id> a2;
|
||||
a2.Allocate(20);
|
||||
NonResizableDecorImpl impl;
|
||||
|
||||
auto decor = vtkm::cont::make_ArrayHandleDecorator(5, impl, a1, a2);
|
||||
VTKM_TEST_ASSERT(decor.GetNumberOfValues() == 5);
|
||||
|
||||
// Allocate and Shrink should throw an ErrorBadType:
|
||||
bool threw = false;
|
||||
try
|
||||
{
|
||||
decor.Allocate(10);
|
||||
}
|
||||
catch (vtkm::cont::ErrorBadType& e)
|
||||
{
|
||||
std::cerr << "Caught expected exception: " << e.what() << "\n";
|
||||
threw = true;
|
||||
}
|
||||
VTKM_TEST_ASSERT(threw, "Allocate did not throw as expected.");
|
||||
VTKM_TEST_ASSERT(decor.GetNumberOfValues() == 5);
|
||||
|
||||
threw = false;
|
||||
try
|
||||
{
|
||||
decor.Shrink(3);
|
||||
}
|
||||
catch (vtkm::cont::ErrorBadType& e)
|
||||
{
|
||||
std::cerr << "Caught expected exception: " << e.what() << "\n";
|
||||
threw = true;
|
||||
}
|
||||
VTKM_TEST_ASSERT(threw, "Allocate did not throw as expected.");
|
||||
VTKM_TEST_ASSERT(decor.GetNumberOfValues() == 5);
|
||||
}
|
||||
}
|
||||
|
||||
void TestArrayHandleDecorator()
|
||||
{
|
||||
vtkm::testing::Testing::TryTypes(DecoratorTests{}, vtkm::TypeListScalarAll{});
|
||||
|
||||
ResizeTest();
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
Loading…
Reference in New Issue
Block a user