mirror of
https://gitlab.kitware.com/vtk/vtk-m
synced 2024-09-08 13:23:51 +00:00
Consolidate UnitTestArrayHandle
Previously, each device adapter implementation had their own version of this test by including a common header. Simplify this by making a single test in UnitTests_vtkm_cont_testing, which can now be compiled for and tested on a device.
This commit is contained in:
parent
b4e6370e9e
commit
2a0e92c63e
@ -9,7 +9,6 @@
|
||||
##============================================================================
|
||||
|
||||
set(unit_tests
|
||||
UnitTestCudaArrayHandle.cu
|
||||
UnitTestCudaArrayHandleFancy.cu
|
||||
UnitTestCudaArrayHandleMultiplexer.cu
|
||||
UnitTestCudaBitField.cu
|
||||
|
@ -1,20 +0,0 @@
|
||||
//============================================================================
|
||||
// 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.
|
||||
//============================================================================
|
||||
|
||||
#include <vtkm/cont/cuda/DeviceAdapterCuda.h>
|
||||
#include <vtkm/cont/testing/TestingArrayHandles.h>
|
||||
|
||||
int UnitTestCudaArrayHandle(int argc, char* argv[])
|
||||
{
|
||||
auto& tracker = vtkm::cont::GetRuntimeDeviceTracker();
|
||||
tracker.ForceDevice(vtkm::cont::DeviceAdapterTagCuda{});
|
||||
return vtkm::cont::testing::TestingArrayHandles<vtkm::cont::DeviceAdapterTagCuda>::Run(argc,
|
||||
argv);
|
||||
}
|
@ -9,7 +9,6 @@
|
||||
##============================================================================
|
||||
|
||||
set(unit_tests
|
||||
UnitTestKokkosArrayHandle.cxx
|
||||
UnitTestKokkosArrayHandleFancy.cxx
|
||||
UnitTestKokkosArrayHandleMultiplexer.cxx
|
||||
UnitTestKokkosBitField.cxx
|
||||
|
@ -1,20 +0,0 @@
|
||||
//============================================================================
|
||||
// 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.
|
||||
//============================================================================
|
||||
|
||||
#include <vtkm/cont/kokkos/DeviceAdapterKokkos.h>
|
||||
#include <vtkm/cont/testing/TestingArrayHandles.h>
|
||||
|
||||
int UnitTestKokkosArrayHandle(int argc, char* argv[])
|
||||
{
|
||||
auto& tracker = vtkm::cont::GetRuntimeDeviceTracker();
|
||||
tracker.ForceDevice(vtkm::cont::DeviceAdapterTagKokkos{});
|
||||
return vtkm::cont::testing::TestingArrayHandles<vtkm::cont::DeviceAdapterTagKokkos>::Run(argc,
|
||||
argv);
|
||||
}
|
@ -9,7 +9,6 @@
|
||||
##============================================================================
|
||||
|
||||
set(unit_tests
|
||||
UnitTestOpenMPArrayHandle.cxx
|
||||
UnitTestOpenMPArrayHandleFancy.cxx
|
||||
UnitTestOpenMPArrayHandleMultiplexer.cxx
|
||||
UnitTestOpenMPBitField.cxx
|
||||
|
@ -1,19 +0,0 @@
|
||||
//============================================================================
|
||||
// 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.
|
||||
//============================================================================
|
||||
#include <vtkm/cont/openmp/DeviceAdapterOpenMP.h>
|
||||
#include <vtkm/cont/testing/TestingArrayHandles.h>
|
||||
|
||||
int UnitTestOpenMPArrayHandle(int argc, char* argv[])
|
||||
{
|
||||
auto& tracker = vtkm::cont::GetRuntimeDeviceTracker();
|
||||
tracker.ForceDevice(vtkm::cont::DeviceAdapterTagOpenMP{});
|
||||
return vtkm::cont::testing::TestingArrayHandles<vtkm::cont::DeviceAdapterTagOpenMP>::Run(argc,
|
||||
argv);
|
||||
}
|
@ -9,7 +9,6 @@
|
||||
##============================================================================
|
||||
|
||||
set(unit_tests
|
||||
UnitTestSerialArrayHandle.cxx
|
||||
UnitTestSerialArrayHandleFancy.cxx
|
||||
UnitTestSerialArrayHandleMultiplexer.cxx
|
||||
UnitTestSerialBitField.cxx
|
||||
|
@ -1,20 +0,0 @@
|
||||
//============================================================================
|
||||
// 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.
|
||||
//============================================================================
|
||||
|
||||
#include <vtkm/cont/serial/DeviceAdapterSerial.h>
|
||||
#include <vtkm/cont/testing/TestingArrayHandles.h>
|
||||
|
||||
int UnitTestSerialArrayHandle(int argc, char* argv[])
|
||||
{
|
||||
auto& tracker = vtkm::cont::GetRuntimeDeviceTracker();
|
||||
tracker.ForceDevice(vtkm::cont::DeviceAdapterTagSerial{});
|
||||
return vtkm::cont::testing::TestingArrayHandles<vtkm::cont::DeviceAdapterTagSerial>::Run(argc,
|
||||
argv);
|
||||
}
|
@ -9,7 +9,6 @@
|
||||
##============================================================================
|
||||
|
||||
set(unit_tests
|
||||
UnitTestTBBArrayHandle.cxx
|
||||
UnitTestTBBArrayHandleFancy.cxx
|
||||
UnitTestTBBArrayHandleMultiplexer.cxx
|
||||
UnitTestTBBBitField.cxx
|
||||
|
@ -1,19 +0,0 @@
|
||||
//============================================================================
|
||||
// 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.
|
||||
//============================================================================
|
||||
|
||||
#include <vtkm/cont/tbb/DeviceAdapterTBB.h>
|
||||
#include <vtkm/cont/testing/TestingArrayHandles.h>
|
||||
|
||||
int UnitTestTBBArrayHandle(int argc, char* argv[])
|
||||
{
|
||||
auto& tracker = vtkm::cont::GetRuntimeDeviceTracker();
|
||||
tracker.ForceDevice(vtkm::cont::DeviceAdapterTagTBB{});
|
||||
return vtkm::cont::testing::TestingArrayHandles<vtkm::cont::DeviceAdapterTagTBB>::Run(argc, argv);
|
||||
}
|
@ -12,7 +12,6 @@ set(headers
|
||||
ExplicitTestData.h
|
||||
MakeTestDataSet.h
|
||||
Testing.h
|
||||
TestingArrayHandles.h
|
||||
TestingArrayHandleMultiplexer.h
|
||||
TestingCellLocatorRectilinearGrid.h
|
||||
TestingCellLocatorTwoLevel.h
|
||||
@ -82,6 +81,7 @@ set(unit_tests
|
||||
set(unit_tests_device
|
||||
UnitTestAlgorithm.cxx
|
||||
UnitTestArrayCopy.cxx
|
||||
UnitTestArrayHandle.cxx
|
||||
UnitTestArrayHandleDecorator.cxx
|
||||
UnitTestArrayHandleExtractComponent.cxx
|
||||
UnitTestArrayHandlePermutation.cxx
|
||||
|
@ -1,764 +0,0 @@
|
||||
//============================================================================
|
||||
// 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.
|
||||
//============================================================================
|
||||
#ifndef vtk_m_cont_testing_TestingArrayHandles_h
|
||||
#define vtk_m_cont_testing_TestingArrayHandles_h
|
||||
|
||||
#include <vtkm/TypeTraits.h>
|
||||
#include <vtkm/cont/ArrayHandle.h>
|
||||
#include <vtkm/cont/RuntimeDeviceTracker.h>
|
||||
|
||||
#include <vtkm/worklet/DispatcherMapField.h>
|
||||
#include <vtkm/worklet/WorkletMapField.h>
|
||||
|
||||
#include <vtkm/cont/ArrayHandleExtractComponent.h>
|
||||
#include <vtkm/cont/testing/Testing.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <vector>
|
||||
|
||||
namespace vtkm
|
||||
{
|
||||
namespace cont
|
||||
{
|
||||
namespace testing
|
||||
{
|
||||
|
||||
namespace array_handle_testing
|
||||
{
|
||||
template <class IteratorType, typename T>
|
||||
void CheckValues(IteratorType begin, IteratorType end, T)
|
||||
{
|
||||
|
||||
vtkm::Id index = 0;
|
||||
for (IteratorType iter = begin; iter != end; iter++)
|
||||
{
|
||||
T expectedValue = TestValue(index, T());
|
||||
if (!test_equal(*iter, expectedValue))
|
||||
{
|
||||
std::stringstream message;
|
||||
message << "Got unexpected value in array." << std::endl
|
||||
<< "Expected: " << expectedValue << ", Found: " << *iter << std::endl;
|
||||
VTKM_TEST_FAIL(message.str().c_str());
|
||||
}
|
||||
|
||||
index++;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void CheckArray(const vtkm::cont::ArrayHandle<T>& handle)
|
||||
{
|
||||
CheckPortal(handle.ReadPortal());
|
||||
}
|
||||
}
|
||||
|
||||
// Use to get an arbitrarily different valuetype than T:
|
||||
template <typename T>
|
||||
struct OtherType
|
||||
{
|
||||
using Type = vtkm::Int32;
|
||||
};
|
||||
template <>
|
||||
struct OtherType<vtkm::Int32>
|
||||
{
|
||||
using Type = vtkm::UInt8;
|
||||
};
|
||||
|
||||
/// This class has a single static member, Run, that tests that all Fancy Array
|
||||
/// Handles work with the given DeviceAdapter
|
||||
///
|
||||
template <class DeviceAdapterTag>
|
||||
struct TestingArrayHandles
|
||||
{
|
||||
// Make sure deprecated types still work (while applicable)
|
||||
VTKM_DEPRECATED_SUPPRESS_BEGIN
|
||||
VTKM_STATIC_ASSERT(
|
||||
(std::is_same<typename vtkm::cont::ArrayHandle<vtkm::Id>::ReadPortalType,
|
||||
typename vtkm::cont::ArrayHandle<vtkm::Id>::template ExecutionTypes<
|
||||
DeviceAdapterTag>::PortalConst>::value));
|
||||
VTKM_STATIC_ASSERT((std::is_same<typename vtkm::cont::ArrayHandle<vtkm::Id>::WritePortalType,
|
||||
typename vtkm::cont::ArrayHandle<vtkm::Id>::
|
||||
template ExecutionTypes<DeviceAdapterTag>::Portal>::value));
|
||||
VTKM_DEPRECATED_SUPPRESS_END
|
||||
|
||||
template <typename PortalType>
|
||||
struct PortalExecObjectWrapper : vtkm::cont::ExecutionObjectBase
|
||||
{
|
||||
PortalType Portal;
|
||||
PortalExecObjectWrapper(const PortalType& portal)
|
||||
: Portal(portal)
|
||||
{
|
||||
}
|
||||
|
||||
PortalType PrepareForExecution(DeviceAdapterTag, vtkm::cont::Token&) const
|
||||
{
|
||||
return this->Portal;
|
||||
}
|
||||
|
||||
template <typename OtherDevice>
|
||||
PortalType PrepareForExecution(OtherDevice, vtkm::cont::Token&) const
|
||||
{
|
||||
VTKM_TEST_FAIL("Executing on wrong device.");
|
||||
return this->Portal;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename PortalType>
|
||||
static PortalExecObjectWrapper<PortalType> WrapPortal(const PortalType& portal)
|
||||
{
|
||||
return PortalExecObjectWrapper<PortalType>(portal);
|
||||
}
|
||||
|
||||
struct PassThrough : public vtkm::worklet::WorkletMapField
|
||||
{
|
||||
using ControlSignature = void(FieldIn, ExecObject, FieldOut);
|
||||
using ExecutionSignature = _3(_2, InputIndex);
|
||||
|
||||
template <typename PortalType>
|
||||
VTKM_EXEC typename PortalType::ValueType operator()(const PortalType& portal,
|
||||
vtkm::Id index) const
|
||||
{
|
||||
return portal.Get(index);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T, typename ExecutionPortalType>
|
||||
struct AssignTestValue : public vtkm::exec::FunctorBase
|
||||
{
|
||||
ExecutionPortalType Portal;
|
||||
VTKM_CONT
|
||||
AssignTestValue(ExecutionPortalType p)
|
||||
: Portal(p)
|
||||
{
|
||||
}
|
||||
|
||||
VTKM_EXEC
|
||||
void operator()(vtkm::Id index) const { this->Portal.Set(index, TestValue(index, T())); }
|
||||
};
|
||||
|
||||
template <typename T, typename ExecutionPortalType>
|
||||
struct InplaceFunctor : public vtkm::exec::FunctorBase
|
||||
{
|
||||
ExecutionPortalType Portal;
|
||||
VTKM_CONT
|
||||
InplaceFunctor(const ExecutionPortalType& p)
|
||||
: Portal(p)
|
||||
{
|
||||
}
|
||||
|
||||
VTKM_EXEC
|
||||
void operator()(vtkm::Id index) const
|
||||
{
|
||||
this->Portal.Set(index, T(this->Portal.Get(index) + T(1)));
|
||||
}
|
||||
};
|
||||
|
||||
private:
|
||||
static constexpr vtkm::Id ARRAY_SIZE = 100;
|
||||
|
||||
using Algorithm = vtkm::cont::DeviceAdapterAlgorithm<DeviceAdapterTag>;
|
||||
|
||||
using DispatcherPassThrough = vtkm::worklet::DispatcherMapField<PassThrough>;
|
||||
struct VerifyEmptyArrays
|
||||
{
|
||||
template <typename T>
|
||||
VTKM_CONT void operator()(T) const
|
||||
{
|
||||
std::cout << "Try operations on empty arrays." << std::endl;
|
||||
// After each operation, reinitialize array in case something gets
|
||||
// allocated.
|
||||
vtkm::cont::ArrayHandle<T> arrayHandle = vtkm::cont::ArrayHandle<T>();
|
||||
VTKM_TEST_ASSERT(arrayHandle.GetNumberOfValues() == 0,
|
||||
"Uninitialized array does not report zero values.");
|
||||
arrayHandle = vtkm::cont::ArrayHandle<T>();
|
||||
VTKM_TEST_ASSERT(arrayHandle.ReadPortal().GetNumberOfValues() == 0,
|
||||
"Uninitialized array does not give portal with zero values.");
|
||||
vtkm::cont::Token token;
|
||||
arrayHandle = vtkm::cont::ArrayHandle<T>();
|
||||
arrayHandle.Allocate(0, vtkm::CopyFlag::On);
|
||||
arrayHandle = vtkm::cont::ArrayHandle<T>();
|
||||
arrayHandle.ReleaseResourcesExecution();
|
||||
arrayHandle = vtkm::cont::ArrayHandle<T>();
|
||||
arrayHandle.ReleaseResources();
|
||||
arrayHandle = vtkm::cont::make_ArrayHandleMove(std::vector<T>());
|
||||
arrayHandle.PrepareForInput(DeviceAdapterTag(), token);
|
||||
arrayHandle = vtkm::cont::ArrayHandle<T>();
|
||||
arrayHandle.PrepareForInPlace(DeviceAdapterTag(), token);
|
||||
arrayHandle = vtkm::cont::ArrayHandle<T>();
|
||||
arrayHandle.PrepareForOutput(ARRAY_SIZE, DeviceAdapterTag(), token);
|
||||
}
|
||||
};
|
||||
|
||||
struct VerifyUserOwnedMemory
|
||||
{
|
||||
template <typename T>
|
||||
VTKM_CONT void operator()(T) const
|
||||
{
|
||||
std::cout << "Creating array with user-allocated memory." << std::endl;
|
||||
std::vector<T> buffer(ARRAY_SIZE);
|
||||
for (vtkm::Id index = 0; index < ARRAY_SIZE; index++)
|
||||
{
|
||||
buffer[static_cast<std::size_t>(index)] = TestValue(index, T());
|
||||
}
|
||||
|
||||
vtkm::cont::ArrayHandle<T> arrayHandle =
|
||||
vtkm::cont::make_ArrayHandle(buffer, vtkm::CopyFlag::Off);
|
||||
|
||||
VTKM_TEST_ASSERT(arrayHandle.GetNumberOfValues() == ARRAY_SIZE,
|
||||
"ArrayHandle has wrong number of entries.");
|
||||
|
||||
std::cout << "Check array with user provided memory." << std::endl;
|
||||
array_handle_testing::CheckArray(arrayHandle);
|
||||
|
||||
std::cout << "Check out execution array behavior." << std::endl;
|
||||
{ //as input
|
||||
vtkm::cont::Token token;
|
||||
typename vtkm::cont::ArrayHandle<T>::ReadPortalType executionPortal =
|
||||
arrayHandle.PrepareForInput(DeviceAdapterTag(), token);
|
||||
token.DetachFromAll();
|
||||
static_cast<void>(executionPortal);
|
||||
|
||||
//use a worklet to verify the input transfer worked properly
|
||||
vtkm::cont::ArrayHandle<T> result;
|
||||
DispatcherPassThrough().Invoke(arrayHandle, WrapPortal(executionPortal), result);
|
||||
array_handle_testing::CheckArray(result);
|
||||
}
|
||||
|
||||
std::cout << "Check out inplace." << std::endl;
|
||||
{ //as inplace
|
||||
vtkm::cont::Token token;
|
||||
typename vtkm::cont::ArrayHandle<T>::WritePortalType executionPortal =
|
||||
arrayHandle.PrepareForInPlace(DeviceAdapterTag(), token);
|
||||
token.DetachFromAll();
|
||||
static_cast<void>(executionPortal);
|
||||
|
||||
//use a worklet to verify the inplace transfer worked properly
|
||||
vtkm::cont::ArrayHandle<T> result;
|
||||
DispatcherPassThrough().Invoke(arrayHandle, WrapPortal(executionPortal), result);
|
||||
array_handle_testing::CheckArray(result);
|
||||
}
|
||||
|
||||
//clear out user array for next test
|
||||
std::fill(buffer.begin(), buffer.end(), static_cast<T>(-1));
|
||||
|
||||
std::cout << "Check out output." << std::endl;
|
||||
{ //as output with same length as user provided. This should work
|
||||
//as no new memory needs to be allocated
|
||||
vtkm::cont::Token token;
|
||||
auto outputPortal = arrayHandle.PrepareForOutput(ARRAY_SIZE, DeviceAdapterTag(), token);
|
||||
|
||||
//fill array on device
|
||||
Algorithm::Schedule(AssignTestValue<T, decltype(outputPortal)>{ outputPortal }, ARRAY_SIZE);
|
||||
|
||||
//sync data, which should fill up the user buffer
|
||||
token.DetachFromAll();
|
||||
arrayHandle.SyncControlArray();
|
||||
|
||||
//check that we got the proper values in the user array
|
||||
array_handle_testing::CheckValues(buffer.begin(), buffer.end(), T{});
|
||||
}
|
||||
|
||||
{ //as output with a length larger than the memory provided by the user
|
||||
//this should fail
|
||||
bool gotException = false;
|
||||
try
|
||||
{
|
||||
//you should not be able to allocate a size larger than the
|
||||
//user provided and get the results
|
||||
vtkm::cont::Token token;
|
||||
arrayHandle.PrepareForOutput(ARRAY_SIZE * 2, DeviceAdapterTag(), token);
|
||||
token.DetachFromAll();
|
||||
arrayHandle.WritePortal();
|
||||
}
|
||||
catch (vtkm::cont::Error&)
|
||||
{
|
||||
gotException = true;
|
||||
}
|
||||
VTKM_TEST_ASSERT(gotException,
|
||||
"PrepareForOutput should fail when asked to "
|
||||
"re-allocate user provided memory.");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
struct VerifyUserTransferredMemory
|
||||
{
|
||||
template <typename T>
|
||||
VTKM_CONT void operator()(T) const
|
||||
{
|
||||
T* buffer = new T[ARRAY_SIZE];
|
||||
for (vtkm::Id index = 0; index < ARRAY_SIZE; index++)
|
||||
{
|
||||
buffer[static_cast<std::size_t>(index)] = TestValue(index, T());
|
||||
}
|
||||
|
||||
auto user_free_function = [](void* ptr) { delete[] static_cast<T*>(ptr); };
|
||||
vtkm::cont::ArrayHandleBasic<T> arrayHandle(buffer, ARRAY_SIZE, user_free_function);
|
||||
|
||||
VTKM_TEST_ASSERT(arrayHandle.GetNumberOfValues() == ARRAY_SIZE,
|
||||
"ArrayHandle has wrong number of entries.");
|
||||
|
||||
std::cout << "Check array with user transferred memory." << std::endl;
|
||||
array_handle_testing::CheckArray(arrayHandle);
|
||||
|
||||
std::cout << "Check out execution array behavior." << std::endl;
|
||||
{ //as input
|
||||
vtkm::cont::Token token;
|
||||
typename vtkm::cont::ArrayHandle<T>::ReadPortalType executionPortal =
|
||||
arrayHandle.PrepareForInput(DeviceAdapterTag(), token);
|
||||
token.DetachFromAll();
|
||||
static_cast<void>(executionPortal);
|
||||
|
||||
//use a worklet to verify the input transfer worked properly
|
||||
vtkm::cont::ArrayHandle<T> result;
|
||||
DispatcherPassThrough().Invoke(arrayHandle, WrapPortal(executionPortal), result);
|
||||
array_handle_testing::CheckArray(result);
|
||||
}
|
||||
|
||||
std::cout << "Check out inplace." << std::endl;
|
||||
{ //as inplace
|
||||
vtkm::cont::Token token;
|
||||
typename vtkm::cont::ArrayHandle<T>::WritePortalType executionPortal =
|
||||
arrayHandle.PrepareForInPlace(DeviceAdapterTag(), token);
|
||||
token.DetachFromAll();
|
||||
static_cast<void>(executionPortal);
|
||||
|
||||
//use a worklet to verify the inplace transfer worked properly
|
||||
vtkm::cont::ArrayHandle<T> result;
|
||||
DispatcherPassThrough().Invoke(arrayHandle, WrapPortal(executionPortal), result);
|
||||
array_handle_testing::CheckArray(result);
|
||||
}
|
||||
|
||||
std::cout << "Check out output." << std::endl;
|
||||
{ //as output with same length as user provided. This should work
|
||||
//as no new memory needs to be allocated
|
||||
vtkm::cont::Token token;
|
||||
arrayHandle.PrepareForOutput(ARRAY_SIZE, DeviceAdapterTag(), token);
|
||||
token.DetachFromAll();
|
||||
|
||||
//we can't verify output contents as those aren't fetched, we
|
||||
//can just make sure the allocation didn't throw an exception
|
||||
}
|
||||
|
||||
{ //as output with a length larger than the memory provided by the user
|
||||
//this should fail
|
||||
bool gotException = false;
|
||||
try
|
||||
{
|
||||
//you should not be able to allocate a size larger than the
|
||||
//user provided and get the results
|
||||
vtkm::cont::Token token;
|
||||
arrayHandle.PrepareForOutput(ARRAY_SIZE * 2, DeviceAdapterTag(), token);
|
||||
token.DetachFromAll();
|
||||
arrayHandle.WritePortal();
|
||||
}
|
||||
catch (vtkm::cont::Error&)
|
||||
{
|
||||
gotException = true;
|
||||
}
|
||||
VTKM_TEST_ASSERT(gotException,
|
||||
"PrepareForOutput should fail when asked to "
|
||||
"re-allocate user provided memory.");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
struct VerifyVectorMovedMemory
|
||||
{
|
||||
template <typename T>
|
||||
VTKM_CONT void operator()(T) const
|
||||
{
|
||||
std::cout << "Creating moved std::vector memory." << std::endl;
|
||||
std::vector<T> buffer(ARRAY_SIZE);
|
||||
for (vtkm::Id index = 0; index < ARRAY_SIZE; index++)
|
||||
{
|
||||
buffer[static_cast<std::size_t>(index)] = TestValue(index, T());
|
||||
}
|
||||
|
||||
vtkm::cont::ArrayHandle<T> arrayHandle = vtkm::cont::make_ArrayHandleMove(std::move(buffer));
|
||||
// buffer is now invalid
|
||||
|
||||
VTKM_TEST_ASSERT(arrayHandle.GetNumberOfValues() == ARRAY_SIZE,
|
||||
"ArrayHandle has wrong number of entries.");
|
||||
|
||||
std::cout << "Check array with moved std::vector memory." << std::endl;
|
||||
array_handle_testing::CheckArray(arrayHandle);
|
||||
|
||||
std::cout << "Check out execution array behavior." << std::endl;
|
||||
{ //as input
|
||||
vtkm::cont::Token token;
|
||||
typename vtkm::cont::ArrayHandle<T>::ReadPortalType executionPortal;
|
||||
executionPortal = arrayHandle.PrepareForInput(DeviceAdapterTag(), token);
|
||||
token.DetachFromAll();
|
||||
|
||||
//use a worklet to verify the input transfer worked properly
|
||||
vtkm::cont::ArrayHandle<T> result;
|
||||
DispatcherPassThrough().Invoke(arrayHandle, WrapPortal(executionPortal), result);
|
||||
array_handle_testing::CheckArray(result);
|
||||
}
|
||||
|
||||
std::cout << "Check out inplace." << std::endl;
|
||||
{ //as inplace
|
||||
vtkm::cont::Token token;
|
||||
typename vtkm::cont::ArrayHandle<T>::WritePortalType executionPortal;
|
||||
executionPortal = arrayHandle.PrepareForInPlace(DeviceAdapterTag(), token);
|
||||
token.DetachFromAll();
|
||||
|
||||
//use a worklet to verify the inplace transfer worked properly
|
||||
vtkm::cont::ArrayHandle<T> result;
|
||||
DispatcherPassThrough().Invoke(arrayHandle, WrapPortal(executionPortal), result);
|
||||
array_handle_testing::CheckArray(result);
|
||||
}
|
||||
|
||||
std::cout << "Check out output." << std::endl;
|
||||
{ //as output with same length as user provided. This should work
|
||||
//as no new memory needs to be allocated
|
||||
vtkm::cont::Token token;
|
||||
arrayHandle.PrepareForOutput(ARRAY_SIZE, DeviceAdapterTag(), token);
|
||||
token.DetachFromAll();
|
||||
|
||||
//we can't verify output contents as those aren't fetched, we
|
||||
//can just make sure the allocation didn't throw an exception
|
||||
}
|
||||
|
||||
{ //as a vector moved to the ArrayHandle, reallocation should be possible
|
||||
vtkm::cont::Token token;
|
||||
arrayHandle.PrepareForOutput(ARRAY_SIZE * 2, DeviceAdapterTag(), token);
|
||||
token.DetachFromAll();
|
||||
|
||||
//we can't verify output contents as those aren't fetched, we
|
||||
//can just make sure the allocation didn't throw an exception
|
||||
VTKM_TEST_ASSERT(arrayHandle.GetNumberOfValues() == ARRAY_SIZE * 2);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
struct VerifyInitializerList
|
||||
{
|
||||
template <typename T>
|
||||
VTKM_CONT void operator()(T) const
|
||||
{
|
||||
std::cout << "Creating array with initializer list memory." << std::endl;
|
||||
vtkm::cont::ArrayHandle<T> arrayHandle =
|
||||
vtkm::cont::make_ArrayHandle({ TestValue(0, T()), TestValue(1, T()), TestValue(2, T()) });
|
||||
|
||||
VTKM_TEST_ASSERT(arrayHandle.GetNumberOfValues() == 3,
|
||||
"ArrayHandle has wrong number of entries.");
|
||||
|
||||
std::cout << "Check array with initializer list memory." << std::endl;
|
||||
array_handle_testing::CheckArray(arrayHandle);
|
||||
|
||||
std::cout << "Check out execution array behavior." << std::endl;
|
||||
{ //as input
|
||||
vtkm::cont::Token token;
|
||||
typename vtkm::cont::ArrayHandle<T>::ReadPortalType executionPortal;
|
||||
executionPortal = arrayHandle.PrepareForInput(DeviceAdapterTag(), token);
|
||||
token.DetachFromAll();
|
||||
|
||||
//use a worklet to verify the input transfer worked properly
|
||||
vtkm::cont::ArrayHandle<T> result;
|
||||
DispatcherPassThrough().Invoke(arrayHandle, WrapPortal(executionPortal), result);
|
||||
array_handle_testing::CheckArray(result);
|
||||
}
|
||||
|
||||
std::cout << "Check out inplace." << std::endl;
|
||||
{ //as inplace
|
||||
vtkm::cont::Token token;
|
||||
typename vtkm::cont::ArrayHandle<T>::WritePortalType executionPortal;
|
||||
executionPortal = arrayHandle.PrepareForInPlace(DeviceAdapterTag(), token);
|
||||
token.DetachFromAll();
|
||||
|
||||
//use a worklet to verify the inplace transfer worked properly
|
||||
vtkm::cont::ArrayHandle<T> result;
|
||||
DispatcherPassThrough().Invoke(arrayHandle, WrapPortal(executionPortal), result);
|
||||
array_handle_testing::CheckArray(result);
|
||||
}
|
||||
|
||||
std::cout << "Check out output." << std::endl;
|
||||
{ //as output with same length as user provided. This should work
|
||||
//as no new memory needs to be allocated
|
||||
vtkm::cont::Token token;
|
||||
arrayHandle.PrepareForOutput(3, DeviceAdapterTag(), token);
|
||||
token.DetachFromAll();
|
||||
|
||||
//we can't verify output contents as those aren't fetched, we
|
||||
//can just make sure the allocation didn't throw an exception
|
||||
}
|
||||
|
||||
{ //as a vector moved to the ArrayHandle, reallocation should be possible
|
||||
vtkm::cont::Token token;
|
||||
arrayHandle.PrepareForOutput(ARRAY_SIZE * 2, DeviceAdapterTag(), token);
|
||||
token.DetachFromAll();
|
||||
|
||||
//we can't verify output contents as those aren't fetched, we
|
||||
//can just make sure the allocation didn't throw an exception
|
||||
VTKM_TEST_ASSERT(arrayHandle.GetNumberOfValues() == ARRAY_SIZE * 2);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
struct VerifyVTKMAllocatedHandle
|
||||
{
|
||||
template <typename T>
|
||||
VTKM_CONT void operator()(T) const
|
||||
{
|
||||
vtkm::cont::ArrayHandle<T> arrayHandle;
|
||||
|
||||
VTKM_TEST_ASSERT(arrayHandle.GetNumberOfValues() == 0,
|
||||
"ArrayHandle has wrong number of entries.");
|
||||
{
|
||||
vtkm::cont::Token token;
|
||||
using ExecutionPortalType = typename vtkm::cont::ArrayHandle<T>::WritePortalType;
|
||||
ExecutionPortalType executionPortal =
|
||||
arrayHandle.PrepareForOutput(ARRAY_SIZE * 2, DeviceAdapterTag(), token);
|
||||
|
||||
//we drop down to manually scheduling so that we don't need
|
||||
//need to bring in array handle counting
|
||||
AssignTestValue<T, ExecutionPortalType> functor(executionPortal);
|
||||
Algorithm::Schedule(functor, ARRAY_SIZE * 2);
|
||||
}
|
||||
|
||||
VTKM_TEST_ASSERT(arrayHandle.GetNumberOfValues() == ARRAY_SIZE * 2,
|
||||
"Array not allocated correctly.");
|
||||
array_handle_testing::CheckArray(arrayHandle);
|
||||
|
||||
std::cout << "Try shrinking the array." << std::endl;
|
||||
arrayHandle.Allocate(ARRAY_SIZE, vtkm::CopyFlag::On);
|
||||
VTKM_TEST_ASSERT(arrayHandle.GetNumberOfValues() == ARRAY_SIZE,
|
||||
"Array size did not shrink correctly.");
|
||||
array_handle_testing::CheckArray(arrayHandle);
|
||||
|
||||
std::cout << "Try reallocating array." << std::endl;
|
||||
arrayHandle.Allocate(ARRAY_SIZE * 2);
|
||||
VTKM_TEST_ASSERT(arrayHandle.GetNumberOfValues() == ARRAY_SIZE * 2,
|
||||
"Array size did not allocate correctly.");
|
||||
// No point in checking values. This method can invalidate them.
|
||||
|
||||
std::cout << "Try in place operation." << std::endl;
|
||||
{
|
||||
vtkm::cont::Token token;
|
||||
using ExecutionPortalType = typename vtkm::cont::ArrayHandle<T>::WritePortalType;
|
||||
|
||||
// Reset array data.
|
||||
Algorithm::Schedule(AssignTestValue<T, ExecutionPortalType>{ arrayHandle.PrepareForOutput(
|
||||
ARRAY_SIZE * 2, DeviceAdapterTag{}, token) },
|
||||
ARRAY_SIZE * 2);
|
||||
|
||||
ExecutionPortalType executionPortal =
|
||||
arrayHandle.PrepareForInPlace(DeviceAdapterTag(), token);
|
||||
|
||||
//in place can't be done through the dispatcher
|
||||
//instead we have to drop down to manually scheduling
|
||||
InplaceFunctor<T, ExecutionPortalType> functor(executionPortal);
|
||||
Algorithm::Schedule(functor, ARRAY_SIZE * 2);
|
||||
}
|
||||
typename vtkm::cont::ArrayHandle<T>::ReadPortalType controlPortal = arrayHandle.ReadPortal();
|
||||
for (vtkm::Id index = 0; index < ARRAY_SIZE; index++)
|
||||
{
|
||||
VTKM_TEST_ASSERT(test_equal(controlPortal.Get(index), TestValue(index, T()) + T(1)),
|
||||
"Did not get result from in place operation.");
|
||||
}
|
||||
|
||||
VTKM_TEST_ASSERT(arrayHandle == arrayHandle, "Array handle does not equal itself.");
|
||||
VTKM_TEST_ASSERT(arrayHandle != vtkm::cont::ArrayHandle<T>(),
|
||||
"Array handle equals different array.");
|
||||
}
|
||||
};
|
||||
|
||||
struct VerifyVTKMTransferredOwnership
|
||||
{
|
||||
template <typename T>
|
||||
VTKM_CONT void operator()(T) const
|
||||
{
|
||||
|
||||
vtkm::cont::internal::TransferredBuffer transferredMemory;
|
||||
|
||||
//Steal memory from a handle that has multiple copies to verify all
|
||||
//copies are updated correctly
|
||||
{
|
||||
vtkm::cont::ArrayHandle<T> arrayHandle;
|
||||
auto copyOfHandle = arrayHandle;
|
||||
|
||||
VTKM_TEST_ASSERT(arrayHandle.GetNumberOfValues() == 0,
|
||||
"ArrayHandle has wrong number of entries.");
|
||||
{
|
||||
vtkm::cont::Token token;
|
||||
using ExecutionPortalType = typename vtkm::cont::ArrayHandle<T>::WritePortalType;
|
||||
ExecutionPortalType executionPortal =
|
||||
arrayHandle.PrepareForOutput(ARRAY_SIZE * 2, DeviceAdapterTag(), token);
|
||||
|
||||
//we drop down to manually scheduling so that we don't need
|
||||
//need to bring in array handle counting
|
||||
AssignTestValue<T, ExecutionPortalType> functor(executionPortal);
|
||||
Algorithm::Schedule(functor, ARRAY_SIZE * 2);
|
||||
}
|
||||
|
||||
transferredMemory = copyOfHandle.GetBuffers()[0].TakeHostBufferOwnership();
|
||||
|
||||
VTKM_TEST_ASSERT(copyOfHandle.GetNumberOfValues() == ARRAY_SIZE * 2,
|
||||
"Array not allocated correctly.");
|
||||
array_handle_testing::CheckArray(arrayHandle);
|
||||
|
||||
std::cout << "Try in place operation." << std::endl;
|
||||
{
|
||||
vtkm::cont::Token token;
|
||||
using ExecutionPortalType = typename vtkm::cont::ArrayHandle<T>::WritePortalType;
|
||||
|
||||
// Reset array data.
|
||||
Algorithm::Schedule(AssignTestValue<T, ExecutionPortalType>{ arrayHandle.PrepareForOutput(
|
||||
ARRAY_SIZE * 2, DeviceAdapterTag{}, token) },
|
||||
ARRAY_SIZE * 2);
|
||||
|
||||
ExecutionPortalType executionPortal =
|
||||
arrayHandle.PrepareForInPlace(DeviceAdapterTag(), token);
|
||||
|
||||
//in place can't be done through the dispatcher
|
||||
//instead we have to drop down to manually scheduling
|
||||
InplaceFunctor<T, ExecutionPortalType> functor(executionPortal);
|
||||
Algorithm::Schedule(functor, ARRAY_SIZE * 2);
|
||||
}
|
||||
typename vtkm::cont::ArrayHandle<T>::ReadPortalType controlPortal =
|
||||
arrayHandle.ReadPortal();
|
||||
for (vtkm::Id index = 0; index < ARRAY_SIZE; index++)
|
||||
{
|
||||
VTKM_TEST_ASSERT(test_equal(controlPortal.Get(index), TestValue(index, T()) + T(1)),
|
||||
"Did not get result from in place operation.");
|
||||
}
|
||||
}
|
||||
|
||||
transferredMemory.Delete(transferredMemory.Container);
|
||||
}
|
||||
};
|
||||
|
||||
struct VerifyEqualityOperators
|
||||
{
|
||||
template <typename T>
|
||||
VTKM_CONT void operator()(T) const
|
||||
{
|
||||
std::cout << "Verify that shallow copied array handles compare equal:\n";
|
||||
{
|
||||
vtkm::cont::ArrayHandle<T> a1;
|
||||
vtkm::cont::ArrayHandle<T> a2 = a1; // shallow copy
|
||||
vtkm::cont::ArrayHandle<T> a3;
|
||||
VTKM_TEST_ASSERT(a1 == a2, "Shallow copied array not equal.");
|
||||
VTKM_TEST_ASSERT(!(a1 != a2), "Shallow copied array not equal.");
|
||||
VTKM_TEST_ASSERT(a1 != a3, "Distinct arrays compared equal.");
|
||||
VTKM_TEST_ASSERT(!(a1 == a3), "Distinct arrays compared equal.");
|
||||
|
||||
// Operations on a1 shouldn't affect equality
|
||||
a1.Allocate(200);
|
||||
VTKM_TEST_ASSERT(a1 == a2, "Shallow copied array not equal.");
|
||||
VTKM_TEST_ASSERT(!(a1 != a2), "Shallow copied array not equal.");
|
||||
|
||||
a1.ReadPortal();
|
||||
VTKM_TEST_ASSERT(a1 == a2, "Shallow copied array not equal.");
|
||||
VTKM_TEST_ASSERT(!(a1 != a2), "Shallow copied array not equal.");
|
||||
|
||||
vtkm::cont::Token token;
|
||||
a1.PrepareForInPlace(DeviceAdapterTag(), token);
|
||||
VTKM_TEST_ASSERT(a1 == a2, "Shallow copied array not equal.");
|
||||
VTKM_TEST_ASSERT(!(a1 != a2), "Shallow copied array not equal.");
|
||||
}
|
||||
|
||||
std::cout << "Verify that handles with different storage types are not equal.\n";
|
||||
{
|
||||
vtkm::cont::ArrayHandle<T, StorageTagBasic> a1;
|
||||
vtkm::cont::ArrayHandle<vtkm::Vec<T, 3>, StorageTagBasic> tmp;
|
||||
auto a2 = vtkm::cont::make_ArrayHandleExtractComponent(tmp, 1);
|
||||
|
||||
VTKM_TEST_ASSERT(a1 != a2, "Arrays with different storage type compared equal.");
|
||||
VTKM_TEST_ASSERT(!(a1 == a2), "Arrays with different storage type compared equal.");
|
||||
}
|
||||
|
||||
std::cout << "Verify that handles with different value types are not equal.\n";
|
||||
{
|
||||
vtkm::cont::ArrayHandle<T, StorageTagBasic> a1;
|
||||
vtkm::cont::ArrayHandle<typename OtherType<T>::Type, StorageTagBasic> a2;
|
||||
|
||||
VTKM_TEST_ASSERT(a1 != a2, "Arrays with different value type compared equal.");
|
||||
VTKM_TEST_ASSERT(!(a1 == a2), "Arrays with different value type compared equal.");
|
||||
}
|
||||
|
||||
std::cout << "Verify that handles with different storage and value types are not equal.\n";
|
||||
{
|
||||
vtkm::cont::ArrayHandle<T, StorageTagBasic> a1;
|
||||
vtkm::cont::ArrayHandle<vtkm::Vec<typename OtherType<T>::Type, 3>, StorageTagBasic> tmp;
|
||||
auto a2 = vtkm::cont::make_ArrayHandleExtractComponent(tmp, 1);
|
||||
|
||||
VTKM_TEST_ASSERT(a1 != a2, "Arrays with different storage and value type compared equal.");
|
||||
VTKM_TEST_ASSERT(!(a1 == a2),
|
||||
"Arrays with different storage and value type compared equal.");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
struct VerifyFill
|
||||
{
|
||||
template <typename T>
|
||||
VTKM_CONT void operator()(T) const
|
||||
{
|
||||
std::cout << "Initialize values of array." << std::endl;
|
||||
const T testValue1 = TestValue(13, T{});
|
||||
vtkm::cont::ArrayHandle<T> array;
|
||||
array.AllocateAndFill(ARRAY_SIZE, testValue1);
|
||||
{
|
||||
auto portal = array.ReadPortal();
|
||||
for (vtkm::Id index = 0; index < ARRAY_SIZE; ++index)
|
||||
{
|
||||
VTKM_TEST_ASSERT(portal.Get(index) == testValue1);
|
||||
}
|
||||
}
|
||||
|
||||
std::cout << "Grow array with new values." << std::endl;
|
||||
const T testValue2 = TestValue(42, T{});
|
||||
array.AllocateAndFill(ARRAY_SIZE * 2, testValue2, vtkm::CopyFlag::On);
|
||||
{
|
||||
auto portal = array.ReadPortal();
|
||||
for (vtkm::Id index = 0; index < ARRAY_SIZE; ++index)
|
||||
{
|
||||
VTKM_TEST_ASSERT(portal.Get(index) == testValue1);
|
||||
}
|
||||
for (vtkm::Id index = ARRAY_SIZE; index < ARRAY_SIZE * 2; ++index)
|
||||
{
|
||||
VTKM_TEST_ASSERT(portal.Get(index) == testValue2);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
struct TryArrayHandleType
|
||||
{
|
||||
void operator()() const
|
||||
{
|
||||
vtkm::testing::Testing::TryTypes(VerifyEmptyArrays{});
|
||||
vtkm::testing::Testing::TryTypes(VerifyUserOwnedMemory{});
|
||||
vtkm::testing::Testing::TryTypes(VerifyUserTransferredMemory{});
|
||||
vtkm::testing::Testing::TryTypes(VerifyVectorMovedMemory{});
|
||||
vtkm::testing::Testing::TryTypes(VerifyInitializerList{});
|
||||
vtkm::testing::Testing::TryTypes(VerifyVTKMAllocatedHandle{});
|
||||
vtkm::testing::Testing::TryTypes(VerifyVTKMTransferredOwnership{});
|
||||
vtkm::testing::Testing::TryTypes(VerifyEqualityOperators{});
|
||||
vtkm::testing::Testing::TryTypes(VerifyFill{});
|
||||
}
|
||||
};
|
||||
|
||||
public:
|
||||
static VTKM_CONT int Run(int argc, char* argv[])
|
||||
{
|
||||
vtkm::cont::GetRuntimeDeviceTracker().ForceDevice(DeviceAdapterTag());
|
||||
return vtkm::cont::testing::Testing::Run(TryArrayHandleType(), argc, argv);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
} // namespace vtkm::cont::testing
|
||||
|
||||
#endif //vtk_m_cont_testing_TestingArrayHandles_h
|
569
vtkm/cont/testing/UnitTestArrayHandle.cxx
Normal file
569
vtkm/cont/testing/UnitTestArrayHandle.cxx
Normal file
@ -0,0 +1,569 @@
|
||||
//============================================================================
|
||||
// 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.
|
||||
//============================================================================
|
||||
#include <vtkm/TypeTraits.h>
|
||||
#include <vtkm/cont/ArrayHandle.h>
|
||||
|
||||
#include <vtkm/worklet/DispatcherMapField.h>
|
||||
#include <vtkm/worklet/WorkletMapField.h>
|
||||
|
||||
#include <vtkm/cont/ArrayHandleExtractComponent.h>
|
||||
#include <vtkm/cont/testing/Testing.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <vector>
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
template <class IteratorType, typename T>
|
||||
void CheckValues(IteratorType begin, IteratorType end, T offset)
|
||||
{
|
||||
|
||||
vtkm::Id index = 0;
|
||||
for (IteratorType iter = begin; iter != end; iter++)
|
||||
{
|
||||
T expectedValue = TestValue(index, T()) + offset;
|
||||
if (!test_equal(*iter, expectedValue))
|
||||
{
|
||||
std::stringstream message;
|
||||
message << "Got unexpected value in array." << std::endl
|
||||
<< "Expected: " << expectedValue << ", Found: " << *iter << std::endl;
|
||||
VTKM_TEST_FAIL(message.str().c_str());
|
||||
}
|
||||
|
||||
index++;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void CheckArray(const vtkm::cont::ArrayHandle<T>& handle, T offset = T(0))
|
||||
{
|
||||
CheckPortal(handle.ReadPortal(), offset);
|
||||
}
|
||||
|
||||
// Use to get an arbitrarily different valuetype than T:
|
||||
template <typename T>
|
||||
struct OtherType
|
||||
{
|
||||
using Type = vtkm::Int32;
|
||||
};
|
||||
template <>
|
||||
struct OtherType<vtkm::Int32>
|
||||
{
|
||||
using Type = vtkm::UInt8;
|
||||
};
|
||||
|
||||
struct PassThrough : public vtkm::worklet::WorkletMapField
|
||||
{
|
||||
using ControlSignature = void(FieldIn, FieldOut);
|
||||
using ExecutionSignature = _2(_1);
|
||||
|
||||
template <typename T>
|
||||
VTKM_EXEC T operator()(const T& value) const
|
||||
{
|
||||
return value;
|
||||
}
|
||||
};
|
||||
|
||||
struct AssignTestValue : public vtkm::worklet::WorkletMapField
|
||||
{
|
||||
using ControlSignature = void(FieldIn indices, FieldOut values);
|
||||
|
||||
template <typename T>
|
||||
VTKM_EXEC void operator()(vtkm::Id index, T& valueOut) const
|
||||
{
|
||||
valueOut = TestValue(index, T());
|
||||
}
|
||||
};
|
||||
|
||||
struct InplaceAdd1 : public vtkm::worklet::WorkletMapField
|
||||
{
|
||||
using ControlSignature = void(FieldInOut);
|
||||
|
||||
template <typename T>
|
||||
VTKM_EXEC void operator()(T& value) const
|
||||
{
|
||||
value = static_cast<T>(value + T(1));
|
||||
}
|
||||
};
|
||||
|
||||
constexpr vtkm::Id ARRAY_SIZE = 100;
|
||||
|
||||
struct VerifyEmptyArrays
|
||||
{
|
||||
template <typename T>
|
||||
VTKM_CONT void operator()(T) const
|
||||
{
|
||||
std::cout << "Try operations on empty arrays." << std::endl;
|
||||
// After each operation, reinitialize array in case something gets
|
||||
// allocated.
|
||||
vtkm::cont::ArrayHandle<T> arrayHandle = vtkm::cont::ArrayHandle<T>();
|
||||
VTKM_TEST_ASSERT(arrayHandle.GetNumberOfValues() == 0,
|
||||
"Uninitialized array does not report zero values.");
|
||||
arrayHandle = vtkm::cont::ArrayHandle<T>();
|
||||
VTKM_TEST_ASSERT(arrayHandle.ReadPortal().GetNumberOfValues() == 0,
|
||||
"Uninitialized array does not give portal with zero values.");
|
||||
vtkm::cont::Token token;
|
||||
arrayHandle = vtkm::cont::ArrayHandle<T>();
|
||||
arrayHandle.Allocate(0, vtkm::CopyFlag::On);
|
||||
arrayHandle = vtkm::cont::ArrayHandle<T>();
|
||||
arrayHandle.ReleaseResourcesExecution();
|
||||
arrayHandle = vtkm::cont::ArrayHandle<T>();
|
||||
arrayHandle.ReleaseResources();
|
||||
arrayHandle = vtkm::cont::make_ArrayHandleMove(std::vector<T>());
|
||||
arrayHandle.PrepareForInput(vtkm::cont::DeviceAdapterTagSerial{}, token);
|
||||
arrayHandle = vtkm::cont::ArrayHandle<T>();
|
||||
arrayHandle.PrepareForInPlace(vtkm::cont::DeviceAdapterTagSerial{}, token);
|
||||
arrayHandle = vtkm::cont::ArrayHandle<T>();
|
||||
arrayHandle.PrepareForOutput(ARRAY_SIZE, vtkm::cont::DeviceAdapterTagSerial{}, token);
|
||||
}
|
||||
};
|
||||
|
||||
struct VerifyUserOwnedMemory
|
||||
{
|
||||
template <typename T>
|
||||
VTKM_CONT void operator()(T) const
|
||||
{
|
||||
vtkm::cont::Invoker invoke;
|
||||
|
||||
std::cout << "Creating array with user-allocated memory." << std::endl;
|
||||
std::vector<T> buffer(ARRAY_SIZE);
|
||||
for (vtkm::Id index = 0; index < ARRAY_SIZE; index++)
|
||||
{
|
||||
buffer[static_cast<std::size_t>(index)] = TestValue(index, T());
|
||||
}
|
||||
|
||||
vtkm::cont::ArrayHandle<T> arrayHandle =
|
||||
vtkm::cont::make_ArrayHandle(buffer, vtkm::CopyFlag::Off);
|
||||
|
||||
VTKM_TEST_ASSERT(arrayHandle.GetNumberOfValues() == ARRAY_SIZE,
|
||||
"ArrayHandle has wrong number of entries.");
|
||||
|
||||
std::cout << "Check array with user provided memory." << std::endl;
|
||||
CheckArray(arrayHandle);
|
||||
|
||||
std::cout << "Check out execution array behavior." << std::endl;
|
||||
{ //as input
|
||||
vtkm::cont::ArrayHandle<T> result;
|
||||
invoke(PassThrough{}, arrayHandle, result);
|
||||
CheckArray(result);
|
||||
}
|
||||
|
||||
std::cout << "Check out inplace." << std::endl;
|
||||
{ //as inplace
|
||||
invoke(InplaceAdd1{}, arrayHandle);
|
||||
CheckArray(arrayHandle, T(1));
|
||||
}
|
||||
|
||||
//clear out user array for next test
|
||||
std::fill(buffer.begin(), buffer.end(), static_cast<T>(-1));
|
||||
|
||||
std::cout << "Check out output." << std::endl;
|
||||
{ //as output with same length as user provided. This should work
|
||||
//as no new memory needs to be allocated
|
||||
invoke(AssignTestValue{}, vtkm::cont::ArrayHandleIndex(ARRAY_SIZE), arrayHandle);
|
||||
|
||||
//sync data, which should fill up the user buffer
|
||||
arrayHandle.SyncControlArray();
|
||||
|
||||
//check that we got the proper values in the user array
|
||||
CheckValues(buffer.begin(), buffer.end(), T{ 0 });
|
||||
}
|
||||
|
||||
std::cout << "Check invalid reallocation." << std::endl;
|
||||
{ //as output with a length larger than the memory provided by the user
|
||||
//this should fail
|
||||
bool gotException = false;
|
||||
try
|
||||
{
|
||||
//you should not be able to allocate a size larger than the
|
||||
//user provided and get the results
|
||||
vtkm::cont::Token token;
|
||||
arrayHandle.PrepareForOutput(ARRAY_SIZE * 2, vtkm::cont::DeviceAdapterTagSerial{}, token);
|
||||
token.DetachFromAll();
|
||||
arrayHandle.WritePortal();
|
||||
}
|
||||
catch (vtkm::cont::Error&)
|
||||
{
|
||||
gotException = true;
|
||||
}
|
||||
VTKM_TEST_ASSERT(gotException,
|
||||
"PrepareForOutput should fail when asked to "
|
||||
"re-allocate user provided memory.");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
struct VerifyUserTransferredMemory
|
||||
{
|
||||
template <typename T>
|
||||
VTKM_CONT void operator()(T) const
|
||||
{
|
||||
vtkm::cont::Invoker invoke;
|
||||
|
||||
T* buffer = new T[ARRAY_SIZE];
|
||||
for (vtkm::Id index = 0; index < ARRAY_SIZE; index++)
|
||||
{
|
||||
buffer[static_cast<std::size_t>(index)] = TestValue(index, T());
|
||||
}
|
||||
|
||||
auto user_free_function = [](void* ptr) { delete[] static_cast<T*>(ptr); };
|
||||
vtkm::cont::ArrayHandleBasic<T> arrayHandle(buffer, ARRAY_SIZE, user_free_function);
|
||||
|
||||
VTKM_TEST_ASSERT(arrayHandle.GetNumberOfValues() == ARRAY_SIZE,
|
||||
"ArrayHandle has wrong number of entries.");
|
||||
|
||||
std::cout << "Check array with user transferred memory." << std::endl;
|
||||
CheckArray(arrayHandle);
|
||||
|
||||
std::cout << "Check out execution array behavior." << std::endl;
|
||||
{ //as input
|
||||
vtkm::cont::ArrayHandle<T> result;
|
||||
invoke(PassThrough{}, arrayHandle, result);
|
||||
CheckArray(result);
|
||||
}
|
||||
|
||||
std::cout << "Check out inplace." << std::endl;
|
||||
{ //as inplace
|
||||
invoke(InplaceAdd1{}, arrayHandle);
|
||||
CheckArray(arrayHandle, T(1));
|
||||
}
|
||||
|
||||
std::cout << "Check out output." << std::endl;
|
||||
{ //as output with same length as user provided. This should work
|
||||
//as no new memory needs to be allocated
|
||||
invoke(AssignTestValue{}, vtkm::cont::ArrayHandleIndex(ARRAY_SIZE), arrayHandle);
|
||||
|
||||
//sync data, which should fill up the user buffer
|
||||
arrayHandle.SyncControlArray();
|
||||
|
||||
//check that we got the proper values in the user array
|
||||
CheckValues(buffer, buffer + ARRAY_SIZE, T{ 0 });
|
||||
}
|
||||
|
||||
{ //as output with a length larger than the memory provided by the user
|
||||
//this should fail
|
||||
bool gotException = false;
|
||||
try
|
||||
{
|
||||
//you should not be able to allocate a size larger than the
|
||||
//user provided and get the results
|
||||
vtkm::cont::Token token;
|
||||
arrayHandle.PrepareForOutput(ARRAY_SIZE * 2, vtkm::cont::DeviceAdapterTagSerial{}, token);
|
||||
token.DetachFromAll();
|
||||
arrayHandle.WritePortal();
|
||||
}
|
||||
catch (vtkm::cont::Error&)
|
||||
{
|
||||
gotException = true;
|
||||
}
|
||||
VTKM_TEST_ASSERT(gotException,
|
||||
"PrepareForOutput should fail when asked to "
|
||||
"re-allocate user provided memory.");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
struct VerifyVectorMovedMemory
|
||||
{
|
||||
template <typename T>
|
||||
VTKM_CONT void operator()(T) const
|
||||
{
|
||||
vtkm::cont::Invoker invoke;
|
||||
|
||||
std::cout << "Creating moved std::vector memory." << std::endl;
|
||||
std::vector<T> buffer(ARRAY_SIZE);
|
||||
for (vtkm::Id index = 0; index < ARRAY_SIZE; index++)
|
||||
{
|
||||
buffer[static_cast<std::size_t>(index)] = TestValue(index, T());
|
||||
}
|
||||
|
||||
vtkm::cont::ArrayHandle<T> arrayHandle = vtkm::cont::make_ArrayHandleMove(std::move(buffer));
|
||||
// buffer is now invalid
|
||||
|
||||
VTKM_TEST_ASSERT(arrayHandle.GetNumberOfValues() == ARRAY_SIZE,
|
||||
"ArrayHandle has wrong number of entries.");
|
||||
|
||||
std::cout << "Check array with moved std::vector memory." << std::endl;
|
||||
CheckArray(arrayHandle);
|
||||
|
||||
std::cout << "Check out execution array behavior." << std::endl;
|
||||
{ //as input
|
||||
vtkm::cont::ArrayHandle<T> result;
|
||||
invoke(PassThrough{}, arrayHandle, result);
|
||||
CheckArray(result);
|
||||
}
|
||||
|
||||
std::cout << "Check out inplace." << std::endl;
|
||||
{ //as inplace
|
||||
invoke(InplaceAdd1{}, arrayHandle);
|
||||
CheckArray(arrayHandle, T(1));
|
||||
}
|
||||
|
||||
std::cout << "Check out output." << std::endl;
|
||||
{ //as output with same length as user provided. This should work
|
||||
//as no new memory needs to be allocated
|
||||
invoke(AssignTestValue{}, vtkm::cont::ArrayHandleIndex(ARRAY_SIZE), arrayHandle);
|
||||
|
||||
//check that we got the proper values in the user array
|
||||
CheckArray(arrayHandle);
|
||||
}
|
||||
|
||||
{ //as a vector moved to the ArrayHandle, reallocation should be possible
|
||||
invoke(AssignTestValue{}, vtkm::cont::ArrayHandleIndex(ARRAY_SIZE * 2), arrayHandle);
|
||||
VTKM_TEST_ASSERT(arrayHandle.GetNumberOfValues() == ARRAY_SIZE * 2);
|
||||
|
||||
//check that we got the proper values in the user array
|
||||
CheckArray(arrayHandle);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
struct VerifyInitializerList
|
||||
{
|
||||
template <typename T>
|
||||
VTKM_CONT void operator()(T) const
|
||||
{
|
||||
vtkm::cont::Invoker invoke;
|
||||
|
||||
std::cout << "Creating array with initializer list memory." << std::endl;
|
||||
vtkm::cont::ArrayHandle<T> arrayHandle =
|
||||
vtkm::cont::make_ArrayHandle({ TestValue(0, T()), TestValue(1, T()), TestValue(2, T()) });
|
||||
|
||||
VTKM_TEST_ASSERT(arrayHandle.GetNumberOfValues() == 3,
|
||||
"ArrayHandle has wrong number of entries.");
|
||||
|
||||
std::cout << "Check array with initializer list memory." << std::endl;
|
||||
CheckArray(arrayHandle);
|
||||
|
||||
std::cout << "Check out execution array behavior." << std::endl;
|
||||
{ //as input
|
||||
vtkm::cont::ArrayHandle<T> result;
|
||||
invoke(PassThrough{}, arrayHandle, result);
|
||||
CheckArray(result);
|
||||
}
|
||||
|
||||
std::cout << "Check out inplace." << std::endl;
|
||||
{ //as inplace
|
||||
invoke(InplaceAdd1{}, arrayHandle);
|
||||
CheckArray(arrayHandle, T(1));
|
||||
}
|
||||
|
||||
std::cout << "Check out output." << std::endl;
|
||||
{ //as output with same length as user provided. This should work
|
||||
//as no new memory needs to be allocated
|
||||
invoke(AssignTestValue{}, vtkm::cont::ArrayHandleIndex(3), arrayHandle);
|
||||
|
||||
//check that we got the proper values in the user array
|
||||
CheckArray(arrayHandle);
|
||||
}
|
||||
|
||||
{ //as a vector moved to the ArrayHandle, reallocation should be possible
|
||||
invoke(AssignTestValue{}, vtkm::cont::ArrayHandleIndex(ARRAY_SIZE * 2), arrayHandle);
|
||||
VTKM_TEST_ASSERT(arrayHandle.GetNumberOfValues() == ARRAY_SIZE * 2);
|
||||
|
||||
//check that we got the proper values in the user array
|
||||
CheckArray(arrayHandle);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
struct VerifyVTKMAllocatedHandle
|
||||
{
|
||||
template <typename T>
|
||||
VTKM_CONT void operator()(T) const
|
||||
{
|
||||
vtkm::cont::Invoker invoke;
|
||||
|
||||
vtkm::cont::ArrayHandle<T> arrayHandle;
|
||||
|
||||
VTKM_TEST_ASSERT(arrayHandle.GetNumberOfValues() == 0,
|
||||
"ArrayHandle has wrong number of entries.");
|
||||
invoke(AssignTestValue{}, vtkm::cont::ArrayHandleIndex(ARRAY_SIZE * 2), arrayHandle);
|
||||
|
||||
VTKM_TEST_ASSERT(arrayHandle.GetNumberOfValues() == ARRAY_SIZE * 2,
|
||||
"Array not allocated correctly.");
|
||||
CheckArray(arrayHandle);
|
||||
|
||||
std::cout << "Try shrinking the array." << std::endl;
|
||||
arrayHandle.Allocate(ARRAY_SIZE, vtkm::CopyFlag::On);
|
||||
VTKM_TEST_ASSERT(arrayHandle.GetNumberOfValues() == ARRAY_SIZE,
|
||||
"Array size did not shrink correctly.");
|
||||
CheckArray(arrayHandle);
|
||||
|
||||
std::cout << "Try reallocating array." << std::endl;
|
||||
arrayHandle.Allocate(ARRAY_SIZE * 2);
|
||||
VTKM_TEST_ASSERT(arrayHandle.GetNumberOfValues() == ARRAY_SIZE * 2,
|
||||
"Array size did not allocate correctly.");
|
||||
// No point in checking values. This method can invalidate them.
|
||||
|
||||
std::cout << "Try in place operation." << std::endl;
|
||||
// Reset array data.
|
||||
invoke(AssignTestValue{}, vtkm::cont::ArrayHandleIndex(ARRAY_SIZE * 2), arrayHandle);
|
||||
|
||||
invoke(InplaceAdd1{}, arrayHandle);
|
||||
CheckArray(arrayHandle, T(1));
|
||||
|
||||
VTKM_TEST_ASSERT(arrayHandle == arrayHandle, "Array handle does not equal itself.");
|
||||
VTKM_TEST_ASSERT(arrayHandle != vtkm::cont::ArrayHandle<T>(),
|
||||
"Array handle equals different array.");
|
||||
}
|
||||
};
|
||||
|
||||
struct VerifyVTKMTransferredOwnership
|
||||
{
|
||||
template <typename T>
|
||||
VTKM_CONT void operator()(T) const
|
||||
{
|
||||
vtkm::cont::Invoker invoke;
|
||||
|
||||
vtkm::cont::internal::TransferredBuffer transferredMemory;
|
||||
|
||||
//Steal memory from a handle that has multiple copies to verify all
|
||||
//copies are updated correctly
|
||||
{
|
||||
vtkm::cont::ArrayHandle<T> arrayHandle;
|
||||
auto copyOfHandle = arrayHandle;
|
||||
|
||||
VTKM_TEST_ASSERT(arrayHandle.GetNumberOfValues() == 0,
|
||||
"ArrayHandle has wrong number of entries.");
|
||||
invoke(AssignTestValue{}, vtkm::cont::ArrayHandleIndex(ARRAY_SIZE * 2), arrayHandle);
|
||||
|
||||
transferredMemory = copyOfHandle.GetBuffers()[0].TakeHostBufferOwnership();
|
||||
|
||||
VTKM_TEST_ASSERT(copyOfHandle.GetNumberOfValues() == ARRAY_SIZE * 2,
|
||||
"Array not allocated correctly.");
|
||||
CheckArray(arrayHandle);
|
||||
|
||||
std::cout << "Try in place operation." << std::endl;
|
||||
invoke(InplaceAdd1{}, arrayHandle);
|
||||
CheckArray(arrayHandle, T(1));
|
||||
}
|
||||
|
||||
transferredMemory.Delete(transferredMemory.Container);
|
||||
}
|
||||
};
|
||||
|
||||
struct VerifyEqualityOperators
|
||||
{
|
||||
template <typename T>
|
||||
VTKM_CONT void operator()(T) const
|
||||
{
|
||||
std::cout << "Verify that shallow copied array handles compare equal:\n";
|
||||
{
|
||||
vtkm::cont::ArrayHandle<T> a1;
|
||||
vtkm::cont::ArrayHandle<T> a2 = a1; // shallow copy
|
||||
vtkm::cont::ArrayHandle<T> a3;
|
||||
VTKM_TEST_ASSERT(a1 == a2, "Shallow copied array not equal.");
|
||||
VTKM_TEST_ASSERT(!(a1 != a2), "Shallow copied array not equal.");
|
||||
VTKM_TEST_ASSERT(a1 != a3, "Distinct arrays compared equal.");
|
||||
VTKM_TEST_ASSERT(!(a1 == a3), "Distinct arrays compared equal.");
|
||||
|
||||
// Operations on a1 shouldn't affect equality
|
||||
a1.Allocate(200);
|
||||
VTKM_TEST_ASSERT(a1 == a2, "Shallow copied array not equal.");
|
||||
VTKM_TEST_ASSERT(!(a1 != a2), "Shallow copied array not equal.");
|
||||
|
||||
a1.ReadPortal();
|
||||
VTKM_TEST_ASSERT(a1 == a2, "Shallow copied array not equal.");
|
||||
VTKM_TEST_ASSERT(!(a1 != a2), "Shallow copied array not equal.");
|
||||
|
||||
vtkm::cont::Token token;
|
||||
a1.PrepareForInPlace(vtkm::cont::DeviceAdapterTagSerial{}, token);
|
||||
VTKM_TEST_ASSERT(a1 == a2, "Shallow copied array not equal.");
|
||||
VTKM_TEST_ASSERT(!(a1 != a2), "Shallow copied array not equal.");
|
||||
}
|
||||
|
||||
std::cout << "Verify that handles with different storage types are not equal.\n";
|
||||
{
|
||||
vtkm::cont::ArrayHandle<T, vtkm::cont::StorageTagBasic> a1;
|
||||
vtkm::cont::ArrayHandle<vtkm::Vec<T, 3>, vtkm::cont::StorageTagBasic> tmp;
|
||||
auto a2 = vtkm::cont::make_ArrayHandleExtractComponent(tmp, 1);
|
||||
|
||||
VTKM_TEST_ASSERT(a1 != a2, "Arrays with different storage type compared equal.");
|
||||
VTKM_TEST_ASSERT(!(a1 == a2), "Arrays with different storage type compared equal.");
|
||||
}
|
||||
|
||||
std::cout << "Verify that handles with different value types are not equal.\n";
|
||||
{
|
||||
vtkm::cont::ArrayHandle<T, vtkm::cont::StorageTagBasic> a1;
|
||||
vtkm::cont::ArrayHandle<typename OtherType<T>::Type, vtkm::cont::StorageTagBasic> a2;
|
||||
|
||||
VTKM_TEST_ASSERT(a1 != a2, "Arrays with different value type compared equal.");
|
||||
VTKM_TEST_ASSERT(!(a1 == a2), "Arrays with different value type compared equal.");
|
||||
}
|
||||
|
||||
std::cout << "Verify that handles with different storage and value types are not equal.\n";
|
||||
{
|
||||
vtkm::cont::ArrayHandle<T, vtkm::cont::StorageTagBasic> a1;
|
||||
vtkm::cont::ArrayHandle<vtkm::Vec<typename OtherType<T>::Type, 3>,
|
||||
vtkm::cont::StorageTagBasic>
|
||||
tmp;
|
||||
auto a2 = vtkm::cont::make_ArrayHandleExtractComponent(tmp, 1);
|
||||
|
||||
VTKM_TEST_ASSERT(a1 != a2, "Arrays with different storage and value type compared equal.");
|
||||
VTKM_TEST_ASSERT(!(a1 == a2), "Arrays with different storage and value type compared equal.");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
struct VerifyFill
|
||||
{
|
||||
template <typename T>
|
||||
VTKM_CONT void operator()(T) const
|
||||
{
|
||||
std::cout << "Initialize values of array." << std::endl;
|
||||
const T testValue1 = TestValue(13, T{});
|
||||
vtkm::cont::ArrayHandle<T> array;
|
||||
array.AllocateAndFill(ARRAY_SIZE, testValue1);
|
||||
{
|
||||
auto portal = array.ReadPortal();
|
||||
for (vtkm::Id index = 0; index < ARRAY_SIZE; ++index)
|
||||
{
|
||||
VTKM_TEST_ASSERT(portal.Get(index) == testValue1);
|
||||
}
|
||||
}
|
||||
|
||||
std::cout << "Grow array with new values." << std::endl;
|
||||
const T testValue2 = TestValue(42, T{});
|
||||
array.AllocateAndFill(ARRAY_SIZE * 2, testValue2, vtkm::CopyFlag::On);
|
||||
{
|
||||
auto portal = array.ReadPortal();
|
||||
for (vtkm::Id index = 0; index < ARRAY_SIZE; ++index)
|
||||
{
|
||||
VTKM_TEST_ASSERT(portal.Get(index) == testValue1);
|
||||
}
|
||||
for (vtkm::Id index = ARRAY_SIZE; index < ARRAY_SIZE * 2; ++index)
|
||||
{
|
||||
VTKM_TEST_ASSERT(portal.Get(index) == testValue2);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
VTKM_CONT void Run()
|
||||
{
|
||||
vtkm::testing::Testing::TryTypes(VerifyEmptyArrays{});
|
||||
vtkm::testing::Testing::TryTypes(VerifyUserOwnedMemory{});
|
||||
vtkm::testing::Testing::TryTypes(VerifyUserTransferredMemory{});
|
||||
vtkm::testing::Testing::TryTypes(VerifyVectorMovedMemory{});
|
||||
vtkm::testing::Testing::TryTypes(VerifyInitializerList{});
|
||||
vtkm::testing::Testing::TryTypes(VerifyVTKMAllocatedHandle{});
|
||||
vtkm::testing::Testing::TryTypes(VerifyVTKMTransferredOwnership{});
|
||||
vtkm::testing::Testing::TryTypes(VerifyEqualityOperators{});
|
||||
vtkm::testing::Testing::TryTypes(VerifyFill{});
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
int UnitTestArrayHandle(int argc, char* argv[])
|
||||
{
|
||||
return vtkm::cont::testing::Testing::Run(Run, argc, argv);
|
||||
}
|
@ -894,13 +894,15 @@ struct TestValueImpl<std::string>
|
||||
/// returned by vtkm::testing::TestValue.
|
||||
///
|
||||
template <typename PortalType>
|
||||
static inline VTKM_CONT void CheckPortal(const PortalType& portal)
|
||||
static inline VTKM_CONT void CheckPortal(
|
||||
const PortalType& portal,
|
||||
typename PortalType::ValueType offset = typename PortalType::ValueType(0))
|
||||
{
|
||||
using ValueType = typename PortalType::ValueType;
|
||||
|
||||
for (vtkm::Id index = 0; index < portal.GetNumberOfValues(); index++)
|
||||
{
|
||||
ValueType expectedValue = TestValue(index, ValueType());
|
||||
ValueType expectedValue = TestValue(index, ValueType()) + offset;
|
||||
ValueType foundValue = portal.Get(index);
|
||||
if (!test_equal(expectedValue, foundValue))
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user