ac889b5004
The `VecTraits` class allows templated functions, methods, and classes to treat type arguments uniformly as `Vec` types or to otherwise differentiate between scalar and vector types. This only works for types that `VecTraits` is defined for. The `VecTraits` templated class now has a default implementation that will be used for any type that does not have a `VecTraits` specialization. This removes many surprise compiler errors when using a template that, unknown to you, has `VecTraits` in its implementation. One potential issue is that if `VecTraits` gets defined for a new type, the behavior of `VecTraits` could change for that type in backward-incompatible ways. If `VecTraits` is used in a purely generic way, this should not be an issue. However, if assumptions were made about the components and length, this could cause problems. Fixes #589
1358 lines
53 KiB
C++
1358 lines
53 KiB
C++
//============================================================================
|
|
// 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_UnknownArrayHandle_h
|
|
#define vtk_m_cont_UnknownArrayHandle_h
|
|
|
|
#include <vtkm/cont/vtkm_cont_export.h>
|
|
|
|
#include <vtkm/cont/ArrayExtractComponent.h>
|
|
#include <vtkm/cont/ArrayHandle.h>
|
|
#include <vtkm/cont/ArrayHandleCast.h>
|
|
#include <vtkm/cont/ArrayHandleMultiplexer.h>
|
|
#include <vtkm/cont/ArrayHandleRecombineVec.h>
|
|
#include <vtkm/cont/ArrayHandleRuntimeVec.h>
|
|
#include <vtkm/cont/ArrayHandleStride.h>
|
|
#include <vtkm/cont/StorageList.h>
|
|
|
|
#include <vtkm/Deprecated.h>
|
|
#include <vtkm/TypeList.h>
|
|
|
|
#include <memory>
|
|
#include <typeindex>
|
|
|
|
namespace vtkm
|
|
{
|
|
namespace cont
|
|
{
|
|
|
|
namespace detail
|
|
{
|
|
|
|
template <typename T, typename S>
|
|
void UnknownAHDelete(void* mem)
|
|
{
|
|
using AH = vtkm::cont::ArrayHandle<T, S>;
|
|
AH* arrayHandle = reinterpret_cast<AH*>(mem);
|
|
delete arrayHandle;
|
|
}
|
|
|
|
template <typename T, typename S>
|
|
const std::vector<vtkm::cont::internal::Buffer>& UnknownAHBuffers(void* mem)
|
|
{
|
|
using AH = vtkm::cont::ArrayHandle<T, S>;
|
|
AH* arrayHandle = reinterpret_cast<AH*>(mem);
|
|
return arrayHandle->GetBuffers();
|
|
}
|
|
|
|
template <typename T, typename S>
|
|
void* UnknownAHNewInstance()
|
|
{
|
|
return new vtkm::cont::ArrayHandle<T, S>;
|
|
}
|
|
|
|
template <typename T, typename S>
|
|
vtkm::Id UnknownAHNumberOfValues(void* mem)
|
|
{
|
|
using AH = vtkm::cont::ArrayHandle<T, S>;
|
|
AH* arrayHandle = reinterpret_cast<AH*>(mem);
|
|
return arrayHandle->GetNumberOfValues();
|
|
}
|
|
|
|
// Uses SFINAE to use Storage<>::GetNumberOfComponents if it exists, or the VecTraits otherwise
|
|
template <typename T, typename S>
|
|
inline auto UnknownAHNumberOfComponentsImpl(void* mem)
|
|
-> decltype(vtkm::cont::internal::Storage<T, S>::GetNumberOfComponents(
|
|
std::vector<vtkm::cont::internal::Buffer>()))
|
|
{
|
|
using AH = vtkm::cont::ArrayHandle<T, S>;
|
|
AH* arrayHandle = reinterpret_cast<AH*>(mem);
|
|
return vtkm::cont::internal::Storage<T, S>::GetNumberOfComponents(arrayHandle->GetBuffers());
|
|
}
|
|
|
|
// Uses SFINAE to use the number of compnents in VecTraits.
|
|
// Note that this will conflict with the above overloaded function if the storage has a
|
|
// GetNumberOfComponents method and VecTraits has a static size. However, I cannot think
|
|
// of a use case for the storage to report the number of components for a static data type.
|
|
// If that happens, this implementation will need to be modified.
|
|
template <typename T, typename S>
|
|
inline auto UnknownAHNumberOfComponentsImpl(void*) -> decltype(vtkm::VecTraits<T>::NUM_COMPONENTS)
|
|
{
|
|
static constexpr vtkm::IdComponent numComponents = vtkm::VecTraits<T>::NUM_COMPONENTS;
|
|
return numComponents;
|
|
}
|
|
|
|
// Fallback for when there is no way to determine the number of components. (This could be
|
|
// because each value could have a different number of components.
|
|
template <typename T, typename S>
|
|
inline vtkm::IdComponent UnknownAHNumberOfComponentsImpl(...)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
template <typename T, typename S>
|
|
vtkm::IdComponent UnknownAHNumberOfComponents(void* mem)
|
|
{
|
|
return UnknownAHNumberOfComponentsImpl<T, S>(mem);
|
|
}
|
|
|
|
// Uses SFINAE to use Storage<>::GetNumberOfComponents if it exists, or the VecTraits otherwise
|
|
template <typename T, typename S>
|
|
inline auto UnknownAHNumberOfComponentsFlatImpl(void* mem)
|
|
-> decltype(vtkm::cont::internal::Storage<T, S>::GetNumberOfComponents(
|
|
std::vector<vtkm::cont::internal::Buffer>()))
|
|
{
|
|
using AH = vtkm::cont::ArrayHandle<T, S>;
|
|
AH* arrayHandle = reinterpret_cast<AH*>(mem);
|
|
// Making an assumption here that `T` is a `Vec`-like object that `GetNumberOfComponents`
|
|
// will report on how many each has. Further assuming that the components of `T` are
|
|
// static. If a future `ArrayHandle` type violates this, this code will have to become
|
|
// more complex.
|
|
return (vtkm::cont::internal::Storage<T, S>::GetNumberOfComponents(arrayHandle->GetBuffers()) *
|
|
vtkm::VecFlat<typename vtkm::VecTraits<T>::ComponentType>::NUM_COMPONENTS);
|
|
}
|
|
|
|
// Uses SFINAE to use the number of compnents in VecTraits.
|
|
// Note that this will conflict with the above overloaded function if the storage has a
|
|
// GetNumberOfComponents method and VecTraits has a static size. However, I cannot think
|
|
// of a use case for the storage to report the number of components for a static data type.
|
|
// If that happens, this implementation will need to be modified.
|
|
template <typename T, typename S>
|
|
inline auto UnknownAHNumberOfComponentsFlatImpl(void*)
|
|
-> decltype(vtkm::VecTraits<T>::NUM_COMPONENTS)
|
|
{
|
|
// static constexpr vtkm::IdComponent numComponents = vtkm::VecFlat<T>::NUM_COMPONENTS;
|
|
// return numComponents;
|
|
return vtkm::VecFlat<T>::NUM_COMPONENTS;
|
|
}
|
|
|
|
// Fallback for when there is no way to determine the number of components. (This could be
|
|
// because each value could have a different number of components or just that VecTraits
|
|
// are not defined.) Since it cannot be flattened, just return the same as num components.
|
|
template <typename T, typename S>
|
|
inline vtkm::IdComponent UnknownAHNumberOfComponentsFlatImpl(...)
|
|
{
|
|
return UnknownAHNumberOfComponentsImpl<T, S>(static_cast<void*>(nullptr));
|
|
}
|
|
|
|
template <typename T, typename S>
|
|
vtkm::IdComponent UnknownAHNumberOfComponentsFlat(void* mem)
|
|
{
|
|
return UnknownAHNumberOfComponentsFlatImpl<T, S>(mem);
|
|
}
|
|
|
|
template <typename T, typename S>
|
|
void UnknownAHAllocate(void* mem,
|
|
vtkm::Id numValues,
|
|
vtkm::CopyFlag preserve,
|
|
vtkm::cont::Token& token)
|
|
{
|
|
using AH = vtkm::cont::ArrayHandle<T, S>;
|
|
AH* arrayHandle = reinterpret_cast<AH*>(mem);
|
|
arrayHandle->Allocate(numValues, preserve, token);
|
|
}
|
|
|
|
template <typename T, typename S>
|
|
void UnknownAHShallowCopy(const void* sourceMem, void* destinationMem)
|
|
{
|
|
using AH = vtkm::cont::ArrayHandle<T, S>;
|
|
const AH* source = reinterpret_cast<const AH*>(sourceMem);
|
|
AH* destination = reinterpret_cast<AH*>(destinationMem);
|
|
*destination = *source;
|
|
}
|
|
|
|
template <typename T, typename S>
|
|
void UnknownAHDeepCopy(const void* sourceMem, void* destinationMem)
|
|
{
|
|
using AH = vtkm::cont::ArrayHandle<T, S>;
|
|
const AH* source = reinterpret_cast<const AH*>(sourceMem);
|
|
AH* destination = reinterpret_cast<AH*>(destinationMem);
|
|
destination->DeepCopyFrom(*source);
|
|
}
|
|
|
|
template <typename T, typename S>
|
|
std::vector<vtkm::cont::internal::Buffer>
|
|
UnknownAHExtractComponent(void* mem, vtkm::IdComponent componentIndex, vtkm::CopyFlag allowCopy)
|
|
{
|
|
using AH = vtkm::cont::ArrayHandle<T, S>;
|
|
AH* arrayHandle = reinterpret_cast<AH*>(mem);
|
|
auto componentArray = vtkm::cont::ArrayExtractComponent(*arrayHandle, componentIndex, allowCopy);
|
|
return componentArray.GetBuffers();
|
|
}
|
|
|
|
template <typename T, typename S>
|
|
void UnknownAHReleaseResources(void* mem)
|
|
{
|
|
using AH = vtkm::cont::ArrayHandle<T, S>;
|
|
AH* arrayHandle = reinterpret_cast<AH*>(mem);
|
|
arrayHandle->ReleaseResources();
|
|
}
|
|
|
|
template <typename T, typename S>
|
|
void UnknownAHReleaseResourcesExecution(void* mem)
|
|
{
|
|
using AH = vtkm::cont::ArrayHandle<T, S>;
|
|
AH* arrayHandle = reinterpret_cast<AH*>(mem);
|
|
arrayHandle->ReleaseResourcesExecution();
|
|
}
|
|
|
|
template <typename T, typename S>
|
|
void UnknownAHPrintSummary(void* mem, std::ostream& out, bool full)
|
|
{
|
|
using AH = vtkm::cont::ArrayHandle<T, S>;
|
|
AH* arrayHandle = reinterpret_cast<AH*>(mem);
|
|
vtkm::cont::printSummary_ArrayHandle(*arrayHandle, out, full);
|
|
}
|
|
|
|
struct VTKM_CONT_EXPORT UnknownAHContainer;
|
|
|
|
struct MakeUnknownAHContainerFunctor
|
|
{
|
|
template <typename T, typename S>
|
|
std::shared_ptr<UnknownAHContainer> operator()(const vtkm::cont::ArrayHandle<T, S>& array) const;
|
|
};
|
|
|
|
struct VTKM_CONT_EXPORT UnknownAHComponentInfo
|
|
{
|
|
std::type_index Type;
|
|
bool IsIntegral;
|
|
bool IsFloat;
|
|
bool IsSigned;
|
|
std::size_t Size;
|
|
|
|
UnknownAHComponentInfo() = delete;
|
|
|
|
bool operator==(const UnknownAHComponentInfo& rhs);
|
|
|
|
template <typename T>
|
|
static UnknownAHComponentInfo Make()
|
|
{
|
|
return UnknownAHComponentInfo{ typeid(T),
|
|
std::is_integral<T>::value,
|
|
std::is_floating_point<T>::value,
|
|
std::is_signed<T>::value,
|
|
sizeof(T) };
|
|
}
|
|
|
|
private:
|
|
UnknownAHComponentInfo(std::type_index&& type,
|
|
bool isIntegral,
|
|
bool isFloat,
|
|
bool isSigned,
|
|
std::size_t size)
|
|
: Type(std::move(type))
|
|
, IsIntegral(isIntegral)
|
|
, IsFloat(isFloat)
|
|
, IsSigned(isSigned)
|
|
, Size(size)
|
|
{
|
|
}
|
|
};
|
|
|
|
struct VTKM_CONT_EXPORT UnknownAHContainer
|
|
{
|
|
void* ArrayHandlePointer;
|
|
|
|
std::type_index ValueType;
|
|
std::type_index StorageType;
|
|
UnknownAHComponentInfo BaseComponentType;
|
|
|
|
using DeleteType = void(void*);
|
|
DeleteType* DeleteFunction;
|
|
|
|
using BuffersType = const std::vector<vtkm::cont::internal::Buffer>&(void*);
|
|
BuffersType* Buffers;
|
|
|
|
using NewInstanceType = void*();
|
|
NewInstanceType* NewInstance;
|
|
|
|
using NewInstanceBasicType = std::shared_ptr<UnknownAHContainer>();
|
|
NewInstanceBasicType* NewInstanceBasic;
|
|
NewInstanceBasicType* NewInstanceFloatBasic;
|
|
|
|
using NumberOfValuesType = vtkm::Id(void*);
|
|
NumberOfValuesType* NumberOfValues;
|
|
|
|
using NumberOfComponentsType = vtkm::IdComponent(void*);
|
|
NumberOfComponentsType* NumberOfComponents;
|
|
NumberOfComponentsType* NumberOfComponentsFlat;
|
|
|
|
using AllocateType = void(void*, vtkm::Id, vtkm::CopyFlag, vtkm::cont::Token&);
|
|
AllocateType* Allocate;
|
|
|
|
using ShallowCopyType = void(const void*, void*);
|
|
ShallowCopyType* ShallowCopy;
|
|
|
|
using DeepCopyType = void(const void*, void*);
|
|
DeepCopyType* DeepCopy;
|
|
|
|
using ExtractComponentType = std::vector<vtkm::cont::internal::Buffer>(void*,
|
|
vtkm::IdComponent,
|
|
vtkm::CopyFlag);
|
|
ExtractComponentType* ExtractComponent;
|
|
|
|
using ReleaseResourcesType = void(void*);
|
|
ReleaseResourcesType* ReleaseResources;
|
|
ReleaseResourcesType* ReleaseResourcesExecution;
|
|
|
|
using PrintSummaryType = void(void*, std::ostream&, bool);
|
|
PrintSummaryType* PrintSummary;
|
|
|
|
void operator=(const UnknownAHContainer&) = delete;
|
|
|
|
~UnknownAHContainer() { this->DeleteFunction(this->ArrayHandlePointer); }
|
|
|
|
std::shared_ptr<UnknownAHContainer> MakeNewInstance() const;
|
|
|
|
template <typename T, typename S>
|
|
static std::shared_ptr<UnknownAHContainer> Make(const vtkm::cont::ArrayHandle<T, S>& array)
|
|
{
|
|
return std::shared_ptr<UnknownAHContainer>(new UnknownAHContainer(array));
|
|
}
|
|
|
|
template <typename TargetT, typename SourceT, typename SourceS>
|
|
static std::shared_ptr<UnknownAHContainer> Make(
|
|
const vtkm::cont::ArrayHandle<TargetT, vtkm::cont::StorageTagCast<SourceT, SourceS>>& array)
|
|
{
|
|
vtkm::cont::ArrayHandleCast<TargetT, vtkm::cont::ArrayHandle<SourceT, SourceS>> castArray =
|
|
array;
|
|
return Make(castArray.GetSourceArray());
|
|
}
|
|
|
|
template <typename T, typename... Ss>
|
|
static std::shared_ptr<UnknownAHContainer> Make(
|
|
const vtkm::cont::ArrayHandle<T, vtkm::cont::StorageTagMultiplexer<Ss...>>& array)
|
|
{
|
|
auto&& variant = vtkm::cont::ArrayHandleMultiplexer<vtkm::cont::ArrayHandle<T, Ss>...>(array)
|
|
.GetArrayHandleVariant();
|
|
if (variant.IsValid())
|
|
{
|
|
return variant.CastAndCall(MakeUnknownAHContainerFunctor{});
|
|
}
|
|
else
|
|
{
|
|
return std::shared_ptr<UnknownAHContainer>{};
|
|
}
|
|
}
|
|
|
|
private:
|
|
UnknownAHContainer(const UnknownAHContainer&) = default;
|
|
|
|
template <typename T, typename S>
|
|
explicit UnknownAHContainer(const vtkm::cont::ArrayHandle<T, S>& array);
|
|
};
|
|
|
|
template <typename T>
|
|
std::shared_ptr<UnknownAHContainer> UnknownAHNewInstanceBasic(vtkm::VecTraitsTagSizeStatic)
|
|
{
|
|
return UnknownAHContainer::Make(vtkm::cont::ArrayHandleBasic<T>{});
|
|
}
|
|
template <typename T>
|
|
std::shared_ptr<UnknownAHContainer> UnknownAHNewInstanceBasic(vtkm::VecTraitsTagSizeVariable)
|
|
{
|
|
throw vtkm::cont::ErrorBadType("Cannot create a basic array container from with ValueType of " +
|
|
vtkm::cont::TypeToString<T>());
|
|
}
|
|
template <typename T>
|
|
std::shared_ptr<UnknownAHContainer> UnknownAHNewInstanceBasic()
|
|
{
|
|
return UnknownAHNewInstanceBasic<T>(typename vtkm::VecTraits<T>::IsSizeStatic{});
|
|
}
|
|
|
|
template <typename T>
|
|
std::shared_ptr<UnknownAHContainer> UnknownAHNewInstanceFloatBasic(vtkm::VecTraitsTagSizeStatic)
|
|
{
|
|
using FloatT = typename vtkm::VecTraits<T>::template ReplaceBaseComponentType<vtkm::FloatDefault>;
|
|
return UnknownAHContainer::Make(vtkm::cont::ArrayHandleBasic<FloatT>{});
|
|
}
|
|
template <typename T>
|
|
std::shared_ptr<UnknownAHContainer> UnknownAHNewInstanceFloatBasic(vtkm::VecTraitsTagSizeVariable)
|
|
{
|
|
throw vtkm::cont::ErrorBadType("Cannot create a basic array container from with ValueType of " +
|
|
vtkm::cont::TypeToString<T>());
|
|
}
|
|
template <typename T>
|
|
std::shared_ptr<UnknownAHContainer> UnknownAHNewInstanceFloatBasic()
|
|
{
|
|
return UnknownAHNewInstanceFloatBasic<T>(typename vtkm::VecTraits<T>::IsSizeStatic{});
|
|
}
|
|
|
|
template <typename T, typename S>
|
|
inline UnknownAHContainer::UnknownAHContainer(const vtkm::cont::ArrayHandle<T, S>& array)
|
|
: ArrayHandlePointer(new vtkm::cont::ArrayHandle<T, S>(array))
|
|
, ValueType(typeid(T))
|
|
, StorageType(typeid(S))
|
|
, BaseComponentType(
|
|
UnknownAHComponentInfo::Make<typename vtkm::VecTraits<T>::BaseComponentType>())
|
|
, DeleteFunction(detail::UnknownAHDelete<T, S>)
|
|
, Buffers(detail::UnknownAHBuffers<T, S>)
|
|
, NewInstance(detail::UnknownAHNewInstance<T, S>)
|
|
, NewInstanceBasic(detail::UnknownAHNewInstanceBasic<T>)
|
|
, NewInstanceFloatBasic(detail::UnknownAHNewInstanceFloatBasic<T>)
|
|
, NumberOfValues(detail::UnknownAHNumberOfValues<T, S>)
|
|
, NumberOfComponents(detail::UnknownAHNumberOfComponents<T, S>)
|
|
, NumberOfComponentsFlat(detail::UnknownAHNumberOfComponentsFlat<T, S>)
|
|
, Allocate(detail::UnknownAHAllocate<T, S>)
|
|
, ShallowCopy(detail::UnknownAHShallowCopy<T, S>)
|
|
, DeepCopy(detail::UnknownAHDeepCopy<T, S>)
|
|
, ExtractComponent(detail::UnknownAHExtractComponent<T, S>)
|
|
, ReleaseResources(detail::UnknownAHReleaseResources<T, S>)
|
|
, ReleaseResourcesExecution(detail::UnknownAHReleaseResourcesExecution<T, S>)
|
|
, PrintSummary(detail::UnknownAHPrintSummary<T, S>)
|
|
{
|
|
}
|
|
|
|
template <typename T, typename S>
|
|
inline std::shared_ptr<UnknownAHContainer> MakeUnknownAHContainerFunctor::operator()(
|
|
const vtkm::cont::ArrayHandle<T, S>& array) const
|
|
{
|
|
return UnknownAHContainer::Make(array);
|
|
};
|
|
|
|
} // namespace detail
|
|
|
|
// Forward declaration. Include UncertainArrayHandle.h if using this.
|
|
template <typename ValueTypeList, typename StorageTypeList>
|
|
class UncertainArrayHandle;
|
|
|
|
/// \brief An ArrayHandle of an unknown value type and storage.
|
|
///
|
|
/// `UnknownArrayHandle` holds an `ArrayHandle` object using runtime polymorphism
|
|
/// to manage different value and storage types rather than compile-time templates.
|
|
/// This adds a programming convenience that helps avoid a proliferation of
|
|
/// templates. It also provides the management necessary to interface VTK-m with
|
|
/// data sources where types will not be known until runtime and is the storage
|
|
/// mechanism for classes like `DataSet` and `Field` that can hold numerous
|
|
/// types.
|
|
///
|
|
/// To interface between the runtime polymorphism and the templated algorithms
|
|
/// in VTK-m, `UnknownArrayHandle` contains a method named `CastAndCallForTypes`
|
|
/// that determines the correct type from some known list of value types and
|
|
/// storage. This mechanism is used internally by VTK-m's worklet invocation
|
|
/// mechanism to determine the type when running algorithms.
|
|
///
|
|
/// If the `UnknownArrayHandle` is used in a context where the possible array
|
|
/// types can be whittled down to a finite list (or you have to), you can
|
|
/// specify lists of value types and storage using the `ResetTypesAndStorage`
|
|
/// method. This will convert this object to an `UncertainArrayHandle` of the
|
|
/// given types. In cases where a finite set of types need to specified but
|
|
/// there is no known subset, `VTKM_DEFAULT_TYPE_LIST` and
|
|
/// `VTKM_DEFAULT_STORAGE_LIST` can be used.
|
|
///
|
|
/// `ArrayHandleCast` and `ArrayHandleMultiplexer` are treated special. If
|
|
/// the `UnknownArrayHandle` is set to an `ArrayHandle` of one of these
|
|
/// types, it will actually store the `ArrayHandle` contained. Likewise,
|
|
/// if the `ArrayHandle` is retrieved as one of these types, it will
|
|
/// automatically convert it if possible.
|
|
///
|
|
class VTKM_CONT_EXPORT UnknownArrayHandle
|
|
{
|
|
std::shared_ptr<detail::UnknownAHContainer> Container;
|
|
|
|
VTKM_CONT bool IsValueTypeImpl(std::type_index type) const;
|
|
VTKM_CONT bool IsStorageTypeImpl(std::type_index type) const;
|
|
VTKM_CONT bool IsBaseComponentTypeImpl(const detail::UnknownAHComponentInfo& type) const;
|
|
|
|
public:
|
|
VTKM_CONT UnknownArrayHandle() = default;
|
|
|
|
template <typename T, typename S>
|
|
VTKM_CONT UnknownArrayHandle(const vtkm::cont::ArrayHandle<T, S>& array)
|
|
: Container(detail::UnknownAHContainer::Make(array))
|
|
{
|
|
}
|
|
|
|
/// \brief Returns whether an array is stored in this `UnknownArrayHandle`.
|
|
///
|
|
/// If the `UnknownArrayHandle` is constructed without an `ArrayHandle`, it
|
|
/// will not have an underlying type, and therefore the operations will be
|
|
/// invalid. It is still possible to set this `UnknownArrayHandle` to an
|
|
/// `ArrayHandle`.
|
|
VTKM_CONT bool IsValid() const;
|
|
|
|
/// \brief Create a new array of the same type as this array.
|
|
///
|
|
/// This method creates a new array that is the same type as this one and
|
|
/// returns a new `UnknownArrayHandle` for it. This method is convenient when
|
|
/// creating output arrays that should be the same type as some input array.
|
|
///
|
|
VTKM_CONT UnknownArrayHandle NewInstance() const;
|
|
|
|
/// \brief Create a new `ArrayHandleBasic` with the same `ValueType` as this array.
|
|
///
|
|
/// This method creates a new `ArrayHandleBasic` that has the same `ValueType` as the
|
|
/// array held by this one and returns a new `UnknownArrayHandle` for it. This method
|
|
/// is convenient when creating output arrays that should have the same types of values
|
|
/// of the input, but the input might not be a writable array.
|
|
///
|
|
VTKM_CONT UnknownArrayHandle NewInstanceBasic() const;
|
|
|
|
/// \brief Create a new `ArrayHandleBasic` with the base component of `FloatDefault`
|
|
///
|
|
/// This method creates a new `ArrayHandleBasic` that has a `ValueType` that is similar
|
|
/// to the array held by this one except that the base component type is replaced with
|
|
/// `vtkm::FloatDefault`. For example, if the contained array has `vtkm::Int32` value types,
|
|
/// the returned array will have `vtkm::FloatDefault` value types. If the contained array
|
|
/// has `vtkm::Id3` value types, the returned array will have `vtkm::Vec3f` value types.
|
|
/// If the contained array already has `vtkm::FloatDefault` as the base component (e.g.
|
|
/// `vtkm::FloatDefault`, `vtkm::Vec3f`, `vtkm::Vec<vtkm::Vec2f, 3>`), then the value type
|
|
/// will be preserved.
|
|
///
|
|
/// The created array is returned in a new `UnknownArrayHandle`.
|
|
///
|
|
/// This method is used to convert an array of an unknown type to an array of an almost
|
|
/// known type.
|
|
///
|
|
VTKM_CONT UnknownArrayHandle NewInstanceFloatBasic() const;
|
|
|
|
/// \brief Returns the name of the value type stored in the array.
|
|
///
|
|
/// Returns an empty string if no array is stored.
|
|
VTKM_CONT std::string GetValueTypeName() const;
|
|
|
|
/// \brief Returns the name of the base component of the value type stored in the array.
|
|
///
|
|
/// Returns an empty string if no array is stored.
|
|
VTKM_CONT std::string GetBaseComponentTypeName() const;
|
|
|
|
/// \brief Returns the name of the storage tag for the array.
|
|
///
|
|
/// Returns an empty string if no array is stored.
|
|
VTKM_CONT std::string GetStorageTypeName() const;
|
|
|
|
/// \brief Returns a string representation of the underlying data type.
|
|
///
|
|
/// The returned string will be of the form `vtkm::cont::ArrayHandle<T, S>` rather than the name
|
|
/// of an actual subclass. If no array is stored, an empty string is returned.
|
|
///
|
|
VTKM_CONT std::string GetArrayTypeName() const;
|
|
|
|
/// Returns true if this array matches the ValueType template argument.
|
|
///
|
|
template <typename ValueType>
|
|
VTKM_CONT bool IsValueType() const
|
|
{
|
|
return this->IsValueTypeImpl(typeid(ValueType));
|
|
}
|
|
|
|
/// Returns true if this array matches the StorageType template argument.
|
|
///
|
|
template <typename StorageType>
|
|
VTKM_CONT bool IsStorageType() const
|
|
{
|
|
return this->IsStorageTypeImpl(typeid(StorageType));
|
|
}
|
|
|
|
/// \brief Returns true if this array's `ValueType` has the provided base component type.
|
|
///
|
|
/// The base component type is the recursive component type of any `Vec`-like object. So
|
|
/// if the array's `ValueType` is `vtkm::Vec<vtkm::Float32, 3>`, then the base component
|
|
/// type will be `vtkm::Float32`. Likewise, if the `ValueType` is
|
|
/// `vtkm::Vec<vtkm::Vec<vtkm::Float32, 3>, 2>`, then the base component type is still
|
|
/// `vtkm::Float32`.
|
|
///
|
|
/// If the `ValueType` is not `Vec`-like type, then the base component type is the same.
|
|
/// So a `ValueType` of `vtkm::Float32` has a base component type of `vtkm::Float32`.
|
|
///
|
|
template <typename BaseComponentType>
|
|
VTKM_CONT bool IsBaseComponentType() const
|
|
{
|
|
return this->IsBaseComponentTypeImpl(detail::UnknownAHComponentInfo::Make<BaseComponentType>());
|
|
}
|
|
|
|
/// \brief Returns true if this array matches the ArrayHandleType template argument.
|
|
///
|
|
/// Note that `UnknownArrayHandle` has some special handling for `ArrayHandleCast` and
|
|
/// `ArrayHandleMultiplexer`. If you stored an array of one of these types into an
|
|
/// `UnknownArrayHandle`, the type of the underlying array will change and `IsType`
|
|
/// will fail. However, you can still get the array back out as that type using
|
|
/// `AsArrayHandle`.
|
|
///
|
|
/// Use the `CanConvert` method instead to determine if the `UnknownArrayHandle`
|
|
/// contains an array that "matches" the array of a given type. Under most
|
|
/// circumstances, you should prefer `CanConvert` over `IsType`.
|
|
///
|
|
template <typename ArrayHandleType>
|
|
VTKM_CONT bool IsType() const
|
|
{
|
|
VTKM_IS_ARRAY_HANDLE(ArrayHandleType);
|
|
return (this->IsValueType<typename ArrayHandleType::ValueType>() &&
|
|
this->IsStorageType<typename ArrayHandleType::StorageTag>());
|
|
}
|
|
|
|
/// \brief Assigns potential value and storage types.
|
|
///
|
|
/// Calling this method will return an `UncertainArrayHandle` with the provided
|
|
/// value and storage type lists. The returned object will hold the same
|
|
/// `ArrayHandle`, but `CastAndCall`s on the returned object will be constrained
|
|
/// to the given types.
|
|
///
|
|
// Defined in UncertainArrayHandle.h
|
|
template <typename NewValueTypeList, typename NewStorageTypeList>
|
|
VTKM_CONT vtkm::cont::UncertainArrayHandle<NewValueTypeList, NewStorageTypeList> ResetTypes(
|
|
NewValueTypeList = NewValueTypeList{},
|
|
NewStorageTypeList = NewStorageTypeList{}) const;
|
|
|
|
/// \brief Returns the number of values in the array.
|
|
///
|
|
VTKM_CONT vtkm::Id GetNumberOfValues() const;
|
|
|
|
/// \brief Returns the number of components for each value in the array.
|
|
///
|
|
/// If the array holds `vtkm::Vec` objects, this will return the number of components
|
|
/// in each value. If the array holds a basic C type (such as `float`), this will return 1.
|
|
/// If the array holds `Vec`-like objects that have the number of components that can vary
|
|
/// at runtime, this method will return 0 (because there is no consistent answer).
|
|
///
|
|
VTKM_CONT vtkm::IdComponent GetNumberOfComponents() const;
|
|
|
|
/// \brief Returns the total number of components for each value in the array.
|
|
///
|
|
/// If the array holds `vtkm::Vec` objects, this will return the total number of components
|
|
/// in each value assuming the object is flattened out to one level of `Vec` objects.
|
|
/// If the array holds a basic C type (such as `float`), this will return 1.
|
|
/// If the array holds a simple `Vec` (such as `vtkm::Vec3f`), this will return the number
|
|
/// of components (in this case 3).
|
|
/// If the array holds a hierarchy of `Vec`s (such as `vtkm::Vec<vtkm::Vec3f, 2>`), this will
|
|
/// return the total number of vecs (in this case 6).
|
|
/// If the array holds `Vec`-like objects that have the number of components that can vary
|
|
/// at runtime, this method will return 0 (because there is no consistent answer).
|
|
///
|
|
VTKM_CONT vtkm::IdComponent GetNumberOfComponentsFlat() const;
|
|
|
|
/// \brief Reallocate the data in the array.
|
|
///
|
|
/// The allocation works the same as the `Allocate` method of `vtkm::cont::ArrayHandle`.
|
|
///
|
|
/// @{
|
|
VTKM_CONT void Allocate(vtkm::Id numValues,
|
|
vtkm::CopyFlag preserve,
|
|
vtkm::cont::Token& token) const;
|
|
VTKM_CONT void Allocate(vtkm::Id numValues, vtkm::CopyFlag preserve = vtkm::CopyFlag::Off) const;
|
|
/// @}
|
|
|
|
/// \brief Determine if the contained array can be passed to the given array type.
|
|
///
|
|
/// This method will return true if calling `AsArrayHandle` of the given type will
|
|
/// succeed. The result is similar to `IsType`, and if `IsType` returns true, then
|
|
/// this will return true. However, this method will also return true for other
|
|
/// types such as an `ArrayHandleMultiplexer` that can contain the array.
|
|
///
|
|
template <typename ArrayHandleType>
|
|
VTKM_CONT bool CanConvert() const;
|
|
|
|
// MSVC will issue deprecation warnings here if this template is instantiated with
|
|
// a deprecated class even if the template is used from a section of code where
|
|
// deprecation warnings are suppressed. This is annoying behavior since this template
|
|
// has no control over what class it is used with. To get around it, we have to
|
|
// suppress all deprecation warnings here.
|
|
#ifdef VTKM_MSVC
|
|
VTKM_DEPRECATED_SUPPRESS_BEGIN
|
|
#endif
|
|
|
|
private:
|
|
template <typename T, typename S>
|
|
VTKM_CONT void BaseAsArrayHandle(vtkm::cont::ArrayHandle<T, S>& array) const
|
|
{
|
|
using ArrayType = vtkm::cont::ArrayHandle<T, S>;
|
|
if (!this->IsType<ArrayType>())
|
|
{
|
|
VTKM_LOG_CAST_FAIL(*this, decltype(array));
|
|
throwFailedDynamicCast(this->GetArrayTypeName(), vtkm::cont::TypeToString(array));
|
|
}
|
|
|
|
array = *reinterpret_cast<ArrayType*>(this->Container->ArrayHandlePointer);
|
|
}
|
|
|
|
public:
|
|
///@{
|
|
/// Returns this array cast appropriately and stored in the given `ArrayHandle` type.
|
|
/// Throws an `ErrorBadType` if the stored array cannot be stored in the given array type.
|
|
/// Use the `CanConvert` method to determine if the array can be returned with the given type.
|
|
///
|
|
template <typename T, typename S>
|
|
VTKM_CONT void AsArrayHandle(vtkm::cont::ArrayHandle<T, S>& array) const
|
|
{
|
|
this->BaseAsArrayHandle(array);
|
|
}
|
|
|
|
template <typename T>
|
|
VTKM_CONT void AsArrayHandle(vtkm::cont::ArrayHandle<T>& array) const;
|
|
|
|
template <typename T, typename... Ss>
|
|
VTKM_CONT void AsArrayHandle(
|
|
vtkm::cont::ArrayHandle<T, vtkm::cont::StorageTagMultiplexer<Ss...>>& array) const;
|
|
|
|
template <typename TargetT, typename SourceT, typename SourceS>
|
|
VTKM_CONT void AsArrayHandle(
|
|
vtkm::cont::ArrayHandle<TargetT, vtkm::cont::StorageTagCast<SourceT, SourceS>>& array) const
|
|
{
|
|
using ContainedArrayType = vtkm::cont::ArrayHandle<SourceT, SourceS>;
|
|
array = vtkm::cont::ArrayHandleCast<TargetT, ContainedArrayType>(
|
|
this->AsArrayHandle<ContainedArrayType>());
|
|
}
|
|
|
|
template <typename T>
|
|
VTKM_CONT void AsArrayHandle(
|
|
vtkm::cont::ArrayHandle<T, vtkm::cont::StorageTagRuntimeVec>& array) const
|
|
{
|
|
using BaseT = typename T::ComponentType;
|
|
if (this->IsStorageType<vtkm::cont::StorageTagBasic>() && this->IsBaseComponentType<BaseT>())
|
|
{
|
|
// Reinterpret the basic array as components, and then wrap that in a runtime vec
|
|
// with the correct amount of components.
|
|
vtkm::cont::ArrayHandle<BaseT, vtkm::cont::StorageTagBasic> basicArray(
|
|
this->Container->Buffers(this->Container->ArrayHandlePointer));
|
|
array =
|
|
vtkm::cont::ArrayHandleRuntimeVec<BaseT>(this->GetNumberOfComponentsFlat(), basicArray);
|
|
}
|
|
else
|
|
{
|
|
this->BaseAsArrayHandle(array);
|
|
}
|
|
}
|
|
|
|
template <typename ArrayType>
|
|
VTKM_CONT ArrayType AsArrayHandle() const
|
|
{
|
|
VTKM_IS_ARRAY_HANDLE(ArrayType);
|
|
ArrayType array;
|
|
this->AsArrayHandle(array);
|
|
return array;
|
|
}
|
|
///@}
|
|
#ifdef VTKM_MSVC
|
|
VTKM_DEPRECATED_SUPPRESS_END
|
|
#endif
|
|
|
|
/// \brief Deep copies data from another `UnknownArrayHandle`.
|
|
///
|
|
/// This method takes an `UnknownArrayHandle` and deep copies data from it.
|
|
///
|
|
/// If this object does not point to an existing `ArrayHandle`, a new `ArrayHandleBasic`
|
|
/// with the same value type of the `source` is created.
|
|
///
|
|
void DeepCopyFrom(const vtkm::cont::UnknownArrayHandle& source);
|
|
|
|
/// \brief Deep copies data from another `UnknownArrayHandle`.
|
|
///
|
|
/// This method takes an `UnknownArrayHandle` and deep copies data from it.
|
|
///
|
|
/// If this object does not point to an existing `ArrayHandle`, this const version
|
|
/// of `DeepCopyFrom` throws an exception.
|
|
///
|
|
void DeepCopyFrom(const vtkm::cont::UnknownArrayHandle& source) const;
|
|
|
|
/// \brief Attempts a shallow copy of an array or a deep copy if that is not possible.
|
|
///
|
|
/// This method takes an `UnknownArrayHandle` and attempts to perform a shallow copy.
|
|
/// This shallow copy occurs if this object points to an `ArrayHandle` of the same type
|
|
/// or does not point to any `ArrayHandle` at all. If this is not possible, then
|
|
/// the array is deep copied.
|
|
///
|
|
/// This method is roughly equivalent to the `ArrayCopyShallowIfPossible` function
|
|
/// (defined in `vtkm/cont/ArrayCopy.h`). However, this method can be used without
|
|
/// having to use a device compiler (whereas `ArrayCopyShallowIfPossible` does require
|
|
/// a device device compiler).
|
|
///
|
|
void CopyShallowIfPossible(const vtkm::cont::UnknownArrayHandle& source);
|
|
|
|
/// \brief Attempts a shallow copy of an array or a deep copy if that is not possible.
|
|
///
|
|
/// This method takes an `UnknownArrayHandle` and attempts to perform a shallow copy.
|
|
/// This shallow copy occurs if this object points to an `ArrayHandle` of the same type.
|
|
/// If the types are incompatible, then the array is deep copied.
|
|
///
|
|
/// If this object does not point to an existing `ArrayHandle`, this const version
|
|
/// of `CopyShallowIfPossible` throws an exception.
|
|
///
|
|
/// This method is roughly equivalent to the `ArrayCopyShallowIfPossible` function
|
|
/// (defined in `vtkm/cont/ArrayCopy.h`). However, this method can be used without
|
|
/// having to use a device compiler (whereas `ArrayCopyShallowIfPossible` does require
|
|
/// a device device compiler).
|
|
///
|
|
void CopyShallowIfPossible(const vtkm::cont::UnknownArrayHandle& source) const;
|
|
|
|
/// \brief Extract a component of the array.
|
|
///
|
|
/// This method returns an array that holds the data for a given flat component of the data.
|
|
/// The `BaseComponentType` has to be specified and must match the contained array (i.e.
|
|
/// the result of `IsBaseComponentType` must succeed for the given type).
|
|
///
|
|
/// This method treats each value in the array as a flat `Vec` even if it is a `Vec` of
|
|
/// `Vec`s. For example, if the array actually holds values of type `Vec<Vec<T, 3>, 2>`,
|
|
/// it is treated as if it holds a `Vec<T, 6>`. See `vtkm::VecFlat` for details on how
|
|
/// vectors are flattened.
|
|
///
|
|
/// The point of using `ExtractComponent` over `AsArrayHandle` is that it drastically reduces
|
|
/// the amount of types you have to try. Most of the type the base component type is one of
|
|
/// the basic C types (i.e. `int`, `long`, `float`, etc.). You do not need to know what shape
|
|
/// the containing `Vec` is in, nor do you need to know the actual storage of the array.
|
|
///
|
|
/// Note that the type of the array returned is `ArrayHandleStride`. Using this type of
|
|
/// array handle has a slight overhead over basic arrays like `ArrayHandleBasic` and
|
|
/// `ArrayHandleSOA`.
|
|
///
|
|
/// When extracting a component of an array, a shallow pointer to the data is returned
|
|
/// whenever possible. However, in some circumstances it is impossible to conform the
|
|
/// array. In these cases, the data are by default copied. If copying the data would
|
|
/// cause problems (for example, you are writing into the array), you can select the
|
|
/// optional `allowCopy` flag to `vtkm::CopyFlag::Off`. In this case, an exception
|
|
/// will be thrown if the result cannot be represented by a shallow copy.
|
|
///
|
|
template <typename BaseComponentType>
|
|
VTKM_CONT vtkm::cont::ArrayHandleStride<BaseComponentType> ExtractComponent(
|
|
vtkm::IdComponent componentIndex,
|
|
vtkm::CopyFlag allowCopy = vtkm::CopyFlag::On) const
|
|
{
|
|
using ComponentArrayType = vtkm::cont::ArrayHandleStride<BaseComponentType>;
|
|
if (!this->IsBaseComponentType<BaseComponentType>())
|
|
{
|
|
VTKM_LOG_CAST_FAIL(*this, ComponentArrayType);
|
|
throwFailedDynamicCast("UnknownArrayHandle with " + this->GetArrayTypeName(),
|
|
"component array of " + vtkm::cont::TypeToString<BaseComponentType>());
|
|
}
|
|
|
|
auto buffers = this->Container->ExtractComponent(
|
|
this->Container->ArrayHandlePointer, componentIndex, allowCopy);
|
|
return ComponentArrayType(buffers);
|
|
}
|
|
|
|
/// \brief Extract the array knowing only the component type of the array.
|
|
///
|
|
/// This method returns an `ArrayHandle` that points to the data in the array. This method
|
|
/// differs from `AsArrayHandle` because you do not need to know the exact `ValueType` and
|
|
/// `StorageTag` of the array. Instead, you only need to know the base component type.
|
|
///
|
|
/// `ExtractArrayFromComponents` works by calling the `ExtractComponent` method and then
|
|
/// combining them together in a fancy `ArrayHandle`. This allows you to ignore the storage
|
|
/// type of the underlying array as well as any `Vec` structure of the value type. However,
|
|
/// it also places some limitations on how the data can be pulled from the data.
|
|
///
|
|
/// First, you have to specify the base component type. This must match the data in the
|
|
/// underlying array (as reported by `IsBaseComponentType`).
|
|
///
|
|
/// Second, the array returned will have the `Vec`s flattened. For example, if the underlying
|
|
/// array has a `ValueType` of `Vec<Vec<T, 3>, 3>`, then this method will tread the data as
|
|
/// if it was `Vec<T, 9>`. There is no way to get an array with `Vec` of `Vec` values.
|
|
///
|
|
/// Third, because the `Vec` length of the values in the returned `ArrayHandle` must be
|
|
/// determined at runtime, that can break many assumptions of using `Vec` objects. The
|
|
/// type is not going to be a `Vec<T,N>` type but rather an internal class that is intended
|
|
/// to behave like that. The type should behave mostly like a `Vec`, but will have some
|
|
/// differences that can lead to unexpected behavior. For example, this `Vec`-like object
|
|
/// will not have a `NUM_COMPONENTS` constant static expression because it is not known
|
|
/// at compile time. (Use the `GetNumberOfComponents` method instead.) And for the same
|
|
/// reason you will not be able to pass these objects to classes overloaded or templated
|
|
/// on the `Vec` type. Also, these `Vec`-like objects cannot be created as new instances.
|
|
/// Thus, you will likely have to iterate over all components rather than do operations on
|
|
/// the whole `Vec`.
|
|
///
|
|
/// Fourth, because `ExtractArrayFromComponents` uses `ExtractComponent` to pull data from
|
|
/// the array (which in turn uses `ArrayExtractComponent`), there are some `ArrayHandle` types
|
|
/// that will require copying data to a new array. This could be problematic in cases where
|
|
/// you want to write to the array. To prevent data from being copied, set the optional
|
|
/// `allowCopy` to `vtkm::CopyFlag::Off`. This will cause an exception to be thrown if
|
|
/// the resulting array cannot reference the memory held in this `UnknownArrayHandle`.
|
|
///
|
|
/// Fifth, component arrays are extracted using `ArrayHandleStride` as the representation
|
|
/// for each component. This array adds a slight overhead for each lookup as it performs the
|
|
/// arithmetic for finding the index of each component.
|
|
///
|
|
template <typename BaseComponentType>
|
|
VTKM_CONT vtkm::cont::ArrayHandleRecombineVec<BaseComponentType> ExtractArrayFromComponents(
|
|
vtkm::CopyFlag allowCopy = vtkm::CopyFlag::On) const
|
|
{
|
|
vtkm::cont::ArrayHandleRecombineVec<BaseComponentType> result;
|
|
vtkm::IdComponent numComponents = this->GetNumberOfComponentsFlat();
|
|
for (vtkm::IdComponent cIndex = 0; cIndex < numComponents; ++cIndex)
|
|
{
|
|
result.AppendComponentArray(this->ExtractComponent<BaseComponentType>(cIndex, allowCopy));
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/// \brief Call a functor using the underlying array type.
|
|
///
|
|
/// `CastAndCallForTypes` attempts to cast the held array to a specific value type,
|
|
/// and then calls the given functor with the cast array. You must specify
|
|
/// the `TypeList` and `StorageList` as template arguments.
|
|
///
|
|
/// After the functor argument you may add any number of arguments that will be
|
|
/// passed to the functor after the converted `ArrayHandle`.
|
|
///
|
|
template <typename TypeList, typename StorageList, typename Functor, typename... Args>
|
|
VTKM_CONT void CastAndCallForTypes(Functor&& functor, Args&&... args) const;
|
|
|
|
/// \brief Call a functor using the underlying array type with a float cast fallback.
|
|
///
|
|
/// `CastAndCallForTypesWithFloatFallback` attempts to cast the held array to a specific
|
|
/// value type, and then calls the given functor with the cast array. You must specify
|
|
/// the `TypeList` and `StorageList` as template arguments.
|
|
///
|
|
/// After the functor argument you may add any number of arguments that will be
|
|
/// passed to the functor after the converted `ArrayHandle`.
|
|
///
|
|
/// If the underlying array does not match any of the requested array types, the
|
|
/// array is copied to a new `ArrayHandleBasic` with `FloatDefault` components
|
|
/// in its value and attempts to cast to those types.
|
|
///
|
|
template <typename TypeList, typename StorageList, typename Functor, typename... Args>
|
|
VTKM_CONT void CastAndCallForTypesWithFloatFallback(Functor&& functor, Args&&... args) const;
|
|
|
|
/// \brief Call a functor on an array extracted from the components.
|
|
///
|
|
/// `CastAndCallWithExtractedArray` behaves similarly to `CastAndCallForTypes`.
|
|
/// It converts the contained data to an `ArrayHandle` and calls a functor with
|
|
/// that `ArrayHandle` (and any number of optionally specified arguments).
|
|
///
|
|
/// The advantage of `CastAndCallWithExtractedArray` is that you do not need to
|
|
/// specify any `TypeList` or `StorageList`. Instead, it internally uses
|
|
/// `ExtractArrayFromComponents` to work with most `ArrayHandle` types with only
|
|
/// about 10 instances of the functor. In contrast, calling `CastAndCallForTypes`
|
|
/// with, for example, `VTKM_DEFAULT_TYPE_LIST` and `VTKM_DEFAULT_STORAGE_LIST`
|
|
/// results in many more instances of the functor but handling many fewer types
|
|
/// of `ArrayHandle`.
|
|
///
|
|
/// There are, however, costs to using this method. Details of these costs are
|
|
/// documented for the `ExtractArrayFromComponents` method, but briefly they
|
|
/// are that `Vec` types get flattened, the resulting array has a strange `Vec`-like
|
|
/// value type that has many limitations on its use, there is an overhead for
|
|
/// retrieving each value from the array, and there is a potential that data
|
|
/// must be copied.
|
|
///
|
|
template <typename Functor, typename... Args>
|
|
VTKM_CONT void CastAndCallWithExtractedArray(Functor&& functor, Args&&... args) const;
|
|
|
|
/// Releases any resources being used in the execution environment (that are
|
|
/// not being shared by the control environment).
|
|
///
|
|
VTKM_CONT void ReleaseResourcesExecution() const;
|
|
|
|
/// Releases all resources in both the control and execution environments.
|
|
///
|
|
VTKM_CONT void ReleaseResources() const;
|
|
|
|
VTKM_CONT void PrintSummary(std::ostream& out, bool full = false) const;
|
|
};
|
|
|
|
//=============================================================================
|
|
// Out of class implementations
|
|
|
|
namespace detail
|
|
{
|
|
|
|
template <typename T, typename S>
|
|
struct UnknownArrayHandleCanConvert
|
|
{
|
|
VTKM_CONT bool operator()(const vtkm::cont::UnknownArrayHandle& array) const
|
|
{
|
|
return array.IsType<vtkm::cont::ArrayHandle<T, S>>();
|
|
}
|
|
};
|
|
|
|
template <typename T>
|
|
struct UnknownArrayHandleCanConvert<T, vtkm::cont::StorageTagBasic>
|
|
{
|
|
VTKM_CONT bool operator()(const vtkm::cont::UnknownArrayHandle& array) const
|
|
{
|
|
using UnrolledVec = vtkm::internal::UnrollVec<T>;
|
|
return (array.IsType<vtkm::cont::ArrayHandleBasic<T>>() ||
|
|
(array.IsStorageType<vtkm::cont::StorageTagRuntimeVec>() &&
|
|
array.IsBaseComponentType<typename UnrolledVec::ComponentType>() &&
|
|
UnrolledVec::NUM_COMPONENTS == array.GetNumberOfComponentsFlat()));
|
|
}
|
|
};
|
|
|
|
template <typename TargetT, typename SourceT, typename SourceS>
|
|
struct UnknownArrayHandleCanConvert<TargetT, vtkm::cont::StorageTagCast<SourceT, SourceS>>
|
|
{
|
|
VTKM_CONT bool operator()(const vtkm::cont::UnknownArrayHandle& array) const
|
|
{
|
|
return UnknownArrayHandleCanConvert<SourceT, SourceS>{}(array);
|
|
}
|
|
};
|
|
|
|
template <typename T>
|
|
struct UnknownArrayHandleCanConvertTry
|
|
{
|
|
template <typename S>
|
|
VTKM_CONT void operator()(S, const vtkm::cont::UnknownArrayHandle& array, bool& canConvert) const
|
|
{
|
|
canConvert |= UnknownArrayHandleCanConvert<T, S>{}(array);
|
|
}
|
|
};
|
|
|
|
template <typename T, typename... Ss>
|
|
struct UnknownArrayHandleCanConvert<T, vtkm::cont::StorageTagMultiplexer<Ss...>>
|
|
{
|
|
VTKM_CONT bool operator()(const vtkm::cont::UnknownArrayHandle& array) const
|
|
{
|
|
bool canConvert = false;
|
|
vtkm::ListForEach(UnknownArrayHandleCanConvertTry<T>{}, vtkm::List<Ss...>{}, array, canConvert);
|
|
return canConvert;
|
|
}
|
|
};
|
|
|
|
template <typename T>
|
|
struct UnknownArrayHandleCanConvert<T, vtkm::cont::StorageTagRuntimeVec>
|
|
{
|
|
VTKM_CONT bool operator()(const vtkm::cont::UnknownArrayHandle& array) const
|
|
{
|
|
using BaseComponentType = typename T::ComponentType;
|
|
return (array.IsType<vtkm::cont::ArrayHandle<T, vtkm::cont::StorageTagRuntimeVec>>() ||
|
|
(array.IsStorageType<vtkm::cont::StorageTagBasic>() &&
|
|
array.IsBaseComponentType<BaseComponentType>()));
|
|
}
|
|
};
|
|
|
|
} // namespace detail
|
|
|
|
template <typename ArrayHandleType>
|
|
VTKM_CONT inline bool UnknownArrayHandle::CanConvert() const
|
|
{
|
|
VTKM_IS_ARRAY_HANDLE(ArrayHandleType);
|
|
|
|
return detail::UnknownArrayHandleCanConvert<typename ArrayHandleType::ValueType,
|
|
typename ArrayHandleType::StorageTag>{}(*this);
|
|
}
|
|
|
|
namespace detail
|
|
{
|
|
|
|
template <typename T,
|
|
vtkm::IdComponent =
|
|
vtkm::VecTraits<typename vtkm::internal::UnrollVec<T>::ComponentType>::NUM_COMPONENTS>
|
|
struct UnknownArrayHandleRuntimeVecAsBasic
|
|
{
|
|
VTKM_CONT bool operator()(const vtkm::cont::UnknownArrayHandle*,
|
|
const detail::UnknownAHContainer*,
|
|
vtkm::cont::ArrayHandle<T>&) const
|
|
{
|
|
// This version only gets called if T contains a `Vec`-like object that is not a strict `Vec`.
|
|
// This is rare but could happen. In this case, the type cannot be stored in an
|
|
// `ArrayHandleRuntimeVec` and therefore the load can never happen, so just ignore.
|
|
return false;
|
|
}
|
|
};
|
|
|
|
template <typename T>
|
|
struct UnknownArrayHandleRuntimeVecAsBasic<T, 1>
|
|
{
|
|
VTKM_CONT bool operator()(const vtkm::cont::UnknownArrayHandle* self,
|
|
const detail::UnknownAHContainer* container,
|
|
vtkm::cont::ArrayHandle<T>& array) const
|
|
{
|
|
using UnrolledVec = vtkm::internal::UnrollVec<T>;
|
|
using ComponentType = typename UnrolledVec::ComponentType;
|
|
if (self->IsStorageType<vtkm::cont::StorageTagRuntimeVec>() &&
|
|
self->IsBaseComponentType<ComponentType>() &&
|
|
UnrolledVec::NUM_COMPONENTS == self->GetNumberOfComponentsFlat())
|
|
{
|
|
// Pull out the components array out of the buffers. The array might not match exactly
|
|
// the array put in, but the buffer should still be consistent with the array (which works
|
|
// because the size of a basic array is based on the number of bytes in the buffer).
|
|
using RuntimeVecType = typename vtkm::cont::ArrayHandleRuntimeVec<ComponentType>::ValueType;
|
|
using StorageRuntimeVec =
|
|
vtkm::cont::internal::Storage<RuntimeVecType, vtkm::cont::StorageTagRuntimeVec>;
|
|
StorageRuntimeVec::AsArrayHandleBasic(container->Buffers(container->ArrayHandlePointer),
|
|
array);
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
};
|
|
|
|
} // namespace detail
|
|
|
|
template <typename T>
|
|
VTKM_CONT inline void UnknownArrayHandle::AsArrayHandle(vtkm::cont::ArrayHandle<T>& array) const
|
|
{
|
|
if (!detail::UnknownArrayHandleRuntimeVecAsBasic<T>{}(this, this->Container.get(), array))
|
|
{
|
|
this->BaseAsArrayHandle(array);
|
|
}
|
|
}
|
|
|
|
namespace detail
|
|
{
|
|
|
|
struct UnknownArrayHandleMultiplexerCastTry
|
|
{
|
|
template <typename T, typename S, typename... Ss>
|
|
VTKM_CONT void operator()(
|
|
S,
|
|
const vtkm::cont::UnknownArrayHandle& unknownArray,
|
|
vtkm::cont::ArrayHandle<T, vtkm::cont::StorageTagMultiplexer<Ss...>>& outputArray,
|
|
bool& converted) const
|
|
{
|
|
using ArrayType = vtkm::cont::ArrayHandle<T, S>;
|
|
if (unknownArray.CanConvert<ArrayType>())
|
|
{
|
|
if (converted && !unknownArray.IsType<ArrayType>())
|
|
{
|
|
// The array has already been converted and pushed in the multiplexer. It is
|
|
// possible that multiple array types can be put in the ArrayHandleMultiplexer
|
|
// (for example, and ArrayHandle or an ArrayHandle that has been cast). Exact
|
|
// matches will override other matches (hence, the second part of the condition),
|
|
// but at this point we have already found a better array to put inside.
|
|
return;
|
|
}
|
|
outputArray = vtkm::cont::ArrayHandleMultiplexer<vtkm::cont::ArrayHandle<T, Ss>...>(
|
|
unknownArray.AsArrayHandle<ArrayType>());
|
|
converted = true;
|
|
}
|
|
}
|
|
};
|
|
|
|
} // namespace detail
|
|
|
|
template <typename T, typename... Ss>
|
|
void UnknownArrayHandle::AsArrayHandle(
|
|
vtkm::cont::ArrayHandle<T, vtkm::cont::StorageTagMultiplexer<Ss...>>& array) const
|
|
{
|
|
bool converted = false;
|
|
vtkm::ListForEach(
|
|
detail::UnknownArrayHandleMultiplexerCastTry{}, vtkm::List<Ss...>{}, *this, array, converted);
|
|
|
|
if (!converted)
|
|
{
|
|
VTKM_LOG_CAST_FAIL(*this, decltype(array));
|
|
throwFailedDynamicCast(vtkm::cont::TypeToString(*this), vtkm::cont::TypeToString(array));
|
|
}
|
|
}
|
|
|
|
namespace detail
|
|
{
|
|
|
|
struct UnknownArrayHandleTry
|
|
{
|
|
template <typename T, typename S, typename Functor, typename... Args>
|
|
void operator()(vtkm::List<T, S>,
|
|
Functor&& f,
|
|
bool& called,
|
|
const vtkm::cont::UnknownArrayHandle& unknownArray,
|
|
Args&&... args) const
|
|
{
|
|
using DerivedArrayType = vtkm::cont::ArrayHandle<T, S>;
|
|
if (!called && unknownArray.CanConvert<DerivedArrayType>())
|
|
{
|
|
called = true;
|
|
DerivedArrayType derivedArray;
|
|
unknownArray.AsArrayHandle(derivedArray);
|
|
VTKM_LOG_CAST_SUCC(unknownArray, derivedArray);
|
|
|
|
// If you get a compile error here, it means that you have called CastAndCall for a
|
|
// vtkm::cont::UnknownArrayHandle and the arguments of the functor do not match those
|
|
// being passed. This is often because it is calling the functor with an ArrayHandle
|
|
// type that was not expected. Either add overloads to the functor to accept all
|
|
// possible array types or constrain the types tried for the CastAndCall. Note that
|
|
// the functor will be called with an array of type vtkm::cont::ArrayHandle<T, S>.
|
|
// Directly using a subclass of ArrayHandle (e.g. vtkm::cont::ArrayHandleConstant<T>)
|
|
// might not work.
|
|
f(derivedArray, std::forward<Args>(args)...);
|
|
}
|
|
}
|
|
};
|
|
|
|
} // namespace detail
|
|
|
|
namespace internal
|
|
{
|
|
|
|
namespace detail
|
|
{
|
|
|
|
template <typename T>
|
|
struct IsUndefinedArrayType
|
|
{
|
|
};
|
|
template <typename T, typename S>
|
|
struct IsUndefinedArrayType<vtkm::List<T, S>> : vtkm::cont::internal::IsInvalidArrayHandle<T, S>
|
|
{
|
|
};
|
|
|
|
} // namespace detail
|
|
|
|
template <typename ValueTypeList, typename StorageTypeList>
|
|
using ListAllArrayTypes =
|
|
vtkm::ListRemoveIf<vtkm::ListCross<ValueTypeList, StorageTypeList>, detail::IsUndefinedArrayType>;
|
|
|
|
VTKM_CONT_EXPORT void ThrowCastAndCallException(const vtkm::cont::UnknownArrayHandle&,
|
|
const std::type_info&);
|
|
|
|
} // namespace internal
|
|
|
|
template <typename TypeList, typename StorageTagList, typename Functor, typename... Args>
|
|
inline void UnknownArrayHandle::CastAndCallForTypes(Functor&& f, Args&&... args) const
|
|
{
|
|
using crossProduct = internal::ListAllArrayTypes<TypeList, StorageTagList>;
|
|
|
|
bool called = false;
|
|
vtkm::ListForEach(detail::UnknownArrayHandleTry{},
|
|
crossProduct{},
|
|
std::forward<Functor>(f),
|
|
called,
|
|
*this,
|
|
std::forward<Args>(args)...);
|
|
if (!called)
|
|
{
|
|
// throw an exception
|
|
VTKM_LOG_CAST_FAIL(*this, TypeList);
|
|
internal::ThrowCastAndCallException(*this, typeid(TypeList));
|
|
}
|
|
}
|
|
|
|
template <typename TypeList, typename StorageTagList, typename Functor, typename... Args>
|
|
VTKM_CONT void UnknownArrayHandle::CastAndCallForTypesWithFloatFallback(Functor&& functor,
|
|
Args&&... args) const
|
|
{
|
|
using crossProduct = internal::ListAllArrayTypes<TypeList, StorageTagList>;
|
|
|
|
bool called = false;
|
|
vtkm::ListForEach(detail::UnknownArrayHandleTry{},
|
|
crossProduct{},
|
|
std::forward<Functor>(functor),
|
|
called,
|
|
*this,
|
|
std::forward<Args>(args)...);
|
|
if (!called)
|
|
{
|
|
// Copy to a float array and try again
|
|
vtkm::cont::UnknownArrayHandle floatArray = this->NewInstanceFloatBasic();
|
|
floatArray.DeepCopyFrom(*this);
|
|
vtkm::ListForEach(detail::UnknownArrayHandleTry{},
|
|
crossProduct{},
|
|
std::forward<Functor>(functor),
|
|
called,
|
|
floatArray,
|
|
std::forward<Args>(args)...);
|
|
}
|
|
if (!called)
|
|
{
|
|
// throw an exception
|
|
VTKM_LOG_CAST_FAIL(*this, TypeList);
|
|
internal::ThrowCastAndCallException(*this, typeid(TypeList));
|
|
}
|
|
}
|
|
|
|
//=============================================================================
|
|
// Free function casting helpers
|
|
|
|
/// Returns true if \c variant matches the type of ArrayHandleType.
|
|
///
|
|
template <typename ArrayHandleType>
|
|
VTKM_CONT inline bool IsType(const vtkm::cont::UnknownArrayHandle& array)
|
|
{
|
|
return array.template IsType<ArrayHandleType>();
|
|
}
|
|
|
|
/// Returns \c variant cast to the given \c ArrayHandle type. Throws \c
|
|
/// ErrorBadType if the cast does not work. Use \c IsType
|
|
/// to check if the cast can happen.
|
|
///
|
|
template <typename ArrayHandleType>
|
|
VTKM_CONT inline ArrayHandleType Cast(const vtkm::cont::UnknownArrayHandle& array)
|
|
{
|
|
return array.template AsArrayHandle<ArrayHandleType>();
|
|
}
|
|
|
|
namespace detail
|
|
{
|
|
|
|
struct UnknownArrayHandleTryExtract
|
|
{
|
|
template <typename T, typename Functor, typename... Args>
|
|
void operator()(T,
|
|
Functor&& f,
|
|
bool& called,
|
|
const vtkm::cont::UnknownArrayHandle& unknownArray,
|
|
Args&&... args) const
|
|
{
|
|
if (!called && unknownArray.IsBaseComponentType<T>())
|
|
{
|
|
called = true;
|
|
auto extractedArray = unknownArray.ExtractArrayFromComponents<T>();
|
|
VTKM_LOG_CAST_SUCC(unknownArray, extractedArray);
|
|
|
|
// If you get a compile error here, it means that you have called
|
|
// CastAndCallWithExtractedArray for a vtkm::cont::UnknownArrayHandle and the arguments of
|
|
// the functor do not match those being passed. This is often because it is calling the
|
|
// functor with an ArrayHandle type that was not expected. Add overloads to the functor to
|
|
// accept all possible array types or constrain the types tried for the CastAndCall. Note
|
|
// that the functor will be called with an array of type that is different than the actual
|
|
// type of the `ArrayHandle` stored in the `UnknownArrayHandle`.
|
|
f(extractedArray, std::forward<Args>(args)...);
|
|
}
|
|
}
|
|
};
|
|
|
|
} // namespace detail
|
|
|
|
template <typename Functor, typename... Args>
|
|
inline void UnknownArrayHandle::CastAndCallWithExtractedArray(Functor&& functor,
|
|
Args&&... args) const
|
|
{
|
|
bool called = false;
|
|
vtkm::ListForEach(detail::UnknownArrayHandleTryExtract{},
|
|
vtkm::TypeListScalarAll{},
|
|
std::forward<Functor>(functor),
|
|
called,
|
|
*this,
|
|
std::forward<Args>(args)...);
|
|
if (!called)
|
|
{
|
|
// Throw an exception.
|
|
// The message will be a little wonky because the types are just the value types, not the
|
|
// full type to cast to.
|
|
VTKM_LOG_CAST_FAIL(*this, vtkm::TypeListScalarAll);
|
|
internal::ThrowCastAndCallException(*this, typeid(vtkm::TypeListScalarAll));
|
|
}
|
|
}
|
|
|
|
}
|
|
} // namespace vtkm::cont
|
|
|
|
//=============================================================================
|
|
// Specializations of serialization related classes
|
|
/// @cond SERIALIZATION
|
|
|
|
namespace vtkm
|
|
{
|
|
namespace cont
|
|
{
|
|
|
|
template <>
|
|
struct VTKM_CONT_EXPORT SerializableTypeString<vtkm::cont::UnknownArrayHandle>
|
|
{
|
|
static VTKM_CONT std::string Get();
|
|
};
|
|
}
|
|
} // namespace vtkm::cont
|
|
|
|
namespace mangled_diy_namespace
|
|
{
|
|
|
|
template <>
|
|
struct VTKM_CONT_EXPORT Serialization<vtkm::cont::UnknownArrayHandle>
|
|
{
|
|
public:
|
|
static VTKM_CONT void save(BinaryBuffer& bb, const vtkm::cont::UnknownArrayHandle& obj);
|
|
static VTKM_CONT void load(BinaryBuffer& bb, vtkm::cont::UnknownArrayHandle& obj);
|
|
};
|
|
|
|
} // namespace mangled_diy_namespace
|
|
|
|
/// @endcond SERIALIZATION
|
|
|
|
#endif //vtk_m_cont_UnknownArrayHandle_h
|