Add guide chapter on unknown array handle

This commit is contained in:
Kenneth Moreland 2024-06-27 08:30:06 -04:00
parent cb07d8400c
commit 41a088f6ce
11 changed files with 577 additions and 97 deletions

@ -636,9 +636,7 @@ This is most typically used with C++ run-time type information to convert a run-
.. doxygenfunction:: vtkm::ListForEach(Functor &&f, vtkm::List<Ts...>, Args&&... args)
The following example shows a rudimentary version of converting a dynamically-typed array to a statically-typed array similar to what is done in |VTKm| classes like :class:`vtkm::cont::UnknownArrayHandle` (which is documented in Chapter~\ref{chap:UnknownArrayHandle}).
.. todo:: Fix ``UnknownArrayHandle`` chapter reference above.
The following example shows a rudimentary version of converting a dynamically-typed array to a statically-typed array similar to what is done in |VTKm| classes like :class:`vtkm::cont::UnknownArrayHandle`, which is documented in :chapref:`unknown-array-handle:Unknown Array Handles`.
.. load-example:: ListForEach
:file: GuideExampleLists.cxx

@ -72,9 +72,7 @@ The filter implementation can get the appropriate field to operate on using the
One of the challenges with writing filters is determining the actual types the algorithm is operating on.
The :class:`vtkm::cont::Field` object pulled from the input :class:`vtkm::cont::DataSet` contains a :class:`vtkm::cont::ArrayHandle` (see :chapref:`basic-array-handles:Basic Array Handles`), but you do not know what the template parameters of the :class:`vtkm::cont::ArrayHandle` are.
There are numerous ways to extract an array of an unknown type out of a :class:`vtkm::cont::ArrayHandle` (many of which will be explored later in Chapter \ref{chap:UnknownArrayHandle}), but the :class:`vtkm::filter::Filter` contains some convenience functions to simplify this.
.. todo:: Fix above reference to unknown array handle chapter.
There are numerous ways to extract an array of an unknown type out of a :class:`vtkm::cont::ArrayHandle`, many of which will be explored later in :chapref:`unknown-array-handle:Unknown Array Handles`, but the :class:`vtkm::filter::Filter` contains some convenience functions to simplify this.
In particular, this filter operates specifically on scalar fields.
For this purpose, :class:`vtkm::filter::Filter` provides the :func:`vtkm::filter::Filter::CastAndCallScalarField` helper method.

@ -345,7 +345,7 @@ void TryPrintArrayContents()
////
//// BEGIN-EXAMPLE CastAndCallWithFloatFallback
////
uncertainArray.CastAndCall(PrintArrayContentsFunctor{});
uncertainArray.CastAndCallWithFloatFallback(PrintArrayContentsFunctor{});
////
//// END-EXAMPLE CastAndCallWithFloatFallback
////

@ -88,7 +88,7 @@ That calls a lambda function that invokes a worklet to create the output field.
.. didyouknow::
The filter implemented in :numref:`ex:FilterFieldImpl` is limited to only find the magnitude of :class:`vtkm::Vec`'s with 3 components.
It may be the case you wish to implement a filter that operates on :class:`vtkm::Vec`'s of multiple sizes (or perhaps even any size).
Chapter \ref{chap:UnknownArrayHandle} discusses how you can use the :class:`vtkm::cont::UnknownArrayHandle` contained in the :class:`vtkm::cont::Field` to more expressively decide what types to check for.
:chapref:`unknown-array-handle:Unknown Array Handles` discusses how you can use the :class:`vtkm::cont::UnknownArrayHandle` contained in the :class:`vtkm::cont::Field` to more expressively decide what types to check for.
.. doxygenfunction:: vtkm::filter::Filter::CastAndCallVariableVecField(const vtkm::cont::UnknownArrayHandle&, Functor&&, Args&&...) const
.. doxygenfunction:: vtkm::filter::Filter::CastAndCallVariableVecField(const vtkm::cont::Field&, Functor&&, Args&&...) const

@ -2,6 +2,8 @@
Fancy Array Handles
==============================
.. todo:: Document :class:`vtkm::cont::ArrayHandleMultiplexer`.
.. index::
double: array handle; fancy

