3.5. Unknown Array Handles
The vtkm::cont::ArrayHandle class uses templating to make very efficient and type-safe access to data.
However, it is sometimes inconvenient or impossible to specify the element type and storage at run-time.
The vtkm::cont::UnknownArrayHandle class provides a mechanism to manage arrays of data with unspecified types.
vtkm::cont::UnknownArrayHandle holds a reference to an array.
Unlike vtkm::cont::ArrayHandle, vtkm::cont::UnknownArrayHandle is not templated.
Instead, it uses C++ run-type type information to store the array without type and cast it when appropriate.
-
class UnknownArrayHandle
An ArrayHandle of an unknown value type and storage.
UnknownArrayHandleholds anArrayHandleobject 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 likeDataSetandFieldthat can hold numerous types.To interface between the runtime polymorphism and the templated algorithms in VTK-m,
UnknownArrayHandlecontains a method namedCastAndCallForTypes()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
UnknownArrayHandleis 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 theResetTypesAndStorage()method. This will convert this object to anUncertainArrayHandleof the given types. In cases where a finite set of types need to specified but there is no known subset,VTKM_DEFAULT_TYPE_LISTandVTKM_DEFAULT_STORAGE_LISTcan be used.ArrayHandleCastandArrayHandleMultiplexerare treated special. If theUnknownArrayHandleis set to anArrayHandleof one of these types, it will actually store theArrayHandlecontained. Likewise, if theArrayHandleis retrieved as one of these types, it will automatically convert it if possible.Subclassed by vtkm::cont::UncertainArrayHandle< ValueTypeList, StorageTypeList >
An vtkm::cont::UnknownArrayHandle can be established by constructing it with or assigning it to an vtkm::cont::ArrayHandle.
The following example demonstrates how an vtkm::cont::UnknownArrayHandle might be used to load an array whose type is not known until run-time.
1VTKM_CONT
2vtkm::cont::UnknownArrayHandle LoadUnknownArray(const void* buffer,
3 vtkm::Id length,
4 std::string type)
5{
6 vtkm::cont::UnknownArrayHandle handle;
7 if (type == "float")
8 {
9 vtkm::cont::ArrayHandle<vtkm::Float32> concreteArray = vtkm::cont::make_ArrayHandle(
10 reinterpret_cast<const vtkm::Float32*>(buffer), length, vtkm::CopyFlag::On);
11 handle = concreteArray;
12 }
13 else if (type == "int")
14 {
15 vtkm::cont::ArrayHandle<vtkm::Int32> concreteArray = vtkm::cont::make_ArrayHandle(
16 reinterpret_cast<const vtkm::Int32*>(buffer), length, vtkm::CopyFlag::On);
17 handle = concreteArray;
18 }
19 return handle;
20}
It is possible to construct a vtkm::cont::UnknownArrayHandle that does not point to any vtkm::cont::ArrayHandle.
In this case, the vtkm::cont::UnknownArrayHandle is considered not “valid.”
Validity can be tested with the vtkm::cont::UnknownArrayHandle::IsValid() method.
-
bool vtkm::cont::UnknownArrayHandle::IsValid() const
Returns whether an array is stored in this
UnknownArrayHandle.If the
UnknownArrayHandleis constructed without anArrayHandle, it will not have an underlying type, and therefore the operations will be invalid. It is still possible to set thisUnknownArrayHandleto anArrayHandle.
Most of the following operations on vtkm::cont::UnknownArrayHandle will fail by throwing an exception if it is not valid.
Note that it is also possible for a vtkm::cont::UnknownArrayHandle to contain an empty vtkm::cont::ArrayHandle.
A vtkm::cont::UnknownArrayHandle that contains a vtkm::cont::ArrayHandle but has no memory allocated is still considered valid.
Some basic, human-readable information can be retrieved using the vtkm::cont::UnknownArrayHandle::PrintSummary() method.
It will print the type and size of the array along with some or all of the values.
-
void vtkm::cont::UnknownArrayHandle::PrintSummary(std::ostream &out, bool full = false) const
Prints a summary of the array’s type, size, and contents.
3.5.1. Allocation
Data pointed to by an vtkm::cont::UnknownArrayHandle is not directly accessible.
However, it is still possible to do some type-agnostic manipulation of the array allocations.
First, it is always possible to call vtkm::cont::UnknownArrayHandle::GetNumberOfValues() to retrieve the current size of the array.
It is also possible to call vtkm::cont::UnknownArrayHandle::Allocate() to change the size of an unknown array.
vtkm::cont::UnknownArrayHandle’s vtkm::cont::UnknownArrayHandle::Allocate() works exactly the same as the vtkm::cont::ArrayHandle::Allocate() in the basic vtkm::cont::ArrayHandle.
-
vtkm::Id vtkm::cont::UnknownArrayHandle::GetNumberOfValues() const
Returns the number of values in the array.
-
void vtkm::cont::UnknownArrayHandle::Allocate(vtkm::Id numValues, vtkm::CopyFlag preserve, vtkm::cont::Token &token) const
Reallocate the data in the array.
The allocation works the same as the
Allocate()method ofvtkm::cont::ArrayHandle.
-
void vtkm::cont::UnknownArrayHandle::Allocate(vtkm::Id numValues, vtkm::CopyFlag preserve = vtkm::CopyFlag::Off) const
Reallocate the data in the array.
The allocation works the same as the
Allocate()method ofvtkm::cont::ArrayHandle.
1 vtkm::cont::UnknownArrayHandle unknownHandle = // ... some valid array
2
3 // Double the size of the array while preserving all the initial values.
4 vtkm::Id originalArraySize = unknownHandle.GetNumberOfValues();
5 unknownHandle.Allocate(originalArraySize * 2, vtkm::CopyFlag::On);
It is often the case where you have an vtkm::cont::UnknownArrayHandle as the input to an operation and you want to generate an output of the same type.
To handle this case, use the vtkm::cont::UnknownArrayHandle::NewInstance() method to create a new array of the same type (without having to determine the type).
-
UnknownArrayHandle vtkm::cont::UnknownArrayHandle::NewInstance() const
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
UnknownArrayHandlefor it. This method is convenient when creating output arrays that should be the same type as some input array.
1 vtkm::cont::UnknownArrayHandle unknownHandle = // ... some valid array
2
3 // Double the size of the array while preserving all the initial values.
4 vtkm::Id originalArraySize = unknownHandle.GetNumberOfValues();
5 unknownHandle.Allocate(originalArraySize * 2, vtkm::CopyFlag::On);
6
7 // Create a new array of the same type as the original.
8 vtkm::cont::UnknownArrayHandle newArray = unknownHandle.NewInstance();
9
10 newArray.Allocate(originalArraySize);
That said, there are many special array handles described in Chapter 4.8 (Memory Layout of Array Handles) and Chapter 4.9 (Fancy Array Handles) that either cannot be directly constructed or cannot be used as outputs.
Thus, if you do not know the storage of the array, the similar array returned by vtkm::cont::UnknownArrayHandle::NewInstance() could be infeasible for use as an output.
Thus, vtkm::cont::UnknownArrayHandle also contains the vtkm::cont::UnknownArrayHandle::NewInstanceBasic() method to create a new array with the same value type but using the basic array storage, which can always be resized and written to.
-
UnknownArrayHandle vtkm::cont::UnknownArrayHandle::NewInstanceBasic() const
Create a new
ArrayHandleBasicwith the sameValueTypeas this array.This method creates a new
ArrayHandleBasicthat has the sameValueTypeas the array held by this one and returns a newUnknownArrayHandlefor 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.
1 vtkm::cont::UnknownArrayHandle indexArray = vtkm::cont::ArrayHandleIndex();
2 // Returns an array of type ArrayHandleBasic<vtkm::Id>
3 vtkm::cont::UnknownArrayHandle basicArray = indexArray.NewInstanceBasic();
It is sometimes the case that you need a new array of a similar type, but that type has to hold floating point values.
For example, if you had an operation that computed a discrete cosine transform on an array, the result would be very inaccurate if stored as integers.
In this case, you would actually want to store the result in an array of floating point values.
For this case, you can use the vtkm::cont::UnknownArrayHandle::NewInstanceFloatBasic() to create a new basic vtkm::cont::ArrayHandle with the component type changed to vtkm::FloatDefault.
For example, if the vtkm::cont::UnknownArrayHandle stores an vtkm::cont::ArrayHandle of type vtkm::Id, vtkm::cont::UnknownArrayHandle::NewInstanceFloatBasic() will create an vtkm::cont::ArrayHandle of type vtkm::FloatDefault.
If the vtkm::cont::UnknownArrayHandle stores an vtkm::cont::ArrayHandle of type vtkm::Id3, vtkm::cont::UnknownArrayHandle::NewInstanceFloatBasic() will create an vtkm::cont::ArrayHandle of type vtkm::Vec3f.
-
UnknownArrayHandle vtkm::cont::UnknownArrayHandle::NewInstanceFloatBasic() const
Create a new
ArrayHandleBasicwith the base component ofvtkm::FloatDefaultThis method creates a new
ArrayHandleBasicthat has aValueTypethat is similar to the array held by this one except that the base component type is replaced withvtkm::FloatDefault. For example, if the contained array hasvtkm::Int32value types, the returned array will havevtkm::FloatDefaultvalue types. If the contained array hasvtkm::Id3value types, the returned array will havevtkm::Vec3fvalue types. If the contained array already hasvtkm::FloatDefaultas 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.
1 vtkm::cont::UnknownArrayHandle intArray = vtkm::cont::ArrayHandleIndex();
2 // Returns an array of type ArrayHandleBasic<vtkm::FloatDefault>
3 vtkm::cont::UnknownArrayHandle floatArray = intArray.NewInstanceFloatBasic();
4
5 vtkm::cont::UnknownArrayHandle id3Array = vtkm::cont::ArrayHandle<vtkm::Id3>();
6 // Returns an array of type ArrayHandleBasic<vtkm::Vec3f>
7 vtkm::cont::UnknownArrayHandle float3Array = id3Array.NewInstanceFloatBasic();
Finally, it may be the case where you are finished using a vtkm::cont::UnknownArrayHandle.
If you want to free up memory on the device, which may have limited memory, you can do so with vtkm::cont::UnknownArrayHandle::ReleaseResourcesExecution(), which will free any memory on the device but preserve the data on the host.
If the data will never be used again, all memory can be freed with vtkm::cont::UnknownArrayHandle::ReleaseResources()
-
void vtkm::cont::UnknownArrayHandle::ReleaseResourcesExecution() const
Releases any resources being used in the execution environment (that are not being shared by the control environment).
-
void vtkm::cont::UnknownArrayHandle::ReleaseResources() const
Releases all resources in both the control and execution environments.
3.5.2. Casting to Known Types
Data pointed to by an vtkm::cont::UnknownArrayHandle is not directly
accessible.
To access the data, you need to retrieve the data as an vtkm::cont::ArrayHandle.
If you happen to know (or can guess) the type, you can use the vtkm::cont::UnknownArrayHandle::AsArrayHandle() method to retrieve the array as a specific type.
-
template<typename T, typename S>
inline void vtkm::cont::UnknownArrayHandle::AsArrayHandle(vtkm::cont::ArrayHandle<T, S> &array) const Returns this array cast appropriately and stored in the given
ArrayHandletype.Throws a
vtkm::cont::ErrorBadTypeif the stored array cannot be stored in the given array type. Use theCanConvert()method to determine if the array can be returned with the given type.
-
template<typename ArrayType>
inline ArrayType vtkm::cont::UnknownArrayHandle::AsArrayHandle() const Returns this array cast appropriately and stored in the given
ArrayHandletype.Throws a
vtkm::cont::ErrorBadTypeif the stored array cannot be stored in the given array type. Use theCanConvert()method to determine if the array can be returned with the given type.
1 vtkm::cont::ArrayHandle<vtkm::Float32> knownArray =
2 unknownArray.AsArrayHandle<vtkm::cont::ArrayHandle<vtkm::Float32>>();
vtkm::cont::UnknownArrayHandle::AsArrayHandle() actually has two forms.
The first form, shown in the previous example, has no arguments and returns the vtkm::cont::ArrayHandle.
This form requires you to specify the type of array as a template parameter.
The alternate form has you pass a reference to a concrete vtkm::cont::ArrayHandle as an argument as shown in the following example.
This form can imply the template parameter from the argument.
vtkm::cont::UnknownArrayHandle.1 unknownArray.AsArrayHandle(knownArray);
vtkm::cont::UnknownArrayHandle::AsArrayHandle() treats vtkm::cont::ArrayHandleCast and vtkm::cont::ArrayHandleMultiplexer special.
If the special vtkm::cont::ArrayHandle can hold the actual array stored, then vtkm::cont::UnknownArrayHandle::AsArrayHandle() will return successfully.
In the following example, vtkm::cont::UnknownArrayHandle::AsArrayHandle() returns an array of type vtkm::Float32 as an vtkm::cont::ArrayHandleCast that converts the values to vtkm::Float64.
1 vtkm::cont::ArrayHandle<vtkm::Float32> originalArray;
2 vtkm::cont::UnknownArrayHandle unknownArray = originalArray;
3
4 vtkm::cont::ArrayHandleCast<vtkm::Float64, decltype(originalArray)> castArray;
5 unknownArray.AsArrayHandle(castArray);
Did You Know?
The inverse retrieval works as well.
If you create an vtkm::cont::UnknownArrayHandle with an vtkm::cont::ArrayHandleCast or vtkm::cont::ArrayHandleMultiplexer, you can get the underlying array with vtkm::cont::UnknownArrayHandle::AsArrayHandle().
These relationships also work recursively (e.g. an array placed in a cast array that is placed in a multiplexer).
If the vtkm::cont::UnknownArrayHandle cannot store its array in the type given to vtkm::cont::UnknownArrayHandle::AsArrayHandle(), it will throw an exception.
Thus, you should not use vtkm::cont::UnknownArrayHandle::AsArrayHandle() with types that you are not sure about.
Use the vtkm::cont::UnknownArrayHandle::CanConvert() method to determine if a given vtkm::cont::ArrayHandle type will work with vtkm::cont::UnknownArrayHandle::AsArrayHandle().
-
template<typename ArrayHandleType>
inline bool vtkm::cont::UnknownArrayHandle::CanConvert() const 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 toIsType(), and ifIsType()returns true, then this will return true. However, this method will also return true for other types such as anArrayHandleMultiplexerthat can contain the array.
vtkm::cont::ArrayHandle can be retrieved from a vtkm::cont::UnknownArrayHandle. 1VTKM_CONT vtkm::FloatDefault GetMiddleValue(
2 const vtkm::cont::UnknownArrayHandle& unknownArray)
3{
4 if (unknownArray.CanConvert<vtkm::cont::ArrayHandleConstant<vtkm::FloatDefault>>())
5 {
6 // Fast path for known array
7 vtkm::cont::ArrayHandleConstant<vtkm::FloatDefault> constantArray;
8 unknownArray.AsArrayHandle(constantArray);
9 return constantArray.GetValue();
10 }
11 else
12 {
13 // General path
14 auto ranges = vtkm::cont::ArrayRangeCompute(unknownArray);
15 vtkm::Range range = ranges.ReadPortal().Get(0);
16 return static_cast<vtkm::FloatDefault>((range.Min + range.Max) / 2);
17 }
18}
By design, vtkm::cont::UnknownArrayHandle::CanConvert() will return true for types that are not actually stored in the vtkm::cont::UnknownArrayHandle but can be retrieved.
If you need to know specifically what type is stored in the vtkm::cont::UnknownArrayHandle, you can use the vtkm::cont::UnknownArrayHandle::IsType() method instead.
-
template<typename ArrayHandleType>
inline bool vtkm::cont::UnknownArrayHandle::IsType() const Returns true if this array matches the ArrayHandleType template argument.
Note that
UnknownArrayHandlehas some special handling forArrayHandleCastandArrayHandleMultiplexer. If you stored an array of one of these types into anUnknownArrayHandle, the type of the underlying array will change andIsType()will fail. However, you can still get the array back out as that type usingAsArrayHandle.Use the
CanConvert()method instead to determine if theUnknownArrayHandlecontains an array that “matches” the array of a given type. Under most circumstances, you should preferCanConvert()overIsType().
If you need to query either the value type or the storage, you can use vtkm::cont::UnknownArrayHandle::IsValueType() and vtkm::cont::UnknownArrayHandle::IsStorageType(), respectively.
vtkm::cont::UnknownArrayHandle also provides vtkm::cont::UnknownArrayHandle::GetValueTypeName(), vtkm::cont::UnknownArrayHandle::GetStorageTypeName(), and vtkm::cont::UnknownArrayHandle::GetArrayTypeName() for debugging purposes.
-
template<typename ValueType>
inline bool vtkm::cont::UnknownArrayHandle::IsValueType() const Returns true if this array matches the ValueType template argument.
-
template<typename StorageType>
inline bool vtkm::cont::UnknownArrayHandle::IsStorageType() const Returns true if this array matches the StorageType template argument.
-
std::string vtkm::cont::UnknownArrayHandle::GetValueTypeName() const
Returns the name of the value type stored in the array.
Returns an empty string if no array is stored.
-
std::string vtkm::cont::UnknownArrayHandle::GetStorageTypeName() const
Returns the name of the storage tag for the array.
Returns an empty string if no array is stored.
-
std::string vtkm::cont::UnknownArrayHandle::GetArrayTypeName() const
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.
Common Errors
vtkm::cont::UnknownArrayHandle::CanConvert() is almost always safer to use than vtkm::cont::UnknownArrayHandle::IsType() or its similar methods.
Even though vtkm::cont::UnknownArrayHandle::IsType() reflects the actual array type, vtkm::cont::UnknownArrayHandle::CanConvert() better describes how vtkm::cont::UnknownArrayHandle will behave.
If you do not know the exact type of the array contained in an vtkm::cont::UnknownArrayHandle, a brute force method to get the data out is to copy it to an array of a known type.
This can be done with the vtkm::cont::UnknownArrayHandle::DeepCopyFrom() method, which will copy the contents of a target array into an existing array of a (potentially) different type.
-
void vtkm::cont::UnknownArrayHandle::DeepCopyFrom(const vtkm::cont::UnknownArrayHandle &source)
Deep copies data from another
UnknownArrayHandle.This method takes an
UnknownArrayHandleand deep copies data from it.If this object does not point to an existing
ArrayHandle, a newArrayHandleBasicwith the same value type of thesourceis created.
-
void vtkm::cont::UnknownArrayHandle::DeepCopyFrom(const vtkm::cont::UnknownArrayHandle &source) const
Deep copies data from another
UnknownArrayHandle.This method takes an
UnknownArrayHandleand deep copies data from it.If this object does not point to an existing
ArrayHandle, this const version ofDeepCopyFrom()throws an exception.
1VTKM_CONT vtkm::cont::ArrayHandle<vtkm::FloatDefault> CopyToDefaultArray(
2 const vtkm::cont::UnknownArrayHandle& unknownArray)
3{
4 // Initialize the output UnknownArrayHandle with the array type we want to copy to.
5 vtkm::cont::UnknownArrayHandle output = vtkm::cont::ArrayHandle<vtkm::FloatDefault>{};
6 output.DeepCopyFrom(unknownArray);
7 return output.AsArrayHandle<vtkm::cont::ArrayHandle<vtkm::FloatDefault>>();
8}
It is often the case that you have good reason to believe that an array is of an expected type, but you have no way to be sure.
To simplify code, the most rational thing to do is to get the array as the expected type if that is indeed what it is, or to copy it to an array of that type otherwise.
The vtkm::cont::UnknownArrayHandle::CopyShallowIfPossible() does just that.
-
void vtkm::cont::UnknownArrayHandle::CopyShallowIfPossible(const vtkm::cont::UnknownArrayHandle &source)
Attempts a shallow copy of an array or a deep copy if that is not possible.
This method takes an
UnknownArrayHandleand attempts to perform a shallow copy. This shallow copy occurs if this object points to anArrayHandleof the same type or does not point to anyArrayHandleat all. If this is not possible, then the array is deep copied.This method is roughly equivalent to the
vtkm::cont::ArrayCopyShallowIfPossible()function (defined invtkm/cont/ArrayCopy.h). However, this method can be used without having to use a device compiler (whereasvtkm::cont::ArrayCopyShallowIfPossible()does require a device device compiler).
-
void vtkm::cont::UnknownArrayHandle::CopyShallowIfPossible(const vtkm::cont::UnknownArrayHandle &source) const
Attempts a shallow copy of an array or a deep copy if that is not possible.
This method takes an
UnknownArrayHandleand attempts to perform a shallow copy. This shallow copy occurs if this object points to anArrayHandleof 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 ofCopyShallowIfPossible()throws an exception.This method is roughly equivalent to the
vtkm::cont::ArrayCopyShallowIfPossible()function (defined invtkm/cont/ArrayCopy.h). However, this method can be used without having to use a device compiler (whereasvtkm::cont::ArrayCopyShallowIfPossible()does require a device device compiler).
vtkm::cont::UnknownArrayHandle::CopyShallowIfPossible() to get an unknown array as a particular type.1VTKM_CONT vtkm::cont::ArrayHandle<vtkm::FloatDefault> GetAsDefaultArray(
2 const vtkm::cont::UnknownArrayHandle& unknownArray)
3{
4 // Initialize the output UnknownArrayHandle with the array type we want to copy to.
5 vtkm::cont::UnknownArrayHandle output = vtkm::cont::ArrayHandle<vtkm::FloatDefault>{};
6 output.CopyShallowIfPossible(unknownArray);
7 return output.AsArrayHandle<vtkm::cont::ArrayHandle<vtkm::FloatDefault>>();
8}
Did You Know?
The vtkm::cont::UnknownArrayHandle copy methods behave similarly to the vtkm::cont::ArrayCopy() functions.
3.5.3. Casting to a List of Potential Types
Using vtkm::cont::UnknownArrayHandle::AsArrayHandle() is fine as long as the correct types are known, but often times they are not.
For this use case vtkm::cont::UnknownArrayHandle has a method named vtkm::cont::UnknownArrayHandle::CastAndCallForTypes() that attempts to cast the array to some set of types.
The vtkm::cont::UnknownArrayHandle::CastAndCallForTypes() method accepts a functor to run on the appropriately cast array.
The functor must have an overloaded const parentheses operator that accepts an vtkm::cont::ArrayHandle of the appropriate type.
You also have to specify two template parameters that specify a vtkm::List of value types to try and a vtkm::List of storage types to try, respectively.
The macros VTKM_DEFAULT_TYPE_LIST and VTKM_DEFAULT_STORAGE_LIST are often used when nothing more specific is known.
-
template<typename TypeList, typename StorageList, typename Functor, typename ...Args>
inline void vtkm::cont::UnknownArrayHandle::CastAndCallForTypes(Functor &&functor, Args&&... args) const 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 theTypeListandStorageListas template arguments.After the functor argument you may add any number of arguments that will be passed to the functor after the converted
ArrayHandle.
vtkm::cont::UnknownArrayHandle with vtkm::cont::UnknownArrayHandle::CastAndCallForTypes(). 1struct PrintArrayContentsFunctor
2{
3 template<typename T, typename S>
4 VTKM_CONT void operator()(const vtkm::cont::ArrayHandle<T, S>& array) const
5 {
6 this->PrintArrayPortal(array.ReadPortal());
7 }
8
9private:
10 template<typename PortalType>
11 VTKM_CONT void PrintArrayPortal(const PortalType& portal) const
12 {
13 for (vtkm::Id index = 0; index < portal.GetNumberOfValues(); index++)
14 {
15 // All ArrayPortal objects have ValueType for the type of each value.
16 using ValueType = typename PortalType::ValueType;
17 using VTraits = vtkm::VecTraits<ValueType>;
18
19 ValueType value = portal.Get(index);
20
21 vtkm::IdComponent numComponents = VTraits::GetNumberOfComponents(value);
22 for (vtkm::IdComponent componentIndex = 0; componentIndex < numComponents;
23 componentIndex++)
24 {
25 std::cout << " " << VTraits::GetComponent(value, componentIndex);
26 }
27 std::cout << std::endl;
28 }
29 }
30};
31
32void PrintArrayContents(const vtkm::cont::UnknownArrayHandle& array)
33{
34 array.CastAndCallForTypes<VTKM_DEFAULT_TYPE_LIST, VTKM_DEFAULT_STORAGE_LIST>(
35 PrintArrayContentsFunctor{});
36}
Did You Know?
The first (required) argument to vtkm::cont::UnknownArrayHandle::CastAndCallForTypes() is the functor to call with the array.
You can supply any number of optional arguments after that.
Those arguments will be passed directly to the functor.
This makes it easy to pass state to the functor.
Did You Know?
When an vtkm::cont::UnknownArrayHandle is used in place of an vtkm::cont::ArrayHandle as an argument to a worklet invocation, it will internally use vtkm::cont::UnknownArrayHandle::CastAndCallForTypes() to attempt to call the worklet with an vtkm::cont::ArrayHandle of the correct type.
vtkm::cont::UnknownArrayHandle has a simple subclass named vtkm::cont::UncertainArrayHandle for use when you can narrow the array to a finite set of types.
vtkm::cont::UncertainArrayHandle has two template parameters that must be specified: a vtkm::List of value types and a vtkm::List of storage types.
-
template<typename ValueTypeList, typename StorageTypeList>
class UncertainArrayHandle : public vtkm::cont::UnknownArrayHandle An ArrayHandle of an uncertain value type and storage.
UncertainArrayHandleholds anArrayHandleobject using runtime polymorphism to manage different value and storage types. It behaves like its superclass,UnknownArrayHandle, except that it also contains two template parameters that providevtkm::Lists of potential value and storage types, respectively.These potential value and storage types come into play when the
CastAndCallmethod is called (or theUncertainArrayHandleis used in thevtkm::cont::CastAndCallfunction). In this case, theCastAndCallwill search forArrayHandles of types that match these two lists.Both
UncertainArrayHandleandUnknownArrayHandlehave a method namedResetTypesthat redefine the lists of potential value and storage types by returning a newUncertainArrayHandlecontaining the sameArrayHandlebut with the new value and storage type lists.
vtkm::cont::UncertainArrayHandle has a method named vtkm::cont::UncertainArrayHandle::CastAndCall() that behaves the same as vtkm::cont::UnknownArrayHandle::CastAndCallForTypes() except that you do not have to specify the types to try.
Instead, the types are taken from the template parameters of the vtkm::cont::UncertainArrayHandle itself.
-
template<typename Functor, typename ...Args>
inline void vtkm::cont::UncertainArrayHandle::CastAndCall(Functor &&functor, Args&&... args) const Call a functor using the underlying array type.
CastAndCallattempts to cast the held array to a specific value type, and then calls the given functor with the cast array.
1 vtkm::cont::UncertainArrayHandle<vtkm::TypeListScalarAll, vtkm::cont::StorageListBasic>
2 uncertainArray(unknownArray);
3 uncertainArray.CastAndCall(PrintArrayContentsFunctor{});
Did You Know?
Like with vtkm::cont::UnknownArrayHandle, if an vtkm::cont::UncertainArrayHandle is used in a worklet invocation, it will internally use vtkm::cont::UncertainArrayHandle::CastAndCall().
This provides a convenient way to specify what array types the invoker should try.
Both vtkm::cont::UnknownArrayHandle and vtkm::cont::UncertainArrayHandle provide a method named vtkm::cont::UnknownArrayHandle::ResetTypes() to redefine the types to try.
vtkm::cont::UncertainArrayHandle::ResetTypes() has two template parameters that are the vtkm::List’s of value and storage types.
vtkm::cont::UnknownArrayHandle::ResetTypes() returns a new vtkm::cont::UncertainArrayHandle with the given types.
This is a convenient way to pass these types to functions.
-
template<typename NewValueTypeList, typename NewStorageTypeList>
vtkm::cont::UncertainArrayHandle<NewValueTypeList, NewStorageTypeList> vtkm::cont::UnknownArrayHandle::ResetTypes(NewValueTypeList = NewValueTypeList{}, NewStorageTypeList = NewStorageTypeList{}) const Assigns potential value and storage types.
Calling this method will return an
UncertainArrayHandlewith the provided value and storage type lists. The returned object will hold the sameArrayHandle, butCastAndCalls on the returned object will be constrained to the given types.
vtkm::cont::UncertainArrayHandle additionally has methods named vtkm::cont::UncertainArrayHandle::ResetValueTypes() and vtkm::cont::UncertainArrayHandle::ResetStorageTypes() to reset the value types and storage types, respectively, without modifying the other.
-
template<typename NewValueTypeList>
inline UncertainArrayHandle<NewValueTypeList, StorageTypeList> vtkm::cont::UncertainArrayHandle::ResetValueTypes(NewValueTypeList = NewValueTypeList{}) const Like
ResetTypesexcept it only resets the value types.
-
template<typename NewStorageTypeList>
inline UncertainArrayHandle<ValueTypeList, NewStorageTypeList> vtkm::cont::UncertainArrayHandle::ResetStorageTypes(NewStorageTypeList = NewStorageTypeList{}) const Like
ResetTypesexcept it only resets the storage types.
1 vtkm::cont::Invoker invoke;
2 invoke(
3 MyWorklet{},
4 unknownArray.ResetTypes<vtkm::TypeListScalarAll, vtkm::cont::StorageListBasic>(),
5 outArray);
Common Errors
Because it returns an vtkm::cont::UncertainArrayHandle, you need to include vtkm/cont/UncertainArrayHandle.h if you use vtkm::cont::UnknownArrayHandle::ResetTypes().
This is true even if you do not directly use the returned object.
3.5.4. Accessing Truly Unknown Arrays
So far in Section 3.5.2 (Casting to Known Types) and Section 3.5.3 (Casting to a List of Potential Types) we explored how to access the data in an vtkm::cont::UnknownArrayHandle when you actually know the array type or can narrow down the array type to some finite number of candidates.
But what happens if you cannot practically narrow down the types in the vtkm::cont::UnknownArrayHandle?
For this case, vtkm::cont::UnknownArrayHandle provides mechanisms for extracting data knowing little or nothing about the types.
3.5.4.1. Cast with Floating Point Fallback
The problem with vtkm::cont::UnknownArrayHandle::CastAndCallForTypes() and vtkm::cont::UncertainArrayHandle::CastAndCall() is that you can only list a finite amount of value types and storage types to try.
If you encounter an vtkm::cont::UnknownArrayHandle containing a different vtkm::cont::ArrayHandle type, the cast and call will simply fail.
Since the compiler must create a code path for each possible vtkm::cont::ArrayHandle type, it may not even be feasible to list all known types.
vtkm::cont::UnknownArrayHandle::CastAndCallForTypesWithFloatFallback() works around this problem by providing a fallback in case the contained vtkm::cont::ArrayHandle does not match any of the types tried.
If none of the types match, then vtkm::cont::UnknownArrayHandle::CastAndCallForTypesWithFloatFallback() will copy the data to a vtkm::cont::ArrayHandle with vtkm::FloatDefault values (or some compatible vtkm::Vec with vtkm::FloatDefault components) and basic storage.
It will then attempt to match again with this copied array.
-
template<typename TypeList, typename StorageList, typename Functor, typename ...Args>
void vtkm::cont::UnknownArrayHandle::CastAndCallForTypesWithFloatFallback(Functor &&functor, Args&&... args) const 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 theTypeListandStorageListas 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
ArrayHandleBasicwithvtkm::FloatDefaultcomponents in its value and attempts to cast to those types.
1 unknownArray.CastAndCallForTypesWithFloatFallback<vtkm::TypeListField,
2 VTKM_DEFAULT_STORAGE_LIST>(
3 PrintArrayContentsFunctor{});
In this case, we do not have to list every possible type because the array will be copied to a known type if nothing matches.
Note that when using vtkm::cont::UnknownArrayHandle::CastAndCallForTypesWithFloatFallback(), you still need to include an appropriate type based on vtkm::FloatDefault in the value type list and vtkm::cont::StorageTagBasic in the storage list so that the copied array can match.
vtkm::cont::UncertainArrayHandle has a matching method named vtkm::cont::UncertainArrayHandle::CastAndCallWithFloatFallback() that does the same operation using the types specified in the vtkm::cont::UncertainArrayHandle.
-
template<typename Functor, typename ...Args>
inline void vtkm::cont::UncertainArrayHandle::CastAndCallWithFloatFallback(Functor &&functor, Args&&... args) const Call a functor using the underlying array type with a float cast fallback.
CastAndCallWithFloatFallback()attempts to cast the held array to a specific value type, and then calls the given functor with the cast array. If the underlying array does not match any of the requested array types, the array is copied to a newArrayHandleBasicwithvtkm::FloatDefaultcomponents in its value and attempts to cast to those types.
vtkm::cont::UncertainArrayHandle with a float fallback.1 uncertainArray.CastAndCallWithFloatFallback(PrintArrayContentsFunctor{});
3.5.4.2. Extracting Components
Using a floating point fallback allows you to use arrays of unknown types in most circumstances, but it does have a few drawbacks.
First, and most obvious, is that you may not operate on the data in its native format.
If you want to preserve the integer format of data, this may not be the method.
Second, the fallback requires a copy of the data.
If vtkm::cont::UnknownArrayHandle::CastAndCallForTypesWithFloatFallback() does not match the type of the array, it copies the array to a new type that (hopefully) can be matched.
Third, vtkm::cont::UnknownArrayHandle::CastAndCallForTypesWithFloatFallback() still needs to match the number of components in each array value.
If the contained vtkm::cont::ArrayHandle contains values that are vtkm::Vec’s of length 2, then the data will be copied to an array of vtkm::Vec2f’s.
If vtkm::Vec2f is not included in the types to try, the cast and call will still fail.
A way to get around these problems is to extract a single component from the array.
You can use the vtkm::cont::UnknownArrayHandle::ExtractComponent() method to return an vtkm::cont::ArrayHandle with the values for a given component for each value in the array.
The type of the returned vtkm::cont::ArrayHandle will be the same regardless of the actual array type stored in the vtkm::cont::UnknownArrayHandle.
-
template<typename BaseComponentType>
inline vtkm::cont::ArrayHandleStride<BaseComponentType> vtkm::cont::UnknownArrayHandle::ExtractComponent(vtkm::IdComponent componentIndex, vtkm::CopyFlag allowCopy = vtkm::CopyFlag::On) const Extract a component of the array.
This method returns an array that holds the data for a given flat component of the data. The
BaseComponentTypehas to be specified and must match the contained array (i.e. the result ofIsBaseComponentType()must succeed for the given type).This method treats each value in the array as a flat
vtkm::Veceven if it is avtkm::VecofVecs. For example, if the array actually holds values of typevtkm::Vec<vtkm::Vec<T, 3>, 2>, it is treated as if it holds aVec<T, 6>. Seevtkm::VecFlatfor details on how vectors are flattened.The point of using
ExtractComponent()overAsArrayHandle()is that it drastically reduces the amount of types you have to try. Most of the time 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 containingvtkm::Vecis 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 likeArrayHandleBasicandArrayHandleSOA.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
allowCopyflag tovtkm::CopyFlag::Off. In this case, an exception will be thrown if the result cannot be represented by a shallow copy.
vtkm::cont::UnknownArrayHandle::ExtractComponent() must be given a template argument for the base component type.
The following example extracts the first component of all vtkm::Vec values in an vtkm::cont::UnknownArrayHandle assuming that the component is of type vtkm::FloatDefault (Example 3.43, line 11).
1 vtkm::cont::ArrayHandleBasic<vtkm::Vec3f> concreteArray =
2 vtkm::cont::make_ArrayHandle<vtkm::Vec3f>({ { 0, 1, 2 },
3 { 3, 4, 5 },
4 { 6, 7, 8 },
5 { 9, 10, 11 },
6 { 12, 13, 14 },
7 { 15, 16, 17 } });
8
9 vtkm::cont::UnknownArrayHandle unknownArray(concreteArray);
10
11 auto componentArray = unknownArray.ExtractComponent<vtkm::FloatDefault>(0);
12 // componentArray contains [ 0, 3, 6, 9, 12, 15 ].
The code in Example 3.43 works with any array with values based on the default floating point type.
If the vtkm::cont::UnknownArrayHandle has an array containing vtkm::FloatDefault, then the returned array has all the same values.
If the vtkm::cont::UnknownArrayHandle contains values of type vtkm::Vec3f, then each value in the returned array will be the first component of this array.
If the vtkm::cont::UnknownArrayHandle really contains an array with incompatible value types (such as vtkm::cont::ArrayHandle<vtkm::Id>), then an vtkm::cont::ErrorBadType will be thrown.
To check if the vtkm::cont::UnknownArrayHandle contains an array of a compatible type, use the vtkm::cont::UnknownArrayHandle::IsBaseComponentType() method to check the component type being used as the template argument to vtkm::cont::UnknownArrayHandle::ExtractComponent().
-
template<typename BaseComponentType>
inline bool vtkm::cont::UnknownArrayHandle::IsBaseComponentType() const Returns true if this array’s
ValueTypehas the provided base component type.The base component type is the recursive component type of any
Vec-like object. So if the array’sValueTypeisvtkm::Vec<vtkm::Float32, 3>, then the base component type will bevtkm::Float32. Likewise, if theValueTypeisvtkm::Vec<vtkm::Vec<vtkm::Float32, 3>, 2>, then the base component type is stillvtkm::Float32.If the
ValueTypeis notVec-like type, then the base component type is the same. So aValueTypeofvtkm::Float32has a base component type ofvtkm::Float32.
1 unknownArray.IsBaseComponentType<vtkm::FloatDefault>()
it is also possible to get a name for the base component type (mostly for debugging purposes) with vtkm::cont::UnknownArrayHandle::GetBaseComponentTypeName().
-
std::string vtkm::cont::UnknownArrayHandle::GetBaseComponentTypeName() const
Returns the name of the base component of the value type stored in the array.
Returns an empty string if no array is stored.
You will often need to query the number of components that can be extracted from the array.
This can be queried with vtkm::cont::UnknownArrayHandle::GetNumberOfComponentsFlat().
-
vtkm::IdComponent vtkm::cont::UnknownArrayHandle::GetNumberOfComponentsFlat() const
Returns the total number of components for each value in the array.
If the array holds
vtkm::Vecobjects, this will return the total number of components in each value assuming the object is flattened out to one level ofVecobjects. If the array holds a basic C type (such asfloat), this will return 1. If the array holds a simpleVec(such asvtkm::Vec3f), this will return the number of components (in this case 3). If the array holds a hierarchy ofVecs (such asvtkm::Vec<vtkm::Vec3f, 2>), this will return the total number of vecs (in this case 6).If this object is holding an array where the number of components can be selected at runtime (for example,
vtkm::cont::ArrayHandleRuntimeVec), this method will still return the correct number of components. However, if each value in the array can be aVecof a different size (such asvtkm::cont::ArrayHandleGroupVecVariable), this method will return 0 (because there is no consistent answer).
This section started with the motivation of getting data from an vtkm::cont::UnknownArrayHandle without knowing anything about the type, yet vtkm::cont::UnknownArrayHandle::ExtractComponent() still requires a type parameter.
However, by limiting the type needed to the base component type, you only need to check the base C types (standard integers and floating points) available in C++.
You do not need to know whether these components are arranged in vtkm::Vec’s or the size of the vtkm::Vec.
A general implementation of an algorithm might have to deal with scalars as well as vtkm::Vec’s of size 2, 3, and 4.
If we consider operations on tensors, vtkm::Vec’s of size 6 and 9 can be common as well.
But when using vtkm::cont::UnknownArrayHandle::ExtractComponent(), a single condition can handle any potential vtkm::Vec size.
Another advantage of vtkm::cont::UnknownArrayHandle::ExtractComponent() is that the type of storage does not need to be specified.
vtkm::cont::UnknownArrayHandle::ExtractComponent() works with any type of vtkm::cont::ArrayHandle storage (with some caveats).
So, Example 3.43 works equally as well with vtkm::cont::ArrayHandleBasic, vtkm::cont::ArrayHandleSOA, vtkm::cont::ArrayHandleUniformPointCoordinates, vtkm::cont::ArrayHandleCartesianProduct, and many others.
Trying to capture all reasonable types of arrays could easily require hundreds of conditions, all of which and more can be captured with vtkm::cont::UnknownArrayHandle::ExtractComponent() and the roughly 12 basic C data types.
In practice, you often only really have to worry about floating point components, which further reduces the cases down to (usually) 2.
vtkm::cont::UnknownArrayHandle::ExtractComponent() works by returning an vtkm::cont::ArrayHandleStride.
This is a special vtkm::cont::ArrayHandle that can access data buffers by skipping values at regular intervals.
This allows it to access data packed in different ways such as vtkm::cont::ArrayHandleBasic, vtkm::cont::ArrayHandleSOA, and many others.
That said, vtkm::cont::ArrayHandleStride is not magic, so if it cannot directly access memory, some or all of it may be copied.
If you are attempting to use the array from vtkm::cont::UnknownArrayHandle::ExtractComponent() as an output array, pass vtkm::CopyFlag::Off as a second argument.
This will ensure that data are not copied so that any data written will go to the original array (or throw an exception if this cannot be done).
Common Errors
Although vtkm::cont::UnknownArrayHandle::ExtractComponent() will technically work with any vtkm::cont::ArrayHandle (of simple vtkm::Vec types), it may require a very inefficient memory copy.
Pay attention if vtkm::cont::UnknownArrayHandle::ExtractComponent() issues a warning about an inefficient memory copy.
This is likely a serious performance issue, and the data should be retrieved in a different way (or better yet stored in a different way).
3.5.4.3. Extracting All Components
Example 3.43 accesses the first component of each vtkm::Vec in an array.
But in practice you usually want to operate on all components stored in the array.
A simple solution is to iterate over each component.
1 std::vector<vtkm::cont::ArrayHandle<vtkm::FloatDefault>> outputArrays(
2 static_cast<std::size_t>(unknownArray.GetNumberOfComponentsFlat()));
3 for (vtkm::IdComponent componentIndex = 0;
4 componentIndex < unknownArray.GetNumberOfComponentsFlat();
5 ++componentIndex)
6 {
7 invoke(MyWorklet{},
8 unknownArray.ExtractComponent<vtkm::FloatDefault>(componentIndex),
9 outputArrays[static_cast<std::size_t>(componentIndex)]);
10 }
To ensure that the type of the extracted component is a basic C type, the vtkm::Vec values are “flattened.”
That is, they are treated as if they are a single level vtkm::Vec.
For example, if you have a value type of vtkm::Vec<vtkm::Id3, 2>, vtkm::cont::UnknownArrayHandle::ExtractComponent() treats this type as vtkm::Vec<vtkm::Id, 6>.
This allows you to extract the components as type vtkm::Id rather than having a special case for vtkm::Id3.
Although iterating over components works fine, it can be inconvenient.
An alternate mechanism is to use vtkm::cont::UnknownArrayHandle::ExtractArrayFromComponents() to get all the components at once.
vtkm::cont::UnknownArrayHandle::ExtractArrayFromComponents() works like vtkm::cont::UnknownArrayHandle::ExtractComponent() except that instead of returning an vtkm::cont::ArrayHandleStride, it returns a special vtkm::cont::ArrayHandleRecombineVec that behaves like an vtkm::cont::ArrayHandle to reference all component arrays at once.
-
template<typename BaseComponentType>
inline vtkm::cont::ArrayHandleRecombineVec<BaseComponentType> vtkm::cont::UnknownArrayHandle::ExtractArrayFromComponents(vtkm::CopyFlag allowCopy = vtkm::CopyFlag::On) const Extract the array knowing only the component type of the array.
This method returns an
ArrayHandlethat points to the data in the array. This method differs fromAsArrayHandle()because you do not need to know the exactValueTypeandStorageTagof the array. Instead, you only need to know the base component type.ExtractArrayFromComponents()works by calling theExtractComponent()method and then combining them together in a fancyArrayHandle. This allows you to ignore the storage type of the underlying array as well as anyVecstructure 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
Vecs flattened. For example, if the underlying array has aValueTypeofvtkm::Vec<vtkm::Vec<T, 3>, 3>, then this method will treat the data as if it wasvtkm::Vec<T, 9>. There is no way to get an array withvtkm::Vecofvtkm::Vecvalues.Third, because the
Veclength of the values in the returnedArrayHandlemust be determined at runtime, that can break many assumptions of usingvtkm::Vecobjects. The type is not going to be avtkm::Vec<T,N>type but rather an internal class that is intended to behave like that. The type should behave mostly like avtkm::Vec, but will have some differences that can lead to unexpected behavior. For example, thisVec-like object will not have aNUM_COMPONENTSconstant static expression because it is not known at compile time. (Use theGetNumberOfComponents()method instead.) And for the same reason you will not be able to pass these objects to classes overloaded or templated on theVectype. Also, theseVec-like objects cannot be created as new instances. Thus, you will likely have to iterate over all components rather than do operations on the wholeVec.Fourth, because
ExtractArrayFromComponents()usesExtractComponent()to pull data from the array (which in turn usesArrayExtractComponent()), there are someArrayHandletypes 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 optionalallowCopytovtkm::CopyFlag::Off. This will cause an exception to be thrown if the resulting array cannot reference the memory held in thisUnknownArrayHandle.Fifth, component arrays are extracted using
ArrayHandleStrideas 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.
1 invoke(MyWorklet{},
2 unknownArray.ExtractArrayFromComponents<vtkm::FloatDefault>(),
3 outArray);
Common Errors
Although it has the same interface as other vtkm::cont::ArrayHandle’s, vtkm::cont::ArrayHandleRecombineVec has a special value type that breaks some conventions.
For example, when used in a worklet, the value type passed from this array to the worklet cannot be replicated.
That is, you cannot create a temporary stack value of the same type.
Because you still need to specify a base component type, you will likely still need to check several types to safely extract data from an vtkm::cont::UnknownArrayHandle by component.
To do this automatically, you can use the vtkm::cont::UnknownArrayHandle::CastAndCallWithExtractedArray().
This method behaves similarly to vtkm::cont::UncertainArrayHandle::CastAndCall() except that it internally uses vtkm::cont::UnknownArrayHandle::ExtractArrayFromComponents().
-
template<typename Functor, typename ...Args>
inline void vtkm::cont::UnknownArrayHandle::CastAndCallWithExtractedArray(Functor &&functor, Args&&... args) const Call a functor on an array extracted from the components.
CastAndCallWithExtractedArray()behaves similarly toCastAndCallForTypes(). It converts the contained data to anArrayHandleand calls a functor with thatArrayHandle(and any number of optionally specified arguments).The advantage of
CastAndCallWithExtractedArray()is that you do not need to specify anyTypeListorStorageList. Instead, it internally usesExtractArrayFromComponents()to work with mostArrayHandletypes with only about 10 instances of the functor. In contrast, callingCastAndCallForTypes()with, for example,VTKM_DEFAULT_TYPE_LISTandVTKM_DEFAULT_STORAGE_LISTresults in many more instances of the functor but handling many fewer types ofArrayHandle.There are, however, costs to using this method. Details of these costs are documented for the
ExtractArrayFromComponents()method, but briefly they are thatVectypes get flattened, the resulting array has a strangeVec-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.
vtkm::cont::UnknownArrayHandle.1 unknownArray.CastAndCallWithExtractedArray(PrintArrayContentsFunctor{});
3.5.5. Mutability
One subtle feature of vtkm::cont::UnknownArrayHandle is that the class is, in principle, a pointer to an array pointer.
This means that the data in an vtkm::cont::UnknownArrayHandle is always mutable even if the class is declared const.
The upshot is that you can pass output arrays as constant vtkm::cont::UnknownArrayHandle references.
1void IndexInitialize(vtkm::Id size, const vtkm::cont::UnknownArrayHandle& output)
2{
3 vtkm::cont::ArrayHandleIndex input(size);
4 output.DeepCopyFrom(input);
5}
Although it seems strange, there is a good reason to allow an output vtkm::cont::UnknownArrayHandle to be const.
It allows a typed vtkm::cont::ArrayHandle to be used as the argument to the function.
In this case, the compiler will automatically convert the vtkm::cont::ArrayHandle to a vtkm::cont::UnknownArrayHandle.
When C++ creates objects like this, they can only be passed a constant reference, an Rvalue reference, or by value.
So, declaring the output parameter as const vtkm::cont::UnknownArrayHandle allows it to be used for code like this.
1template<typename T>
2void Foo(const vtkm::cont::ArrayHandle<T>& input, vtkm::cont::ArrayHandle<T>& output)
3{
4 IndexInitialize(input.GetNumberOfValues(), output);
5 // ...
Of course, you could also declare the output by value instead of by reference, but this has the same semantics with extra internal pointer management.
Did You Know?
When possible, it is better to pass a vtkm::cont::UnknownArrayHandle as a constant reference (or by value) rather than a mutable reference, even if the array contents are going to be modified.
This allows the function to support automatic conversion of an output vtkm::cont::ArrayHandle.
So if a constant vtkm::cont::UnknownArrayHandle can have its contents modified, what is the difference between a constant reference and a non-constant reference?
The difference is that the constant reference can change the array’s content, but not the array itself.
If you want to do operations like doing a shallow copy or changing the underlying type of the array, a non-constant reference is needed.