mirror of
https://gitlab.kitware.com/vtk/vtk-m
synced 2024-10-08 11:29:02 +00:00
Add ArrayHandleRuntimeVec
The new `ArrayHandleRuntimeVec` is a fancy `ArrayHandle` allows you to specify a basic array of `Vec`s where the number of components of the `Vec` are not known until runtime. (It can also optionally specify scalars.) The behavior is much like that of `ArrayHandleGroupVecVariable` except that its representation is much more constrained. This constrained representation allows it to be automatically converted to an `ArrayHandleBasic` with the proper `Vec` value type. This allows one part of code (such as a file reader) to create an array with any `Vec` size, and then that array can be fed to an algorithm that expects an `ArrayHandleBasic` of a certain value type.
This commit is contained in:
parent
a7679c9e99
commit
cdd1dbd7bc
12
docs/changelog/runtime-vec-array.md
Normal file
12
docs/changelog/runtime-vec-array.md
Normal file
@ -0,0 +1,12 @@
|
||||
# Added `ArrayHandleRuntimeVec` to specify vector sizes at runtime.
|
||||
|
||||
The new `ArrayHandleRuntimeVec` is a fancy `ArrayHandle` allows you to
|
||||
specify a basic array of `Vec`s where the number of components of the `Vec`
|
||||
are not known until runtime. (It can also optionally specify scalars.) The
|
||||
behavior is much like that of `ArrayHandleGroupVecVariable` except that its
|
||||
representation is much more constrained. This constrained representation
|
||||
allows it to be automatically converted to an `ArrayHandleBasic` with the
|
||||
proper `Vec` value type. This allows one part of code (such as a file
|
||||
reader) to create an array with any `Vec` size, and then that array can be
|
||||
fed to an algorithm that expects an `ArrayHandleBasic` of a certain value
|
||||
type.
|
@ -53,6 +53,18 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
template <vtkm::IdComponent N>
|
||||
VTKM_EXEC_CONT operator vtkm::Vec<ComponentType, N>() const
|
||||
{
|
||||
vtkm::Vec<ComponentType, N> result;
|
||||
this->CopyInto(result);
|
||||
for (vtkm::IdComponent index = this->NumComponents; index < N; ++index)
|
||||
{
|
||||
result[index] = vtkm::TypeTraits<ComponentType>::ZeroInitialization();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
VTKM_SUPPRESS_EXEC_WARNINGS
|
||||
VTKM_EXEC_CONT
|
||||
vtkm::internal::ArrayPortalValueReference<PortalType> operator[](vtkm::IdComponent index) const
|
||||
@ -61,6 +73,20 @@ public:
|
||||
index + this->Offset);
|
||||
}
|
||||
|
||||
template <typename T, vtkm::IdComponent N>
|
||||
VTKM_EXEC_CONT VecFromPortal& operator=(const vtkm::Vec<T, N>& src)
|
||||
{
|
||||
vtkm::IdComponent numComponents = vtkm::Min(N, this->NumComponents);
|
||||
for (vtkm::IdComponent index = 0; index < numComponents; ++index)
|
||||
{
|
||||
this->Portal.Set(index + this->Offset, src[index]);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
VTKM_EXEC_CONT const PortalType& GetPortal() const { return this->Portal; }
|
||||
VTKM_EXEC_CONT vtkm::Id GetOffset() const { return this->Offset; }
|
||||
|
||||
private:
|
||||
PortalType Portal;
|
||||
vtkm::IdComponent NumComponents;
|
||||
|
@ -47,7 +47,7 @@ public:
|
||||
{
|
||||
}
|
||||
|
||||
/// Copy constructor for any other ArrayPortalConcatenate with a portal type
|
||||
/// Copy constructor for any other ArrayPortalGroupVecVariable with a portal type
|
||||
/// that can be copied to this portal type. This allows us to do any type
|
||||
/// casting that the portals do (like the non-const to const cast).
|
||||
VTKM_SUPPRESS_EXEC_WARNINGS
|
||||
@ -77,12 +77,19 @@ public:
|
||||
|
||||
VTKM_SUPPRESS_EXEC_WARNINGS
|
||||
VTKM_EXEC_CONT
|
||||
void Set(vtkm::Id vtkmNotUsed(index), const ValueType& vtkmNotUsed(value)) const
|
||||
void Set(vtkm::Id index, const ValueType& value) const
|
||||
{
|
||||
if ((&value.GetPortal() == &this->ComponentsPortal) &&
|
||||
(value.GetOffset() == this->OffsetsPortal.Get(index)))
|
||||
{
|
||||
// The ValueType (VecFromPortal) operates on demand. Thus, if you set
|
||||
// something in the value, it has already been passed to the array. Perhaps
|
||||
// we should check to make sure that the value used matches the location
|
||||
// you are trying to set in the array, but we don't do that.
|
||||
// something in the value, it has already been passed to the array.
|
||||
}
|
||||
else
|
||||
{
|
||||
// The value comes from somewhere else. Copy data in.
|
||||
this->Get(index) = value;
|
||||
}
|
||||
}
|
||||
|
||||
VTKM_SUPPRESS_EXEC_WARNINGS
|
||||
|
454
vtkm/cont/ArrayHandleRuntimeVec.h
Normal file
454
vtkm/cont/ArrayHandleRuntimeVec.h
Normal file
@ -0,0 +1,454 @@
|
||||
//============================================================================
|
||||
// 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_ArrayHandleRuntimeVec_h
|
||||
#define vtk_m_cont_ArrayHandleRuntimeVec_h
|
||||
|
||||
#include <vtkm/cont/ArrayExtractComponent.h>
|
||||
#include <vtkm/cont/ArrayHandle.h>
|
||||
#include <vtkm/cont/ArrayHandleBasic.h>
|
||||
#include <vtkm/cont/ArrayPortal.h>
|
||||
#include <vtkm/cont/ErrorBadType.h>
|
||||
|
||||
#include <vtkm/Assert.h>
|
||||
#include <vtkm/StaticAssert.h>
|
||||
#include <vtkm/VecFromPortal.h>
|
||||
#include <vtkm/VecTraits.h>
|
||||
|
||||
namespace vtkm
|
||||
{
|
||||
namespace internal
|
||||
{
|
||||
|
||||
template <typename ComponentsPortalType>
|
||||
class VTKM_ALWAYS_EXPORT ArrayPortalRuntimeVec
|
||||
{
|
||||
public:
|
||||
using ComponentType = typename std::remove_const<typename ComponentsPortalType::ValueType>::type;
|
||||
using ValueType = vtkm::VecFromPortal<ComponentsPortalType>;
|
||||
|
||||
ArrayPortalRuntimeVec() = default;
|
||||
|
||||
VTKM_EXEC_CONT ArrayPortalRuntimeVec(const ComponentsPortalType& componentsPortal,
|
||||
vtkm::IdComponent numComponents)
|
||||
: ComponentsPortal(componentsPortal)
|
||||
, NumberOfComponents(numComponents)
|
||||
{
|
||||
}
|
||||
|
||||
/// Copy constructor for any other ArrayPortalRuntimeVec with a portal type
|
||||
/// that can be copied to this portal type. This allows us to do any type
|
||||
/// casting that the portals do (like the non-const to const cast).
|
||||
template <typename OtherComponentsPortalType>
|
||||
VTKM_EXEC_CONT ArrayPortalRuntimeVec(const ArrayPortalRuntimeVec<OtherComponentsPortalType>& src)
|
||||
: ComponentsPortal(src.GetComponentsPortal())
|
||||
, NumberOfComponents(src.GetNumberOfComponents())
|
||||
{
|
||||
}
|
||||
|
||||
VTKM_EXEC_CONT vtkm::Id GetNumberOfValues() const
|
||||
{
|
||||
return this->ComponentsPortal.GetNumberOfValues() / this->NumberOfComponents;
|
||||
}
|
||||
|
||||
VTKM_EXEC_CONT ValueType Get(vtkm::Id index) const
|
||||
{
|
||||
return ValueType(
|
||||
this->ComponentsPortal, this->NumberOfComponents, index * this->NumberOfComponents);
|
||||
}
|
||||
|
||||
VTKM_EXEC_CONT void Set(vtkm::Id index, const ValueType& value) const
|
||||
{
|
||||
if ((&value.GetPortal() == &this->ComponentsPortal) &&
|
||||
(value.GetOffset() == (index * this->NumberOfComponents)))
|
||||
{
|
||||
// The ValueType (VecFromPortal) operates on demand. Thus, if you set
|
||||
// something in the value, it has already been passed to the array.
|
||||
}
|
||||
else
|
||||
{
|
||||
// The value comes from somewhere else. Copy data in.
|
||||
this->Get(index) = value;
|
||||
}
|
||||
}
|
||||
|
||||
VTKM_EXEC_CONT const ComponentsPortalType& GetComponentsPortal() const
|
||||
{
|
||||
return this->ComponentsPortal;
|
||||
}
|
||||
|
||||
VTKM_EXEC_CONT vtkm::IdComponent GetNumberOfComponents() const
|
||||
{
|
||||
return this->NumberOfComponents;
|
||||
}
|
||||
|
||||
private:
|
||||
ComponentsPortalType ComponentsPortal;
|
||||
vtkm::IdComponent NumberOfComponents = 0;
|
||||
};
|
||||
|
||||
}
|
||||
} // namespace vtkm::internal
|
||||
|
||||
namespace vtkm
|
||||
{
|
||||
namespace cont
|
||||
{
|
||||
|
||||
struct VTKM_ALWAYS_EXPORT StorageTagRuntimeVec
|
||||
{
|
||||
};
|
||||
|
||||
namespace internal
|
||||
{
|
||||
|
||||
template <typename ComponentsPortal>
|
||||
class Storage<vtkm::VecFromPortal<ComponentsPortal>, vtkm::cont::StorageTagRuntimeVec>
|
||||
{
|
||||
using ComponentType = typename ComponentsPortal::ValueType;
|
||||
using ComponentsStorage =
|
||||
vtkm::cont::internal::Storage<ComponentType, vtkm::cont::StorageTagBasic>;
|
||||
|
||||
using ComponentsArray = vtkm::cont::ArrayHandle<ComponentType, StorageTagBasic>;
|
||||
|
||||
VTKM_STATIC_ASSERT_MSG(
|
||||
(std::is_same<ComponentsPortal, typename ComponentsStorage::WritePortalType>::value),
|
||||
"Used invalid ComponentsPortal type with expected ComponentsStorageTag.");
|
||||
|
||||
struct Info
|
||||
{
|
||||
vtkm::IdComponent NumberOfComponents;
|
||||
};
|
||||
|
||||
VTKM_CONT static std::vector<vtkm::cont::internal::Buffer> ComponentsBuffers(
|
||||
const std::vector<vtkm::cont::internal::Buffer>& buffers)
|
||||
{
|
||||
return std::vector<vtkm::cont::internal::Buffer>(buffers.begin() + 1, buffers.end());
|
||||
}
|
||||
|
||||
public:
|
||||
using ReadPortalType =
|
||||
vtkm::internal::ArrayPortalRuntimeVec<typename ComponentsStorage::ReadPortalType>;
|
||||
using WritePortalType =
|
||||
vtkm::internal::ArrayPortalRuntimeVec<typename ComponentsStorage::WritePortalType>;
|
||||
|
||||
VTKM_CONT static vtkm::IdComponent GetNumberOfComponents(
|
||||
const std::vector<vtkm::cont::internal::Buffer>& buffers)
|
||||
{
|
||||
return buffers[0].GetMetaData<Info>().NumberOfComponents;
|
||||
}
|
||||
|
||||
VTKM_CONT static vtkm::Id GetNumberOfValues(
|
||||
const std::vector<vtkm::cont::internal::Buffer>& buffers)
|
||||
{
|
||||
return ComponentsStorage::GetNumberOfValues(ComponentsBuffers(buffers)) /
|
||||
GetNumberOfComponents(buffers);
|
||||
}
|
||||
|
||||
VTKM_CONT static void ResizeBuffers(vtkm::Id numValues,
|
||||
const std::vector<vtkm::cont::internal::Buffer>& buffers,
|
||||
vtkm::CopyFlag preserve,
|
||||
vtkm::cont::Token& token)
|
||||
{
|
||||
ComponentsStorage::ResizeBuffers(
|
||||
numValues * GetNumberOfComponents(buffers), ComponentsBuffers(buffers), preserve, token);
|
||||
}
|
||||
|
||||
VTKM_CONT static void Fill(const std::vector<vtkm::cont::internal::Buffer>&,
|
||||
const vtkm::VecFromPortal<ComponentsPortal>&,
|
||||
vtkm::Id,
|
||||
vtkm::Id,
|
||||
vtkm::cont::Token&)
|
||||
{
|
||||
throw vtkm::cont::ErrorBadType("Fill not supported for ArrayHandleRuntimeVec.");
|
||||
}
|
||||
|
||||
VTKM_CONT static ReadPortalType CreateReadPortal(
|
||||
const std::vector<vtkm::cont::internal::Buffer>& buffers,
|
||||
vtkm::cont::DeviceAdapterId device,
|
||||
vtkm::cont::Token& token)
|
||||
{
|
||||
return ReadPortalType(
|
||||
ComponentsStorage::CreateReadPortal(ComponentsBuffers(buffers), device, token),
|
||||
GetNumberOfComponents(buffers));
|
||||
}
|
||||
|
||||
VTKM_CONT static WritePortalType CreateWritePortal(
|
||||
const std::vector<vtkm::cont::internal::Buffer>& buffers,
|
||||
vtkm::cont::DeviceAdapterId device,
|
||||
vtkm::cont::Token& token)
|
||||
{
|
||||
return WritePortalType(
|
||||
ComponentsStorage::CreateWritePortal(ComponentsBuffers(buffers), device, token),
|
||||
GetNumberOfComponents(buffers));
|
||||
}
|
||||
|
||||
VTKM_CONT static std::vector<vtkm::cont::internal::Buffer> CreateBuffers(
|
||||
vtkm::IdComponent numComponents = 1,
|
||||
const ComponentsArray& componentsArray = ComponentsArray{})
|
||||
{
|
||||
VTKM_LOG_IF_S(vtkm::cont::LogLevel::Warn,
|
||||
(componentsArray.GetNumberOfValues() % numComponents) != 0,
|
||||
"Array given to ArrayHandleRuntimeVec has size ("
|
||||
<< componentsArray.GetNumberOfValues()
|
||||
<< ") that is not divisible by the number of components selected ("
|
||||
<< numComponents << ").");
|
||||
Info info;
|
||||
info.NumberOfComponents = numComponents;
|
||||
return vtkm::cont::internal::CreateBuffers(info, componentsArray);
|
||||
}
|
||||
|
||||
VTKM_CONT static ComponentsArray GetComponentsArray(
|
||||
const std::vector<vtkm::cont::internal::Buffer>& buffers)
|
||||
{
|
||||
return ComponentsArray(ComponentsBuffers(buffers));
|
||||
}
|
||||
|
||||
VTKM_CONT static void AsArrayHandleBasic(
|
||||
const std::vector<vtkm::cont::internal::Buffer>& buffers,
|
||||
vtkm::cont::ArrayHandle<ComponentType, vtkm::cont::StorageTagBasic>& dest)
|
||||
{
|
||||
if (GetNumberOfComponents(buffers) != 1)
|
||||
{
|
||||
throw vtkm::cont::ErrorBadType(
|
||||
"Attempted to pull a scalar array from an ArrayHandleRuntime that does not hold scalars.");
|
||||
}
|
||||
dest = GetComponentsArray(buffers);
|
||||
}
|
||||
|
||||
template <vtkm::IdComponent N>
|
||||
VTKM_CONT static void AsArrayHandleBasic(
|
||||
const std::vector<vtkm::cont::internal::Buffer>& buffers,
|
||||
vtkm::cont::ArrayHandle<vtkm::Vec<ComponentType, N>, vtkm::cont::StorageTagBasic>& dest)
|
||||
{
|
||||
if (GetNumberOfComponents(buffers) != N)
|
||||
{
|
||||
throw vtkm::cont::ErrorBadType(
|
||||
"Attempted to pull an array of Vecs of the wrong size from an ArrayHandleRuntime.");
|
||||
}
|
||||
dest = vtkm::cont::ArrayHandle<vtkm::Vec<ComponentType, N>, vtkm::cont::StorageTagBasic>(
|
||||
ComponentsBuffers(buffers));
|
||||
}
|
||||
|
||||
template <typename T, vtkm::IdComponent NInner, vtkm::IdComponent NOuter>
|
||||
VTKM_CONT static void AsArrayHandleBasic(
|
||||
const std::vector<vtkm::cont::internal::Buffer>& buffers,
|
||||
vtkm::cont::ArrayHandle<vtkm::Vec<vtkm::Vec<T, NInner>, NOuter>, vtkm::cont::StorageTagBasic>&
|
||||
dest)
|
||||
{
|
||||
// Flatten the Vec by one level and attempt to get the array handle for that.
|
||||
vtkm::cont::ArrayHandleBasic<vtkm::Vec<T, NInner * NOuter>> squashedArray;
|
||||
AsArrayHandleBasic(buffers, squashedArray);
|
||||
// Now unsquash the array by stealling the buffers and creating an array of the right type
|
||||
dest =
|
||||
vtkm::cont::ArrayHandle<vtkm::Vec<vtkm::Vec<T, NInner>, NOuter>, vtkm::cont::StorageTagBasic>(
|
||||
squashedArray.GetBuffers());
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
|
||||
/// \brief Fancy array handle for a basic array with runtime selected vec size.
|
||||
///
|
||||
/// It is sometimes the case that you need to create an array of `Vec`s where
|
||||
/// the number of components is not known until runtime. This is problematic
|
||||
/// for normal `ArrayHandle`s because you have to specify the size of the `Vec`s
|
||||
/// as a template parameter at compile time. `ArrayHandleRuntimeVec` can be used
|
||||
/// in this case.
|
||||
///
|
||||
/// Note that this version of `ArrayHandle` breaks some of the assumptions
|
||||
/// about `ArrayHandle` a little bit. Typically, there is exactly one type for
|
||||
/// every value in the array, and this value is also the same between the
|
||||
/// control and execution environment. However, this class uses `VecFromPortal`
|
||||
/// it implement a `Vec`-like class that has a variable number of
|
||||
/// values, and this type can change between control and execution
|
||||
/// environments.
|
||||
///
|
||||
/// It is possible to provide an `ArrayHandleBasic` of the same component
|
||||
/// type as the underlying storage for this array. In this case, the array
|
||||
/// will be accessed much in the same manner as `ArrayHandleGroupVec`.
|
||||
///
|
||||
/// `ArrayHandleRuntimeVec` also allows you to convert the array to an
|
||||
/// `ArrayHandleBasic` of the appropriate `Vec` type (or `component` type).
|
||||
/// A runtime check will be performed to make sure the number of components
|
||||
/// matches.
|
||||
///
|
||||
template <typename ComponentType>
|
||||
class ArrayHandleRuntimeVec
|
||||
: public vtkm::cont::ArrayHandle<
|
||||
vtkm::VecFromPortal<typename ArrayHandleBasic<ComponentType>::WritePortalType>,
|
||||
vtkm::cont::StorageTagRuntimeVec>
|
||||
{
|
||||
public:
|
||||
VTKM_ARRAY_HANDLE_SUBCLASS(
|
||||
ArrayHandleRuntimeVec,
|
||||
(ArrayHandleRuntimeVec<ComponentType>),
|
||||
(vtkm::cont::ArrayHandle<
|
||||
vtkm::VecFromPortal<typename ArrayHandleBasic<ComponentType>::WritePortalType>,
|
||||
vtkm::cont::StorageTagRuntimeVec>));
|
||||
|
||||
private:
|
||||
using StorageType = vtkm::cont::internal::Storage<ValueType, StorageTag>;
|
||||
using ComponentsArrayType = vtkm::cont::ArrayHandle<ComponentType, StorageTagBasic>;
|
||||
|
||||
public:
|
||||
VTKM_CONT
|
||||
ArrayHandleRuntimeVec(vtkm::IdComponent numComponents,
|
||||
const ComponentsArrayType& componentsArray = ComponentsArrayType{})
|
||||
: Superclass(StorageType::CreateBuffers(numComponents, componentsArray))
|
||||
{
|
||||
}
|
||||
|
||||
VTKM_CONT vtkm::IdComponent GetNumberOfComponents() const
|
||||
{
|
||||
return StorageType::GetNumberOfComponents(this->GetBuffers());
|
||||
}
|
||||
|
||||
VTKM_CONT vtkm::cont::ArrayHandleBasic<ComponentType> GetComponentsArray() const
|
||||
{
|
||||
return StorageType::GetComponentsArray(this->GetBuffers());
|
||||
}
|
||||
|
||||
///@{
|
||||
/// \brief Converts the array to that of a basic array handle.
|
||||
///
|
||||
/// This method converts the `ArrayHandleRuntimeVec` to a simple `ArrayHandleBasic`.
|
||||
/// This is useful if the `ArrayHandleRuntimeVec` is passed to a routine that works
|
||||
/// on an array of a specific `Vec` size (or scalars). After a runtime check, the
|
||||
/// array can be converted to a typical array and used as such.
|
||||
template <typename ValueType>
|
||||
void AsArrayHandleBasic(vtkm::cont::ArrayHandle<ValueType>& array) const
|
||||
{
|
||||
StorageType::AsArrayHandleBasic(this->GetBuffers(), array);
|
||||
}
|
||||
|
||||
template <typename ArrayType>
|
||||
ArrayType AsArrayHandleBasic() const
|
||||
{
|
||||
ArrayType array;
|
||||
this->AsArrayHandleBasic(array);
|
||||
return array;
|
||||
}
|
||||
///@}
|
||||
};
|
||||
|
||||
/// \c make_ArrayHandleRuntimeVec is convenience function to generate an
|
||||
/// ArrayHandleRuntimeVec. It takes in an ArrayHandle of values and an
|
||||
/// array handle of offsets and returns an array handle with consecutive
|
||||
/// entries grouped in a Vec.
|
||||
///
|
||||
template <typename T>
|
||||
VTKM_CONT vtkm::cont::ArrayHandleRuntimeVec<T> make_ArrayHandleRuntimeVec(
|
||||
vtkm::IdComponent numComponents,
|
||||
const vtkm::cont::ArrayHandle<T, vtkm::cont::StorageTagBasic>& componentsArray)
|
||||
{
|
||||
return vtkm::cont::ArrayHandleRuntimeVec<T>(numComponents, componentsArray);
|
||||
}
|
||||
|
||||
namespace internal
|
||||
{
|
||||
|
||||
template <>
|
||||
struct ArrayExtractComponentImpl<vtkm::cont::StorageTagRuntimeVec>
|
||||
{
|
||||
template <typename T>
|
||||
auto operator()(const vtkm::cont::ArrayHandle<T, vtkm::cont::StorageTagRuntimeVec>& src,
|
||||
vtkm::IdComponent componentIndex,
|
||||
vtkm::CopyFlag allowCopy) const
|
||||
{
|
||||
using ComponentType = typename T::ComponentType;
|
||||
vtkm::cont::ArrayHandleRuntimeVec<ComponentType> array{ src };
|
||||
constexpr vtkm::IdComponent NUM_SUB_COMPONENTS = vtkm::VecFlat<ComponentType>::NUM_COMPONENTS;
|
||||
vtkm::cont::ArrayHandleStride<typename vtkm::VecTraits<T>::BaseComponentType> dest =
|
||||
ArrayExtractComponentImpl<vtkm::cont::StorageTagBasic>{}(
|
||||
array.GetComponentsArray(), componentIndex % NUM_SUB_COMPONENTS, allowCopy);
|
||||
|
||||
// Adjust stride and offset to expectations of grouped values
|
||||
const vtkm::IdComponent numComponents = array.GetNumberOfComponents();
|
||||
return vtkm::cont::ArrayHandleStride<typename vtkm::VecTraits<T>::BaseComponentType>(
|
||||
dest.GetBasicArray(),
|
||||
dest.GetNumberOfValues() / numComponents,
|
||||
dest.GetStride() * numComponents,
|
||||
dest.GetOffset() + (dest.GetStride() * (componentIndex / NUM_SUB_COMPONENTS)),
|
||||
dest.GetModulo(),
|
||||
dest.GetDivisor());
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
|
||||
}
|
||||
} // namespace vtkm::cont
|
||||
|
||||
//=============================================================================
|
||||
// Specializations of serialization related classes
|
||||
/// @cond SERIALIZATION
|
||||
namespace vtkm
|
||||
{
|
||||
namespace cont
|
||||
{
|
||||
|
||||
template <typename T>
|
||||
struct SerializableTypeString<vtkm::cont::ArrayHandleRuntimeVec<T>>
|
||||
{
|
||||
static VTKM_CONT const std::string& Get()
|
||||
{
|
||||
static std::string name = "AH_RuntimeVec<" + SerializableTypeString<T>::Get() + ">";
|
||||
return name;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename VecType>
|
||||
struct SerializableTypeString<vtkm::cont::ArrayHandle<VecType, vtkm::cont::StorageTagRuntimeVec>>
|
||||
: SerializableTypeString<vtkm::cont::ArrayHandleRuntimeVec<typename VecType::ComponentType>>
|
||||
{
|
||||
};
|
||||
|
||||
}
|
||||
} // vtkm::cont
|
||||
|
||||
namespace mangled_diy_namespace
|
||||
{
|
||||
|
||||
template <typename T>
|
||||
struct Serialization<vtkm::cont::ArrayHandleRuntimeVec<T>>
|
||||
{
|
||||
private:
|
||||
using Type = vtkm::cont::ArrayHandleRuntimeVec<T>;
|
||||
using BaseType = vtkm::cont::ArrayHandle<typename Type::ValueType, typename Type::StorageTag>;
|
||||
|
||||
public:
|
||||
static VTKM_CONT void save(BinaryBuffer& bb, const BaseType& obj)
|
||||
{
|
||||
vtkmdiy::save(bb, Type(obj).GetNumberOfComponents());
|
||||
vtkmdiy::save(bb, Type(obj).GetComponentsArray());
|
||||
}
|
||||
|
||||
static VTKM_CONT void load(BinaryBuffer& bb, BaseType& obj)
|
||||
{
|
||||
vtkm::IdComponent numComponents;
|
||||
vtkm::cont::ArrayHandleBasic<T> componentArray;
|
||||
|
||||
vtkmdiy::load(bb, numComponents);
|
||||
vtkmdiy::load(bb, componentArray);
|
||||
|
||||
obj = vtkm::cont::make_ArrayHandleRuntimeVec(numComponents, componentArray);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename VecType>
|
||||
struct Serialization<vtkm::cont::ArrayHandle<VecType, vtkm::cont::StorageTagRuntimeVec>>
|
||||
: Serialization<vtkm::cont::ArrayHandleRuntimeVec<typename VecType::ComponentType>>
|
||||
{
|
||||
};
|
||||
|
||||
} // diy
|
||||
/// @endcond SERIALIZATION
|
||||
|
||||
#endif //vtk_m_cont_ArrayHandleRuntimeVec_h
|
@ -38,6 +38,7 @@ set(headers
|
||||
ArrayHandleRandomStandardNormal.h
|
||||
ArrayHandleRandomUniformBits.h
|
||||
ArrayHandleRandomUniformReal.h
|
||||
ArrayHandleRuntimeVec.h
|
||||
ArrayHandleSOA.h
|
||||
ArrayHandleStride.h
|
||||
ArrayHandleSwizzle.h
|
||||
|
@ -85,6 +85,7 @@ set(unit_tests_device
|
||||
UnitTestArrayHandleRandomStandardNormal.cxx
|
||||
UnitTestArrayHandleRandomUniformReal.cxx
|
||||
UnitTestArrayHandleRecombineVec.cxx
|
||||
UnitTestArrayHandleRuntimeVec.cxx
|
||||
UnitTestArrayHandleSOA.cxx
|
||||
UnitTestArrayHandleSwizzle.cxx
|
||||
UnitTestArrayHandleTransform.cxx
|
||||
|
@ -17,6 +17,7 @@
|
||||
#include <vtkm/cont/ArrayHandleIndex.h>
|
||||
#include <vtkm/cont/ArrayHandleMultiplexer.h>
|
||||
#include <vtkm/cont/ArrayHandleReverse.h>
|
||||
#include <vtkm/cont/ArrayHandleRuntimeVec.h>
|
||||
#include <vtkm/cont/ArrayHandleSOA.h>
|
||||
#include <vtkm/cont/ArrayHandleUniformPointCoordinates.h>
|
||||
#include <vtkm/cont/ArrayHandleView.h>
|
||||
@ -34,39 +35,79 @@ namespace
|
||||
|
||||
constexpr vtkm::Id ARRAY_SIZE = 10;
|
||||
|
||||
template <typename T>
|
||||
vtkm::IdComponent GetTotalNumComponents(const T& vec)
|
||||
{
|
||||
using VTraits = vtkm::VecTraits<T>;
|
||||
if (std::is_same<typename VTraits::ComponentType, typename VTraits::BaseComponentType>::value)
|
||||
{
|
||||
return VTraits::GetNumberOfComponents(vec);
|
||||
}
|
||||
else
|
||||
{
|
||||
return VTraits::GetNumberOfComponents(vec) *
|
||||
GetTotalNumComponents(VTraits::GetComponent(vec, 0));
|
||||
}
|
||||
}
|
||||
|
||||
// VecFlat.h has something similar, but it only works with static Vec sizes. It might make sense
|
||||
// to move this somewhere else later
|
||||
template <typename BaseComponentType>
|
||||
struct GetVecFlatIndexImpl
|
||||
{
|
||||
template <typename VecType>
|
||||
VTKM_CONT BaseComponentType operator()(const VecType& vec, vtkm::IdComponent index) const
|
||||
{
|
||||
const vtkm::IdComponent subSize = GetTotalNumComponents(vec[0]);
|
||||
return (*this)(vec[index / subSize], index % subSize);
|
||||
}
|
||||
|
||||
VTKM_CONT BaseComponentType operator()(const BaseComponentType& component,
|
||||
vtkm::IdComponent index) const
|
||||
{
|
||||
VTKM_ASSERT(index == 0);
|
||||
return component;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
auto GetVecFlatIndex(const T& vec, vtkm::IdComponent index)
|
||||
{
|
||||
return GetVecFlatIndexImpl<typename vtkm::VecTraits<T>::BaseComponentType>{}(vec, index);
|
||||
}
|
||||
|
||||
template <typename T, typename S>
|
||||
void CheckInputArray(const vtkm::cont::ArrayHandle<T, S>& originalArray,
|
||||
vtkm::CopyFlag allowCopy = vtkm::CopyFlag::Off)
|
||||
{
|
||||
using FlatVec = vtkm::VecFlat<T>;
|
||||
using ComponentType = typename FlatVec::ComponentType;
|
||||
for (vtkm::IdComponent componentId = 0; componentId < FlatVec::NUM_COMPONENTS; ++componentId)
|
||||
auto originalPortal = originalArray.ReadPortal();
|
||||
using ComponentType = typename vtkm::VecTraits<T>::BaseComponentType;
|
||||
const vtkm::IdComponent numComponents = GetTotalNumComponents(originalPortal.Get(0));
|
||||
for (vtkm::IdComponent componentId = 0; componentId < numComponents; ++componentId)
|
||||
{
|
||||
vtkm::cont::ArrayHandleStride<ComponentType> componentArray =
|
||||
vtkm::cont::ArrayExtractComponent(originalArray, componentId, allowCopy);
|
||||
|
||||
auto originalPortal = originalArray.ReadPortal();
|
||||
auto componentPortal = componentArray.ReadPortal();
|
||||
VTKM_TEST_ASSERT(originalPortal.GetNumberOfValues() == componentPortal.GetNumberOfValues());
|
||||
for (vtkm::Id arrayIndex = 0; arrayIndex < originalArray.GetNumberOfValues(); ++arrayIndex)
|
||||
{
|
||||
auto originalValue = vtkm::make_VecFlat(originalPortal.Get(arrayIndex));
|
||||
auto originalValue = GetVecFlatIndex(originalPortal.Get(arrayIndex), componentId);
|
||||
ComponentType componentValue = componentPortal.Get(arrayIndex);
|
||||
VTKM_TEST_ASSERT(test_equal(originalValue[componentId], componentValue));
|
||||
VTKM_TEST_ASSERT(test_equal(originalValue, componentValue));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T, typename S>
|
||||
void CheckOutputArray(const vtkm::cont::ArrayHandle<T, S>& originalArray)
|
||||
void CheckOutputArray(
|
||||
const vtkm::cont::ArrayHandle<T, S>& originalArray,
|
||||
const vtkm::cont::ArrayHandle<T, S>& outputArray = vtkm::cont::ArrayHandle<T, S>{})
|
||||
{
|
||||
CheckInputArray(originalArray);
|
||||
|
||||
vtkm::cont::ArrayHandle<T, S> outputArray;
|
||||
|
||||
using FlatVec = vtkm::VecFlat<T>;
|
||||
using ComponentType = typename FlatVec::ComponentType;
|
||||
constexpr vtkm::IdComponent numComponents = FlatVec::NUM_COMPONENTS;
|
||||
using ComponentType = typename vtkm::VecTraits<T>::BaseComponentType;
|
||||
const vtkm::IdComponent numComponents = GetTotalNumComponents(originalArray.ReadPortal().Get(0));
|
||||
|
||||
// Extract all the stride arrays first, and then allocate them later. This tests to
|
||||
// to make sure that the independent allocation of all the extracted arrays are consistent
|
||||
@ -105,11 +146,12 @@ void CheckOutputArray(const vtkm::cont::ArrayHandle<T, S>& originalArray)
|
||||
auto outPortal = outputArray.ReadPortal();
|
||||
for (vtkm::Id arrayIndex = 0; arrayIndex < originalArray.GetNumberOfValues(); ++arrayIndex)
|
||||
{
|
||||
FlatVec inValue = vtkm::make_VecFlat(inPortal.Get(arrayIndex));
|
||||
FlatVec outValue = vtkm::make_VecFlat(outPortal.Get(arrayIndex));
|
||||
auto inValue = inPortal.Get(arrayIndex);
|
||||
auto outValue = outPortal.Get(arrayIndex);
|
||||
for (vtkm::IdComponent componentId = 0; componentId < numComponents; ++componentId)
|
||||
{
|
||||
VTKM_TEST_ASSERT(test_equal(inValue[componentId], outValue[numComponents - componentId - 1]));
|
||||
VTKM_TEST_ASSERT(test_equal(GetVecFlatIndex(inValue, componentId),
|
||||
GetVecFlatIndex(outValue, numComponents - componentId - 1)));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -161,9 +203,10 @@ void DoTest()
|
||||
{
|
||||
std::cout << "ArrayHandleGroupVec" << std::endl;
|
||||
vtkm::cont::ArrayHandle<vtkm::Vec3f> array;
|
||||
array.Allocate(ARRAY_SIZE * 2);
|
||||
array.Allocate(ARRAY_SIZE * 4);
|
||||
SetPortal(array.WritePortal());
|
||||
CheckOutputArray(vtkm::cont::make_ArrayHandleGroupVec<2>(array));
|
||||
CheckOutputArray(vtkm::cont::make_ArrayHandleGroupVec<4>(array));
|
||||
}
|
||||
|
||||
{
|
||||
@ -185,6 +228,17 @@ void DoTest()
|
||||
CheckInputArray(vtkm::cont::make_ArrayHandleExtractComponent(compositeArray, 1));
|
||||
}
|
||||
|
||||
{
|
||||
std::cout << "ArrayHandleRuntimeVec" << std::endl;
|
||||
vtkm::cont::ArrayHandle<vtkm::Vec3f> array;
|
||||
array.Allocate(ARRAY_SIZE * 4);
|
||||
SetPortal(array.WritePortal());
|
||||
CheckOutputArray(vtkm::cont::make_ArrayHandleRuntimeVec(2, array),
|
||||
vtkm::cont::ArrayHandleRuntimeVec<vtkm::Vec3f>(2));
|
||||
CheckOutputArray(vtkm::cont::make_ArrayHandleRuntimeVec(4, array),
|
||||
vtkm::cont::ArrayHandleRuntimeVec<vtkm::Vec3f>(4));
|
||||
}
|
||||
|
||||
{
|
||||
std::cout << "ArrayHandleCartesianProduct" << std::endl;
|
||||
vtkm::cont::ArrayHandle<vtkm::Float64> array0;
|
||||
|
201
vtkm/cont/testing/UnitTestArrayHandleRuntimeVec.cxx
Normal file
201
vtkm/cont/testing/UnitTestArrayHandleRuntimeVec.cxx
Normal file
@ -0,0 +1,201 @@
|
||||
//============================================================================
|
||||
// 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/ArrayHandleRuntimeVec.h>
|
||||
|
||||
#include <vtkm/cont/Invoker.h>
|
||||
|
||||
#include <vtkm/worklet/WorkletMapField.h>
|
||||
|
||||
#include <vtkm/cont/testing/Testing.h>
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
constexpr vtkm::Id ARRAY_SIZE = 10;
|
||||
|
||||
struct UnusualType
|
||||
{
|
||||
vtkm::Id X;
|
||||
};
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
namespace detail
|
||||
{
|
||||
|
||||
template <>
|
||||
struct TestValueImpl<UnusualType>
|
||||
{
|
||||
VTKM_EXEC_CONT UnusualType operator()(vtkm::Id index) const
|
||||
{
|
||||
return { TestValue(index, decltype(UnusualType::X){}) };
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct TestEqualImpl<UnusualType, UnusualType>
|
||||
{
|
||||
VTKM_EXEC_CONT bool operator()(UnusualType value1,
|
||||
UnusualType value2,
|
||||
vtkm::Float64 tolerance) const
|
||||
{
|
||||
return test_equal(value1.X, value2.X, tolerance);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
struct PassThrough : vtkm::worklet::WorkletMapField
|
||||
{
|
||||
using ControlSignature = void(FieldIn, FieldOut);
|
||||
using ExecutionSignature = void(_1, _2);
|
||||
|
||||
template <typename InValue, typename OutValue>
|
||||
VTKM_EXEC void operator()(const InValue& inValue, OutValue& outValue) const
|
||||
{
|
||||
outValue = inValue;
|
||||
}
|
||||
};
|
||||
|
||||
template <vtkm::IdComponent NUM_COMPONENTS>
|
||||
struct TestRuntimeVecAsInput
|
||||
{
|
||||
template <typename ComponentType>
|
||||
VTKM_CONT void operator()(ComponentType) const
|
||||
{
|
||||
using ValueType = vtkm::Vec<ComponentType, NUM_COMPONENTS>;
|
||||
|
||||
vtkm::cont::ArrayHandle<ComponentType> baseArray;
|
||||
baseArray.Allocate(ARRAY_SIZE * NUM_COMPONENTS);
|
||||
SetPortal(baseArray.WritePortal());
|
||||
|
||||
vtkm::cont::ArrayHandleRuntimeVec<ComponentType> runtimeVecArray(NUM_COMPONENTS, baseArray);
|
||||
VTKM_TEST_ASSERT(runtimeVecArray.GetNumberOfValues() == ARRAY_SIZE,
|
||||
"Group array reporting wrong array size.");
|
||||
|
||||
vtkm::cont::ArrayHandle<ValueType> resultArray;
|
||||
|
||||
vtkm::cont::Invoker{}(PassThrough{}, runtimeVecArray, resultArray);
|
||||
|
||||
VTKM_TEST_ASSERT(resultArray.GetNumberOfValues() == ARRAY_SIZE, "Got bad result array size.");
|
||||
|
||||
//verify that the control portal works
|
||||
vtkm::Id totalIndex = 0;
|
||||
auto resultPortal = resultArray.ReadPortal();
|
||||
for (vtkm::Id index = 0; index < ARRAY_SIZE; ++index)
|
||||
{
|
||||
const ValueType result = resultPortal.Get(index);
|
||||
for (vtkm::IdComponent componentIndex = 0; componentIndex < NUM_COMPONENTS; componentIndex++)
|
||||
{
|
||||
const ComponentType expectedValue = TestValue(totalIndex, ComponentType());
|
||||
VTKM_TEST_ASSERT(test_equal(result[componentIndex], expectedValue),
|
||||
"Result array got wrong value.");
|
||||
totalIndex++;
|
||||
}
|
||||
}
|
||||
|
||||
//verify that you can get the data as a basic array
|
||||
vtkm::cont::ArrayHandle<vtkm::Vec<ComponentType, NUM_COMPONENTS>> flatComponents;
|
||||
runtimeVecArray.AsArrayHandleBasic(flatComponents);
|
||||
VTKM_TEST_ASSERT(test_equal_ArrayHandles(flatComponents, runtimeVecArray));
|
||||
|
||||
vtkm::cont::ArrayHandle<vtkm::Vec<vtkm::Vec<ComponentType, 1>, NUM_COMPONENTS>>
|
||||
nestedComponents;
|
||||
runtimeVecArray.AsArrayHandleBasic(nestedComponents);
|
||||
auto flatPortal = flatComponents.ReadPortal();
|
||||
auto nestedPortal = nestedComponents.ReadPortal();
|
||||
for (vtkm::Id index = 0; index < flatPortal.GetNumberOfValues(); ++index)
|
||||
{
|
||||
VTKM_TEST_ASSERT(test_equal(vtkm::make_VecFlat(flatPortal.Get(index)),
|
||||
vtkm::make_VecFlat(nestedPortal.Get(index))));
|
||||
}
|
||||
|
||||
runtimeVecArray.ReleaseResources();
|
||||
}
|
||||
};
|
||||
|
||||
template <vtkm::IdComponent NUM_COMPONENTS>
|
||||
struct TestRuntimeVecAsOutput
|
||||
{
|
||||
template <typename ComponentType>
|
||||
VTKM_CONT void operator()(ComponentType) const
|
||||
{
|
||||
using ValueType = vtkm::Vec<ComponentType, NUM_COMPONENTS>;
|
||||
|
||||
vtkm::cont::ArrayHandle<ValueType> baseArray;
|
||||
baseArray.Allocate(ARRAY_SIZE);
|
||||
SetPortal(baseArray.WritePortal());
|
||||
|
||||
vtkm::cont::ArrayHandle<ComponentType> resultArray;
|
||||
|
||||
vtkm::cont::ArrayHandleRuntimeVec<ComponentType> runtimeVecArray(NUM_COMPONENTS, resultArray);
|
||||
|
||||
vtkm::cont::Invoker{}(PassThrough{}, baseArray, runtimeVecArray);
|
||||
|
||||
VTKM_TEST_ASSERT(runtimeVecArray.GetNumberOfValues() == ARRAY_SIZE,
|
||||
"Group array reporting wrong array size.");
|
||||
|
||||
VTKM_TEST_ASSERT(resultArray.GetNumberOfValues() == ARRAY_SIZE * NUM_COMPONENTS,
|
||||
"Got bad result array size.");
|
||||
|
||||
//verify that the control portal works
|
||||
vtkm::Id totalIndex = 0;
|
||||
auto resultPortal = resultArray.ReadPortal();
|
||||
for (vtkm::Id index = 0; index < ARRAY_SIZE; ++index)
|
||||
{
|
||||
const ValueType expectedValue = TestValue(index, ValueType());
|
||||
for (vtkm::IdComponent componentIndex = 0; componentIndex < NUM_COMPONENTS; componentIndex++)
|
||||
{
|
||||
const ComponentType result = resultPortal.Get(totalIndex);
|
||||
VTKM_TEST_ASSERT(test_equal(result, expectedValue[componentIndex]),
|
||||
"Result array got wrong value.");
|
||||
totalIndex++;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
void Run()
|
||||
{
|
||||
using HandleTypesToTest =
|
||||
vtkm::List<vtkm::Id, vtkm::Vec2i_32, vtkm::FloatDefault, vtkm::Vec3f_64>;
|
||||
using ScalarTypesToTest = vtkm::List<vtkm::UInt8, vtkm::FloatDefault>;
|
||||
|
||||
std::cout << "-------------------------------------------" << std::endl;
|
||||
std::cout << "Testing ArrayHandleRuntimeVec(3) as Input" << std::endl;
|
||||
vtkm::testing::Testing::TryTypes(TestRuntimeVecAsInput<3>(), HandleTypesToTest());
|
||||
|
||||
std::cout << "-------------------------------------------" << std::endl;
|
||||
std::cout << "Testing ArrayHandleRuntimeVec(4) as Input" << std::endl;
|
||||
vtkm::testing::Testing::TryTypes(TestRuntimeVecAsInput<4>(), HandleTypesToTest());
|
||||
|
||||
std::cout << "-------------------------------------------" << std::endl;
|
||||
std::cout << "Testing ArrayHandleRuntimeVec(2) as Output" << std::endl;
|
||||
vtkm::testing::Testing::TryTypes(TestRuntimeVecAsOutput<2>(), ScalarTypesToTest());
|
||||
|
||||
std::cout << "-------------------------------------------" << std::endl;
|
||||
std::cout << "Testing ArrayHandleRuntimeVec(3) as Output" << std::endl;
|
||||
vtkm::testing::Testing::TryTypes(TestRuntimeVecAsOutput<3>(), ScalarTypesToTest());
|
||||
|
||||
std::cout << "-------------------------------------------" << std::endl;
|
||||
std::cout << "Testing ArrayHandleRuntimeVec(3) as Input with unusual type" << std::endl;
|
||||
TestRuntimeVecAsInput<3>{}(UnusualType{});
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
int UnitTestArrayHandleRuntimeVec(int argc, char* argv[])
|
||||
{
|
||||
return vtkm::cont::testing::Testing::Run(Run, argc, argv);
|
||||
}
|
@ -22,6 +22,7 @@
|
||||
#include <vtkm/cont/ArrayHandleIndex.h>
|
||||
#include <vtkm/cont/ArrayHandlePermutation.h>
|
||||
#include <vtkm/cont/ArrayHandleReverse.h>
|
||||
#include <vtkm/cont/ArrayHandleRuntimeVec.h>
|
||||
#include <vtkm/cont/ArrayHandleSOA.h>
|
||||
#include <vtkm/cont/ArrayHandleSwizzle.h>
|
||||
#include <vtkm/cont/ArrayHandleTransform.h>
|
||||
@ -303,6 +304,20 @@ struct TestArrayHandleGroupVecVariable
|
||||
}
|
||||
};
|
||||
|
||||
struct TestArrayHandleRuntimeVec
|
||||
{
|
||||
template <typename T>
|
||||
void operator()(T) const
|
||||
{
|
||||
auto numComps = RandomValue<vtkm::IdComponent>::Make(1, 5);
|
||||
auto flat = RandomArrayHandle<T>::Make(ArraySize * numComps);
|
||||
auto array = vtkm::cont::make_ArrayHandleRuntimeVec(numComps, flat);
|
||||
RunTest(array);
|
||||
// TODO: Add this back once UnknownArrayHandle supports ArrayHandleRuntimeVec more fully.
|
||||
//RunTest(MakeTestUnknownArrayHandle(array));
|
||||
}
|
||||
};
|
||||
|
||||
void TestArrayHandleIndex()
|
||||
{
|
||||
auto size = RandomValue<vtkm::Id>::Make(2, 10);
|
||||
@ -413,6 +428,9 @@ void TestArrayHandleSerialization()
|
||||
std::cout << "Testing ArrayHandleGroupVecVariable\n";
|
||||
vtkm::testing::Testing::TryTypes(TestArrayHandleGroupVecVariable(), TestTypesList());
|
||||
|
||||
std::cout << "Testing ArrayHandleRuntimeVec\n";
|
||||
vtkm::testing::Testing::TryTypes(TestArrayHandleRuntimeVec(), TestTypesList());
|
||||
|
||||
std::cout << "Testing ArrayHandleIndex\n";
|
||||
TestArrayHandleIndex();
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user