@ -83,8 +83,6 @@ Additionally, you can use its constructors or the :func:`vtkm::cont::make_ArrayH
Strided Arrays
--------------------
.. todo:: Should this be moved to the chapter/section on transformed arrays?
.. index::
double: array handle; stride
double: array handle; offset
@ -163,3 +161,14 @@ This is convenient for operations that want to operate on arrays with an unknown
.. load-example:: GetRuntimeVec
:file: GuideExampleArrayHandleRuntimeVec.cxx
:caption: Using :class:`vtkm::cont::ArrayHandleRuntimeVec` to get an array regardless of the size of the contained :class:`vtkm::Vec` values.
---------------------------------------------
Recombined Vec Arrays of Strided Components
---------------------------------------------
|VTKm| contains a special array, :class:`vtkm::cont::ArrayHandleRecombineVec`, to combine component arrays represented in :class:`vtkm::cont::ArrayHandleStride` together to form `Vec` values.
:class:`vtkm::cont::ArrayHandleRecombineVec` is similar to :class:`vtkm::cont::ArrayHandleSOA` (see :secref:`memory-layout:Structure of Arrays`) except that (1) it holds stride arrays for its components instead of basic arrays and that (2) the number of components can be specified at runtime.
:class:`vtkm::cont::ArrayHandleRecombineVec` is mainly provided for the implementation of extracting arrays out of a :class:`vtkm::cont::UnknownArrayHandle` (see :secref:`unknown-array-handle:Extracting All Components`).
.. doxygenclass:: vtkm::cont::ArrayHandleRecombineVec

@ -9,3 +9,4 @@ Developing Algorithms
basic-array-handles.rst
simple-worklets.rst
basic-filter-impl.rst
unknown-array-handle.rst

@ -0,0 +1,457 @@
==============================
Unknown Array Handles
==============================
.. index::
single: unknown array handle
single: array handle; unknown
The :class:`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 :class:`vtkm::cont::UnknownArrayHandle` class provides a mechanism to manage arrays of data with unspecified types.
:class:`vtkm::cont::UnknownArrayHandle` holds a reference to an array.
Unlike :class:`vtkm::cont::ArrayHandle`, :class:`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.
.. doxygenclass:: vtkm::cont::UnknownArrayHandle
.. index:: unknown array handle; construct
An :class:`vtkm::cont::UnknownArrayHandle` can be established by constructing it with or assigning it to an :class:`vtkm::cont::ArrayHandle`.
The following example demonstrates how an :class:`vtkm::cont::UnknownArrayHandle` might be used to load an array whose type is not known until run-time.
.. load-example:: CreateUnknownArrayHandle
:file: GuideExampleUnknownArrayHandle.cxx
:caption: Creating an :class:`vtkm::cont::UnknownArrayHandle`.
It is possible to construct a :class:`vtkm::cont::UnknownArrayHandle` that does not point to any :class:`vtkm::cont::ArrayHandle`.
In this case, the :class:`vtkm::cont::UnknownArrayHandle` is considered not "valid."
Validity can be tested with the :func:`vtkm::cont::UnknownArrayHandle::IsValid` method.
.. doxygenfunction:: vtkm::cont::UnknownArrayHandle::IsValid
Most of the following operations on :class:`vtkm::cont::UnknownArrayHandle` will fail by throwing an exception if it is not valid.
Note that it is also possible for a :class:`vtkm::cont::UnknownArrayHandle` to contain an empty :class:`vtkm::cont::ArrayHandle`.
A :class:`vtkm::cont::UnknownArrayHandle` that contains a :class:`vtkm::cont::ArrayHandle` but has no memory allocated is still considered valid.
Some basic, human-readable information can be retrieved using the :func:`vtkm::cont::UnknownArrayHandle::PrintSummary` method.
It will print the type and size of the array along with some or all of the values.
.. doxygenfunction:: vtkm::cont::UnknownArrayHandle::PrintSummary
------------------------------
Allocation
------------------------------
.. index:: unknown array handle; allocation
Data pointed to by an :class:`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 :func:`vtkm::cont::UnknownArrayHandle::GetNumberOfValues` to retrieve the current size of the array.
It is also possible to call :func:`vtkm::cont::UnknownArrayHandle::Allocate` to change the size of an unknown array.
:class:`vtkm::cont::UnknownArrayHandle`'s :func:`vtkm::cont::UnknownArrayHandle::Allocate` works exactly the same as the :func:`vtkm::cont::ArrayHandle::Allocate` in the basic :class:`vtkm::cont::ArrayHandle`.
.. doxygenfunction:: vtkm::cont::UnknownArrayHandle::GetNumberOfValues
.. doxygenfunction:: vtkm::cont::UnknownArrayHandle::Allocate(vtkm::Id, vtkm::CopyFlag, vtkm::cont::Token&) const
.. doxygenfunction:: vtkm::cont::UnknownArrayHandle::Allocate(vtkm::Id, vtkm::CopyFlag) const
.. load-example:: UnknownArrayHandleResize
:file: GuideExampleUnknownArrayHandle.cxx
:caption: Checking the size of a :class:`vtkm::cont::ArrayHandle` and resizing it.
It is often the case where you have an :class:`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 :func:`vtkm::cont::UnknownArrayHandle::NewInstance` method to create a new array of the same type (without having to determine the type).
.. doxygenfunction:: vtkm::cont::UnknownArrayHandle::NewInstance
.. load-example:: NonTypeUnknownArrayHandleNewInstance
:file: GuideExampleUnknownArrayHandle.cxx
:caption: Creating a new instance of an unknown array handle.
That said, there are many special array handles described in :chapref:`memory-layout:Memory Layout of Array Handles` and :chapref:`fancy-array-handles: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 :func:`vtkm::cont::UnknownArrayHandle::NewInstance` could be infeasible for use as an output.
Thus, :class:`vtkm::cont::UnknownArrayHandle` also contains the :func:`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.
.. doxygenfunction:: vtkm::cont::UnknownArrayHandle::NewInstanceBasic
.. load-example:: UnknownArrayHandleBasicInstance
:file: GuideExampleUnknownArrayHandle.cxx
:caption: Creating a new basic instance of an unknown array handle.
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 :func:`vtkm::cont::UnknownArrayHandle::NewInstanceFloatBasic` to create a new basic :class:`vtkm::cont::ArrayHandle` with the component type changed to :type:`vtkm::FloatDefault`.
For example, if the :class:`vtkm::cont::UnknownArrayHandle` stores an :class:`vtkm::cont::ArrayHandle` of type :type:`vtkm::Id`, :func:`vtkm::cont::UnknownArrayHandle::NewInstanceFloatBasic` will create an :class:`vtkm::cont::ArrayHandle` of type :type:`vtkm::FloatDefault`.
If the :class:`vtkm::cont::UnknownArrayHandle` stores an :class:`vtkm::cont::ArrayHandle` of type :type:`vtkm::Id3`, :func:`vtkm::cont::UnknownArrayHandle::NewInstanceFloatBasic` will create an :class:`vtkm::cont::ArrayHandle` of type :type:`vtkm::Vec3f`.
.. doxygenfunction:: vtkm::cont::UnknownArrayHandle::NewInstanceFloatBasic
.. load-example:: UnknownArrayHandleFloatInstance
:file: GuideExampleUnknownArrayHandle.cxx
:caption: Creating a new array instance with floating point values.
Finally, it may be the case where you are finished using a :class:`vtkm::cont::UnknownArrayHandle`.
If you want to free up memory on the device, which may have limited memory, you can do so with :func:`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 :func:`vtkm::cont::UnknownArrayHandle::ReleaseResources`
.. doxygenfunction:: vtkm::cont::UnknownArrayHandle::ReleaseResourcesExecution
.. doxygenfunction:: vtkm::cont::UnknownArrayHandle::ReleaseResources
------------------------------
Casting to Known Types
------------------------------
.. index::
single: unknown array handle; cast
single: unknown array handle; as array handle
Data pointed to by an :class:`vtkm::cont::UnknownArrayHandle` is not directly
accessible.
To access the data, you need to retrieve the data as an :class:`vtkm::cont::ArrayHandle`.
If you happen to know (or can guess) the type, you can use the :func:`vtkm::cont::UnknownArrayHandle::AsArrayHandle` method to retrieve the array as a specific type.
.. doxygenfunction:: vtkm::cont::UnknownArrayHandle::AsArrayHandle(vtkm::cont::ArrayHandle<T, S>&) const
.. doxygenfunction:: vtkm::cont::UnknownArrayHandle::AsArrayHandle() const
.. load-example:: UnknownArrayHandleAsArrayHandle1
:file: GuideExampleUnknownArrayHandle.cxx
:caption: Retrieving an array of a known type from :class:`vtkm::cont::UnknownArrayHandle`.
:func:`vtkm::cont::UnknownArrayHandle::AsArrayHandle` actually has two forms.
The first form, shown in the previous example, has no arguments and returns the :class:`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 :class:`vtkm::cont::ArrayHandle` as an argument as shown in the following example.
This form can imply the template parameter from the argument.
.. load-example:: UnknownArrayHandleAsArrayHandle2
:file: GuideExampleUnknownArrayHandle.cxx
:caption: Alternate form for retrieving an array of a known type from :class:`vtkm::cont::UnknownArrayHandle`.
:func:`vtkm::cont::UnknownArrayHandle::AsArrayHandle` treats :class:`vtkm::cont::ArrayHandleCast` and :class:`vtkm::cont::ArrayHandleMultiplexer` special.
If the special :class:`vtkm::cont::ArrayHandle` can hold the actual array stored, then :func:`vtkm::cont::UnknownArrayHandle::AsArrayHandle` will return successfully.
In the following example, :func:`vtkm::cont::UnknownArrayHandle::AsArrayHandle` returns an array of type :type:`vtkm::Float32` as an :class:`vtkm::cont::ArrayHandleCast` that converts the values to :type:`vtkm::Float64`.
.. load-example:: UnknownArrayHandleAsCastArray
:file: GuideExampleUnknownArrayHandle.cxx
:caption: Getting a cast array handle from an :class:`vtkm::cont::ArrayHandleCast`.
.. didyouknow::
The inverse retrieval works as well.
If you create an :class:`vtkm::cont::UnknownArrayHandle` with an :class:`vtkm::cont::ArrayHandleCast` or :class:`vtkm::cont::ArrayHandleMultiplexer`, you can get the underlying array with :func:`vtkm::cont::UnknownArrayHandle::AsArrayHandle`.
These relationships also work recursively (e.g. an array placed in a cast array that is placed in a multiplexer).
.. index:: unknown array handle; query type
If the :class:`vtkm::cont::UnknownArrayHandle` cannot store its array in the type given to :func:`vtkm::cont::UnknownArrayHandle::AsArrayHandle`, it will throw an exception.
Thus, you should not use :func:`vtkm::cont::UnknownArrayHandle::AsArrayHandle` with types that you are not sure about.
Use the :func:`vtkm::cont::UnknownArrayHandle::CanConvert` method to determine if a given :class:`vtkm::cont::ArrayHandle` type will work with :func:`vtkm::cont::UnknownArrayHandle::AsArrayHandle`.
.. doxygenfunction:: vtkm::cont::UnknownArrayHandle::CanConvert
.. load-example:: UnknownArrayHandleCanConvert
:file: GuideExampleUnknownArrayHandle.cxx
:caption: Querying whether a given :class:`vtkm::cont::ArrayHandle` can be retrieved from a :class:`vtkm::cont::UnknownArrayHandle`.
By design, :func:`vtkm::cont::UnknownArrayHandle::CanConvert` will return true for types that are not actually stored in the :class:`vtkm::cont::UnknownArrayHandle` but can be retrieved.
If you need to know specifically what type is stored in the :class:`vtkm::cont::UnknownArrayHandle`, you can use the :func:`vtkm::cont::UnknownArrayHandle::IsType` method instead.
.. doxygenfunction:: vtkm::cont::UnknownArrayHandle::IsType
If you need to query either the value type or the storage, you can use :func:`vtkm::cont::UnknownArrayHandle::IsValueType` and :func:`vtkm::cont::UnknownArrayHandle::IsStorageType`, respectively.
:class:`vtkm::cont::UnknownArrayHandle` also provides :func:`vtkm::cont::UnknownArrayHandle::GetValueTypeName`, :func:`vtkm::cont::UnknownArrayHandle::GetStorageTypeName`, and :func:`vtkm::cont::UnknownArrayHandle::GetArrayTypeName` for debugging purposes.
.. doxygenfunction:: vtkm::cont::UnknownArrayHandle::IsValueType
.. doxygenfunction:: vtkm::cont::UnknownArrayHandle::IsStorageType
.. doxygenfunction:: vtkm::cont::UnknownArrayHandle::GetValueTypeName
.. doxygenfunction:: vtkm::cont::UnknownArrayHandle::GetStorageTypeName
.. doxygenfunction:: vtkm::cont::UnknownArrayHandle::GetArrayTypeName
.. commonerrors::
:func:`vtkm::cont::UnknownArrayHandle::CanConvert` is almost always safer to use than :func:`vtkm::cont::UnknownArrayHandle::IsType` or its similar methods.
Even though :func:`vtkm::cont::UnknownArrayHandle::IsType` reflects the actual array type, :func:`vtkm::cont::UnknownArrayHandle::CanConvert` better describes how :class:`vtkm::cont::UnknownArrayHandle` will behave.
If you do not know the exact type of the array contained in an :class:`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 :func:`vtkm::cont::UnknownArrayHandle::DeepCopyFrom` method, which will copy the contents of a target array into an existing array of a (potentially) different type.
.. doxygenfunction:: vtkm::cont::UnknownArrayHandle::DeepCopyFrom(const vtkm::cont::UnknownArrayHandle&)
.. doxygenfunction:: vtkm::cont::UnknownArrayHandle::DeepCopyFrom(const vtkm::cont::UnknownArrayHandle&) const
.. load-example:: UnknownArrayHandleDeepCopy
:file: GuideExampleUnknownArrayHandle.cxx
:caption: Deep copy arrays of unknown types.
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 :func:`vtkm::cont::UnknownArrayHandle::CopyShallowIfPossible` does just that.
.. doxygenfunction:: vtkm::cont::UnknownArrayHandle::CopyShallowIfPossible(const vtkm::cont::UnknownArrayHandle&)
.. doxygenfunction:: vtkm::cont::UnknownArrayHandle::CopyShallowIfPossible(const vtkm::cont::UnknownArrayHandle&) const
.. load-example:: UnknownArrayHandleShallowCopy
:file: GuideExampleUnknownArrayHandle.cxx
:caption: Using :func:`vtkm::cont::UnknownArrayHandle::CopyShallowIfPossible` to get an unknown array as a particular type.
.. didyouknow::
The :class:`vtkm::cont::UnknownArrayHandle` copy methods behave similarly to the :func:`vtkm::cont::ArrayCopy` functions.
----------------------------------------
Casting to a List of Potential Types
----------------------------------------
.. index:: unknown array handle; cast
Using :func:`vtkm::cont::UnknownArrayHandle::AsArrayHandle` is fine as long as the correct types are known, but often times they are not.
For this use case :class:`vtkm::cont::UnknownArrayHandle` has a method named :func:`vtkm::cont::UnknownArrayHandle::CastAndCallForTypes` that attempts to cast the array to some set of types.
The :func:`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 :class:`vtkm::cont::ArrayHandle` of the appropriate type.
You also have to specify two template parameters that specify a :class:`vtkm::List` of value types to try and a :class:`vtkm::List` of storage types to try, respectively.
The macros :c:macro:`VTKM_DEFAULT_TYPE_LIST` and :c:macro:`VTKM_DEFAULT_STORAGE_LIST` are often used when nothing more specific is known.
.. doxygenfunction:: vtkm::cont::UnknownArrayHandle::CastAndCallForTypes
.. load-example:: UsingCastAndCallForTypes
:file: GuideExampleUnknownArrayHandle.cxx
:caption: Operating on an :class:`vtkm::cont::UnknownArrayHandle` with :func:`vtkm::cont::UnknownArrayHandle::CastAndCallForTypes`.
.. didyouknow::
The first (required) argument to :func:`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.
.. didyouknow::
When an :class:`vtkm::cont::UnknownArrayHandle` is used in place of an :class:`vtkm::cont::ArrayHandle` as an argument to a worklet invocation, it will internally use :func:`vtkm::cont::UnknownArrayHandle::CastAndCallForTypes` to attempt to call the worklet with an :class:`vtkm::cont::ArrayHandle` of the correct type.
:class:`vtkm::cont::UnknownArrayHandle` has a simple subclass named :class:`vtkm::cont::UncertainArrayHandle` for use when you can narrow the array to a finite set of types.
:class:`vtkm::cont::UncertainArrayHandle` has two template parameters that must be specified: a :class:`vtkm::List` of value types and a :class:`vtkm::List` of storage types.
.. doxygenclass:: vtkm::cont::UncertainArrayHandle
:class:`vtkm::cont::UncertainArrayHandle` has a method named :func:`vtkm::cont::UncertainArrayHandle::CastAndCall` that behaves the same as :func:`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 :class:`vtkm::cont::UncertainArrayHandle` itself.
.. doxygenfunction:: vtkm::cont::UncertainArrayHandle::CastAndCall
.. load-example:: UncertainArrayHandle
:file: GuideExampleUnknownArrayHandle.cxx
:caption: Using :class:`vtkm::cont::UncertainArrayHandle` to cast and call a functor.
.. didyouknow::
Like with :class:`vtkm::cont::UnknownArrayHandle`, if an :class:`vtkm::cont::UncertainArrayHandle` is used in a worklet invocation, it will internally use :func:`vtkm::cont::UncertainArrayHandle::CastAndCall`.
This provides a convenient way to specify what array types the invoker should try.
Both :class:`vtkm::cont::UnknownArrayHandle` and :class:`vtkm::cont::UncertainArrayHandle` provide a method named :func:`vtkm::cont::UnknownArrayHandle::ResetTypes` to redefine the types to try.
:func:`vtkm::cont::UncertainArrayHandle::ResetTypes` has two template parameters that are the :class:`vtkm::List`'s of value and storage types.
:func:`vtkm::cont::UnknownArrayHandle::ResetTypes` returns a new :class:`vtkm::cont::UncertainArrayHandle` with the given types.
This is a convenient way to pass these types to functions.
.. doxygenfunction:: vtkm::cont::UnknownArrayHandle::ResetTypes
:class:`vtkm::cont::UncertainArrayHandle` additionally has methods named :func:`vtkm::cont::UncertainArrayHandle::ResetValueTypes` and :func:`vtkm::cont::UncertainArrayHandle::ResetStorageTypes` to reset the value types and storage types, respectively, without modifying the other.
.. doxygenfunction:: vtkm::cont::UncertainArrayHandle::ResetValueTypes
.. doxygenfunction:: vtkm::cont::UncertainArrayHandle::ResetStorageTypes
.. load-example:: UnknownArrayResetTypes
:file: GuideExampleUnknownArrayHandle.cxx
:caption: Resetting the types of an :class:`vtkm::cont::UnknownArrayHandle`.
.. commonerrors::
Because it returns an :class:`vtkm::cont::UncertainArrayHandle`, you need to include :file:`vtkm/cont/UncertainArrayHandle.h` if you use :func:`vtkm::cont::UnknownArrayHandle::ResetTypes`.
This is true even if you do not directly use the returned object.
------------------------------
Accessing Truly Unknown Arrays
------------------------------
So far in :secref:`unknown-array-handle:Casting to Known Types` and :secref:`unknown-array-handle:Casting to a List of Potential Types` we explored how to access the data in an :class:`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 :class:`vtkm::cont::UnknownArrayHandle`?
For this case, :class:`vtkm::cont::UnknownArrayHandle` provides mechanisms for extracting data knowing little or nothing about the types.
Cast with Floating Point Fallback
========================================
.. index:: unknown array handle; fallback
The problem with :func:`vtkm::cont::UnknownArrayHandle::CastAndCallForTypes` and :func:`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 :class:`vtkm::cont::UnknownArrayHandle` containing a different :class:`vtkm::cont::ArrayHandle` type, the cast and call will simply fail.
Since the compiler must create a code path for each possible :class:`vtkm::cont::ArrayHandle` type, it may not even be feasible to list all known types.
:func:`vtkm::cont::UnknownArrayHandle::CastAndCallForTypesWithFloatFallback` works around this problem by providing a fallback in case the contained :class:`vtkm::cont::ArrayHandle` does not match any of the types tried.
If none of the types match, then :func:`vtkm::cont::UnknownArrayHandle::CastAndCallForTypesWithFloatFallback` will copy the data to a :class:`vtkm::cont::ArrayHandle` with :type:`vtkm::FloatDefault` values (or some compatible :class:`vtkm::Vec` with :type:`vtkm::FloatDefault` components) and basic storage.
It will then attempt to match again with this copied array.
.. doxygenfunction:: vtkm::cont::UnknownArrayHandle::CastAndCallForTypesWithFloatFallback
.. load-example:: CastAndCallForTypesWithFloatFallback
:file: GuideExampleUnknownArrayHandle.cxx
:caption: Cast and call a functor from an :class:`vtkm::cont::UnknownArrayHandle` with a float fallback.
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 :func:`vtkm::cont::UnknownArrayHandle::CastAndCallForTypesWithFloatFallback`, you still need to include an appropriate type based on :type:`vtkm::FloatDefault` in the value type list and :class:`vtkm::cont::StorageTagBasic` in the storage list so that the copied array can match.
:class:`vtkm::cont::UncertainArrayHandle` has a matching method named :func:`vtkm::cont::UncertainArrayHandle::CastAndCallWithFloatFallback` that does the same operation using the types specified in the :class:`vtkm::cont::UncertainArrayHandle`.
.. doxygenfunction:: vtkm::cont::UncertainArrayHandle::CastAndCallWithFloatFallback
.. load-example:: CastAndCallWithFloatFallback
:file: GuideExampleUnknownArrayHandle.cxx
:caption: Cast and call a functor from an :class:`vtkm::cont::UncertainArrayHandle` with a float fallback.
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 :func:`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, :func:`vtkm::cont::UnknownArrayHandle::CastAndCallForTypesWithFloatFallback` still needs to match the number of components in each array value.
If the contained :class:`vtkm::cont::ArrayHandle` contains values that are :class:`vtkm::Vec`'s of length 2, then the data will be copied to an array of :type:`vtkm::Vec2f`'s.
If :type:`vtkm::Vec2f` is not included in the types to try, the cast and call will still fail.
.. index:: unknown array handle; extract component
A way to get around these problems is to extract a single component from the array.
You can use the :func:`vtkm::cont::UnknownArrayHandle::ExtractComponent` method to return an :class:`vtkm::cont::ArrayHandle` with the values for a given component for each value in the array.
The type of the returned :class:`vtkm::cont::ArrayHandle` will be the same regardless of the actual array type stored in the :class:`vtkm::cont::UnknownArrayHandle`.
.. doxygenfunction:: vtkm::cont::UnknownArrayHandle::ExtractComponent
:func:`vtkm::cont::UnknownArrayHandle::ExtractComponent` must be given a template argument for the base component type.
The following example extracts the first component of all :class:`vtkm::Vec` values in an :class:`vtkm::cont::UnknownArrayHandle` assuming that the component is of type :type:`vtkm::FloatDefault` (:exlineref:`ex:UnknownArrayExtractComponent:Call`).
.. load-example:: UnknownArrayExtractComponent
:file: GuideExampleUnknownArrayHandle.cxx
:caption: Extracting the first component of every value in an :class:`vtkm::cont::UnknownArrayHandle`.
The code in :numref:`ex:UnknownArrayExtractComponent` works with any array with values based on the default floating point type.
If the :class:`vtkm::cont::UnknownArrayHandle` has an array containing :type:`vtkm::FloatDefault`, then the returned array has all the same values.
If the :class:`vtkm::cont::UnknownArrayHandle` contains values of type :type:`vtkm::Vec3f`, then each value in the returned array will be the first component of this array.
If the :class:`vtkm::cont::UnknownArrayHandle` really contains an array with incompatible value types (such as ``vtkm::cont::ArrayHandle<vtkm::Id>``), then an :class:`vtkm::cont::ErrorBadType` will be thrown.
To check if the :class:`vtkm::cont::UnknownArrayHandle` contains an array of a compatible type, use the :func:`vtkm::cont::UnknownArrayHandle::IsBaseComponentType` method to check the component type being used as the template argument to :func:`vtkm::cont::UnknownArrayHandle::ExtractComponent`.
.. doxygenfunction:: vtkm::cont::UnknownArrayHandle::IsBaseComponentType
.. load-example:: UnknownArrayBaseComponentType
:file: GuideExampleUnknownArrayHandle.cxx
:caption: Checking the base component type in an :class:`vtkm::cont::UnknownArrayHandle`.
it is also possible to get a name for the base component type (mostly for debugging purposes) with :func:`vtkm::cont::UnknownArrayHandle::GetBaseComponentTypeName`.
.. doxygenfunction:: vtkm::cont::UnknownArrayHandle::GetBaseComponentTypeName
You will often need to query the number of components that can be extracted from the array.
This can be queried with :func:`vtkm::cont::UnknownArrayHandle::GetNumberOfComponentsFlat`.
.. doxygenfunction:: vtkm::cont::UnknownArrayHandle::GetNumberOfComponentsFlat
This section started with the motivation of getting data from an :class:`vtkm::cont::UnknownArrayHandle` without knowing anything about the type, yet :func:`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 :class:`vtkm::Vec`'s or the size of the :class:`vtkm::Vec`.
A general implementation of an algorithm might have to deal with scalars as well as :class:`vtkm::Vec`'s of size 2, 3, and 4.
If we consider operations on tensors, :class:`vtkm::Vec`'s of size 6 and 9 can be common as well.
But when using :func:`vtkm::cont::UnknownArrayHandle::ExtractComponent`, a single condition can handle any potential :class:`vtkm::Vec` size.
Another advantage of :func:`vtkm::cont::UnknownArrayHandle::ExtractComponent` is that the type of storage does not need to be specified.
:func:`vtkm::cont::UnknownArrayHandle::ExtractComponent` works with any type of :class:`vtkm::cont::ArrayHandle` storage (with some caveats).
So, :numref:`ex:UnknownArrayExtractComponent` works equally as well with :class:`vtkm::cont::ArrayHandleBasic`, :class:`vtkm::cont::ArrayHandleSOA`, :class:`vtkm::cont::ArrayHandleUniformPointCoordinates`, :class:`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 :func:`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.
:func:`vtkm::cont::UnknownArrayHandle::ExtractComponent` works by returning an :class:`vtkm::cont::ArrayHandleStride`.
This is a special :class:`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 :class:`vtkm::cont::ArrayHandleBasic`, :class:`vtkm::cont::ArrayHandleSOA`, and many others.
That said, :class:`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 :func:`vtkm::cont::UnknownArrayHandle::ExtractComponent` as an output array, pass :enumerator:`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).
.. commonerrors::
Although :func:`vtkm::cont::UnknownArrayHandle::ExtractComponent` will technically work with any :class:`vtkm::cont::ArrayHandle` (of simple :class:`vtkm::Vec` types), it may require a very inefficient memory copy.
Pay attention if :func:`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).
Extracting All Components
==============================
:numref:`ex:UnknownArrayExtractComponent` accesses the first component of each :class:`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.
.. load-example:: UnknownArrayExtractComponentsMultiple
:file: GuideExampleUnknownArrayHandle.cxx
:caption: Extracting each component from an :class:`vtkm::cont::UnknownArrayHandle`.
To ensure that the type of the extracted component is a basic C type, the :class:`vtkm::Vec` values are "flattened."
That is, they are treated as if they are a single level :class:`vtkm::Vec`.
For example, if you have a value type of ``vtkm::Vec<vtkm::Id3, 2>``, :func:`vtkm::cont::UnknownArrayHandle::ExtractComponent` treats this type as ``vtkm::Vec<vtkm::Id, 6>``.
This allows you to extract the components as type :type:`vtkm::Id` rather than having a special case for :type:`vtkm::Id3`.
Although iterating over components works fine, it can be inconvenient.
An alternate mechanism is to use :func:`vtkm::cont::UnknownArrayHandle::ExtractArrayFromComponents` to get all the components at once.
:func:`vtkm::cont::UnknownArrayHandle::ExtractArrayFromComponents` works like :func:`vtkm::cont::UnknownArrayHandle::ExtractComponent` except that instead of returning an :class:`vtkm::cont::ArrayHandleStride`, it returns a special :class:`vtkm::cont::ArrayHandleRecombineVec` that behaves like an :class:`vtkm::cont::ArrayHandle` to reference all component arrays at once.
.. doxygenfunction:: vtkm::cont::UnknownArrayHandle::ExtractArrayFromComponents
.. load-example:: UnknownArrayExtractArrayFromComponents
:file: GuideExampleUnknownArrayHandle.cxx
:caption: Extracting all components from an :class:`vtkm::cont::UnknownArrayHandle` at once.
.. commonerrors::
Although it has the same interface as other :class:`vtkm::cont::ArrayHandle`'s, :class:`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 :class:`vtkm::cont::UnknownArrayHandle` by component.
To do this automatically, you can use the :func:`vtkm::cont::UnknownArrayHandle::CastAndCallWithExtractedArray`.
This method behaves similarly to :func:`vtkm::cont::UncertainArrayHandle::CastAndCall` except that it internally uses :func:`vtkm::cont::UnknownArrayHandle::ExtractArrayFromComponents`.
.. doxygenfunction:: vtkm::cont::UnknownArrayHandle::CastAndCallWithExtractedArray
.. load-example:: UnknownArrayCallWithExtractedArray
:file: GuideExampleUnknownArrayHandle.cxx
:caption: Calling a functor for nearly any type of array stored in an :class:`vtkm::cont::UnknownArrayHandle`.
------------------------------
Mutability
------------------------------
.. index:: unknown array handle; const
One subtle feature of :class:`vtkm::cont::UnknownArrayHandle` is that the class is, in principle, a pointer to an array pointer.
This means that the data in an :class:`vtkm::cont::UnknownArrayHandle` is always mutable even if the class is declared ``const``.
The upshot is that you can pass output arrays as constant :class:`vtkm::cont::UnknownArrayHandle` references.
.. load-example:: UnknownArrayConstOutput
:file: GuideExampleUnknownArrayHandle.cxx
:caption: Using a ``const`` :class:`vtkm::cont::UnknownArrayHandle` for a function output.
Although it seems strange, there is a good reason to allow an output :class:`vtkm::cont::UnknownArrayHandle` to be ``const``.
It allows a typed :class:`vtkm::cont::ArrayHandle` to be used as the argument to the function.
In this case, the compiler will automatically convert the :class:`vtkm::cont::ArrayHandle` to a :class:`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`` :class:`vtkm::cont::UnknownArrayHandle` allows it to be used for code like this.
.. load-example:: UseUnknownArrayConstOutput
:file: GuideExampleUnknownArrayHandle.cxx
:caption: Passing an :class:`vtkm::cont::ArrayHandle` as an output :class:`vtkm::cont::UnknownArrayHandle`.
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.
.. didyouknow::
When possible, it is better to pass a :class:`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 :class:`vtkm::cont::ArrayHandle`.
So if a constant :class:`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.

@ -587,19 +587,19 @@ public:
} // namespace internal
/// \brief A grouping of `ArrayHandleStride`s into an `ArrayHandle` of `Vec`s.
/// @brief A grouping of `ArrayHandleStride`s into an `ArrayHandle` of `vtkm::Vec`s.
///
/// The main intention of `ArrayHandleStride` is to pull out a component of an
/// `ArrayHandle` without knowing there `ArrayHandle`'s storage or `Vec` shape.
/// `ArrayHandle` without knowing there `ArrayHandle`'s storage or `vtkm::Vec` shape.
/// However, usually you want to do an operation on all the components together.
/// `ArrayHandleRecombineVec` implements the functionality to easily take a
/// group of extracted components and treat them as a single `ArrayHandle` of
/// `Vec` values.
/// `vtkm::Vec` values.
///
/// Note that caution should be used with `ArrayHandleRecombineVec` because the
/// size of the `Vec` values is not known at compile time. Thus, the value
/// size of the `vtkm::Vec` values is not known at compile time. Thus, the value
/// type of this array is forced to a special `RecombineVec` class that can cause
/// surprises if treated as a `Vec`. In particular, the static `NUM_COMPONENTS`
/// surprises if treated as a `vtkm::Vec`. In particular, the static `NUM_COMPONENTS`
/// expression does not exist. Furthermore, new variables of type `RecombineVec`
/// cannot be created. This means that simple operators like `+` will not work
/// because they require an intermediate object to be created. (Equal operators
@ -618,17 +618,33 @@ public:
(vtkm::cont::ArrayHandle<internal::detail::RecombinedValueType<ComponentType>,
vtkm::cont::internal::StorageTagRecombineVec>));
/// @brief Return the number of components in each value of the array.
///
/// This is also equal to the number of component arrays referenced by this
/// fancy array.
///
/// `ArrayHandleRecombineVec` always stores flat Vec values. As such, this number
/// of components is the same as the number of base components.
vtkm::IdComponent GetNumberOfComponents() const
{
return StorageType::GetNumberOfComponents(this->GetBuffers());
}
/// @brief Get the array storing the values for a particular component.
///
/// The returned array is a `vtkm::cont::ArrayHandleStride`. It is possible
/// that the returned arrays from different components reference the same area
/// of physical memory (usually referencing values interleaved with each other).
vtkm::cont::ArrayHandleStride<ComponentType> GetComponentArray(
vtkm::IdComponent componentIndex) const
{
return StorageType::ArrayForComponent(this->GetBuffers(), componentIndex);
}
/// @brief Add a component array.
///
/// `AppendComponentArray()` provides an easy way to build an `ArrayHandleRecombineVec`
/// by iteratively adding the component arrays.
void AppendComponentArray(
const vtkm::cont::ArrayHandle<ComponentType, vtkm::cont::StorageTagStride>& array)
{

@ -109,10 +109,10 @@ public:
/// \brief 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,
/// `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 new
/// `ArrayHandleBasic` with `FloatDefault` components in its value and attempts to
/// `ArrayHandleBasic` with `vtkm::FloatDefault` components in its value and attempts to
/// cast to those types.
///
template <typename Functor, typename... Args>

