The driving desire for this change was to make vtk-m ArrayHandle behave more
like the standard vector. The canonical example of what we want to support is:
```
std::vector<vtkm::Id> values;
values.resize(100);
vtkm::cont::ArrayHandle<vtkm::Id> array = vtkm::cont::make_ArrayHandle(values);
vtkm::cont::DeviceAdapterAlgorithm<DeviceAdapter>::Sort(array);
```
And with-out the ability to modify user provided memory, this was impossible.
The UserPortal in ArrayHandle was used to copy a pointer the user
created into an ArrayHandle to use in VTK-m algorithms. However, this is
only really valid for a basic storage, so the functionality has been
moved there, and you have to construct an ArrayHandle with a storage
instead of an array portal.
Add an Allocate method in ArrayHandle that basically forwards the
alllocate request to the storage object. This allows some measure of
control of the array from the control side. You can allocate the array
and set values (by getting the control array portal) if you so desire.
Fixed a problem where ArrayHandle would cause a crash if you tried to
get the control portal on an uninitialized array (it was supposed to
throw an exception).
Also changed some methods in ArrayHandle so that they work resonably
without error when used with an uninitialized array. Specifically, the
aforementioned behavior was changed to "allocate" an array of size 0
(that is, call Allocate(0) on the storage object) to return an empty
array portal rather than throw an error. Although this use of
ArrayHandle can be considered erroneous, it is convenient the get an
empty array portal when dealing with a potentially unallocated array
rather than create a special condition.
Lots of tests have to move values in and out of arrays and check them
against expected values. It is also often the case that these tests are
run on lots of different types. There is some repeated code for
generating known values for particular indices. This change unifies some
of that. This can probably also encourage making more generic tests.
Providing these types tends to "lock in" the precision of the algorithms
used in VTK-m. Since we are using templating anyway, our templates
should be generic enough to handle difference precision in the data.
Usually the appropriate type can be determined by the data provided. In
the case where there is no hint on the precision of data to use (for
example, in the code that provides coordinates for uniform data), there
is a vtkm::FloatDefault.
MSVC likes to warn about using raw pointers as iterators in generic
algorithms because they have been known to lead to problems. When
compiling with that compiler, wrap raw pointers in
stdext::checked_array_pointer to suppress the error and also add a bit
more checking.
After a talk with Robert Maynard, we decided to change the name
ArrayContainerControl to Storage. There are several reasons for this
change.
1. The name ArrayContainerControl is unwieldy. It is long, hard for
humans to parse, and makes for long lines and wraparound. It is also
hard to distinguish from other names like ArrayHandleFoo and
ArrayExecutionManager.
2. The word container is getting overloaded. For example, there is a
SimplePolymorphicContainer. Container is being used for an object that
literally acts like a container for data. This class really manages
data.
3. The data does not necessarily have to be on the control side.
Implicit containers store the data nowhere. Derivative containers might
have all the real data on the execution side. It is possible in the
future to have storage on the execution environment instead of the
control (think interfacing with a simulator on the GPU).
Storage is not a perfect word (what does implicit storage really mean?),
but its the best English word we came up with.