@ -397,7 +397,7 @@ inline std::shared_ptr<UnknownAHContainer> MakeUnknownAHContainerFunctor::operat
template <typename ValueTypeList, typename StorageTypeList>
class UncertainArrayHandle;
/// \brief An ArrayHandle of an unknown value type and storage.
/// @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.
@ -408,14 +408,14 @@ class UncertainArrayHandle;
/// types.
///
/// To interface between the runtime polymorphism and the templated algorithms
/// in VTK-m, `UnknownArrayHandle` contains a method named `CastAndCallForTypes`
/// 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`
/// 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
@ -444,7 +444,7 @@ public:
{
}
/// \brief Returns whether an array is stored in this `UnknownArrayHandle`.
/// @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
@ -452,7 +452,7 @@ public:
/// `ArrayHandle`.
VTKM_CONT bool IsValid() const;
/// \brief Create a new array of the same type as this array.
/// @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
@ -460,7 +460,7 @@ public:
///
VTKM_CONT UnknownArrayHandle NewInstance() const;
/// \brief Create a new `ArrayHandleBasic` with the same `ValueType` as this array.
/// @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
@ -469,7 +469,7 @@ public:
///
VTKM_CONT UnknownArrayHandle NewInstanceBasic() const;
/// \brief Create a new `ArrayHandleBasic` with the base component of `FloatDefault`
/// @brief Create a new `ArrayHandleBasic` with the base component of `vtkm::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
@ -487,22 +487,22 @@ public:
///
VTKM_CONT UnknownArrayHandle NewInstanceFloatBasic() const;
/// \brief Returns the name of the value type stored in the array.
/// @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.
/// @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.
/// @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.
/// @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.
@ -525,7 +525,7 @@ public:
return this->IsStorageTypeImpl(typeid(StorageType));
}
/// \brief Returns true if this array's `ValueType` has the provided base component type.
/// @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
@ -542,17 +542,17 @@ public:
return this->IsBaseComponentTypeImpl(detail::UnknownAHComponentInfo::Make<BaseComponentType>());
}
/// \brief Returns true if this array matches the ArrayHandleType template argument.
/// @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`
/// `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`
/// 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`.
/// circumstances, you should prefer `CanConvert()` over `IsType()`.
///
template <typename ArrayHandleType>
VTKM_CONT bool IsType() const
@ -562,7 +562,7 @@ public:
this->IsStorageType<typename ArrayHandleType::StorageTag>());
}
/// \brief Assigns potential value and storage types.
/// @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
@ -575,11 +575,11 @@ public:
NewValueTypeList = NewValueTypeList{},
NewStorageTypeList = NewStorageTypeList{}) const;
/// \brief Returns the number of values in the array.
/// @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.
/// @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.
@ -588,7 +588,7 @@ public:
///
VTKM_CONT vtkm::IdComponent GetNumberOfComponents() const;
/// \brief Returns the total number of components for each value in the array.
/// @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.
@ -606,21 +606,19 @@ public:
///
VTKM_CONT vtkm::IdComponent GetNumberOfComponentsFlat() const;
/// \brief Reallocate the data in the array.
/// @brief Reallocate the data in the array.
///
/// The allocation works the same as the `Allocate` method of `vtkm::cont::ArrayHandle`.
///
/// @{
/// 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;
/// @copydoc Allocate
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.
/// @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 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.
///
@ -651,24 +649,23 @@ private:
}
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.
///
/// Throws a `vtkm::cont::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);
}
/// @copydoc AsArrayHandle
template <typename T>
VTKM_CONT void AsArrayHandle(vtkm::cont::ArrayHandle<T>& array) const;
/// @copydoc AsArrayHandle
template <typename T, typename... Ss>
VTKM_CONT void AsArrayHandle(
vtkm::cont::ArrayHandle<T, vtkm::cont::StorageTagMultiplexer<Ss...>>& array) const;
/// @copydoc AsArrayHandle
template <typename TargetT, typename SourceT, typename SourceS>
VTKM_CONT void AsArrayHandle(
vtkm::cont::ArrayHandle<TargetT, vtkm::cont::StorageTagCast<SourceT, SourceS>>& array) const
@ -677,7 +674,7 @@ public:
array = vtkm::cont::ArrayHandleCast<TargetT, ContainedArrayType>(
this->AsArrayHandle<ContainedArrayType>());
}
/// @copydoc AsArrayHandle
template <typename T>
VTKM_CONT void AsArrayHandle(
vtkm::cont::ArrayHandle<T, vtkm::cont::StorageTagRuntimeVec>& array) const
@ -697,7 +694,7 @@ public:
this->BaseAsArrayHandle(array);
}
}
/// @copydoc AsArrayHandle
template <typename ArrayType>
VTKM_CONT ArrayType AsArrayHandle() const
{
@ -706,12 +703,12 @@ public:
this->AsArrayHandle(array);
return array;
}
///@}
#ifdef VTKM_MSVC
VTKM_DEPRECATED_SUPPRESS_END
#endif
/// \brief Deep copies data from another `UnknownArrayHandle`.
/// @brief Deep copies data from another `UnknownArrayHandle`.
///
/// This method takes an `UnknownArrayHandle` and deep copies data from it.
///
@ -720,60 +717,60 @@ public:
///
void DeepCopyFrom(const vtkm::cont::UnknownArrayHandle& source);
/// \brief Deep copies data from another `UnknownArrayHandle`.
/// @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.
/// 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.
/// @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
/// This method is roughly equivalent to the `vtkm::cont::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
/// having to use a device compiler (whereas `vtkm::cont::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.
/// @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.
/// of `CopyShallowIfPossible()` throws an exception.
///
/// This method is roughly equivalent to the `ArrayCopyShallowIfPossible` function
/// This method is roughly equivalent to the `vtkm::cont::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
/// having to use a device compiler (whereas `vtkm::cont::ArrayCopyShallowIfPossible()` does require
/// a device device compiler).
///
void CopyShallowIfPossible(const vtkm::cont::UnknownArrayHandle& source) const;
/// \brief Extract a component of the array.
/// @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).
/// 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.
/// This method treats each value in the array as a flat `vtkm::Vec` even if it is a
/// `vtkm::Vec` of `Vec`s. For example, if the array actually holds values of type
/// `vtkm::Vec<vtkm::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 point of using `ExtractComponent()` over `AsArrayHandle()` 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 containing `Vec` is in, nor do you need to know the actual storage of the array.
/// the containing `vtkm::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
@ -804,38 +801,39 @@ public:
return ComponentArrayType(buffers);
}
/// \brief Extract the array knowing only the component type of the array.
/// @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
/// 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
/// `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`).
/// 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.
/// array has a `ValueType` of `vtkm::Vec<vtkm::Vec<T, 3>, 3>`, then this method will treat
/// the data as if it was `vtkm::Vec<T, 9>`. There is no way to get an array with `vtkm::Vec`
/// of `vtkm::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
/// determined at runtime, that can break many assumptions of using `vtkm::Vec` objects. The
/// type is not going to be a `vtkm::Vec<T,N>` type but rather an internal class that is intended
/// to behave like that. The type should behave mostly like a `vtkm::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
/// 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
/// 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
@ -858,9 +856,9 @@ public:
return result;
}
/// \brief Call a functor using the underlying array type.
/// @brief Call a functor using the underlying array type.
///
/// `CastAndCallForTypes` attempts to cast the held array to a specific value 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.
///
@ -870,9 +868,9 @@ public:
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.
/// @brief Call a functor using the underlying array type with a float cast fallback.
///
/// `CastAndCallForTypesWithFloatFallback` attempts to cast the held array to a specific
/// `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.
///
@ -880,28 +878,28 @@ public:
/// 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
/// array is copied to a new `ArrayHandleBasic` with `vtkm::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.
/// @brief Call a functor on an array extracted from the components.
///
/// `CastAndCallWithExtractedArray` behaves similarly to `CastAndCallForTypes`.
/// `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
/// 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`
/// `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
/// 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
@ -919,6 +917,7 @@ public:
///
VTKM_CONT void ReleaseResources() const;
/// Prints a summary of the array's type, size, and contents.
VTKM_CONT void PrintSummary(std::ostream& out, bool full = false) const;
};