Add UnknownArrayHandle::ExtractArrayFromComponents

This method allows you to extract an `ArrayHandle` from
`UnknownArrayHandle` when you only know the base component type.

Also removed the `Read/WritePortalForBaseComponentType` method
from `UnknownArrayHandle`. This functionality is subsumed by
`ExtractArrayFromComponents`.
This commit is contained in:
Kenneth Moreland 2020-12-23 11:36:15 -07:00
parent 755af739e3
commit 7dd9b4252a
5 changed files with 47 additions and 139 deletions

@ -16,11 +16,10 @@
#include <vtkm/cont/ArrayHandle.h>
#include <vtkm/cont/ArrayHandleCast.h>
#include <vtkm/cont/ArrayHandleMultiplexer.h>
#include <vtkm/cont/ArrayHandleRecombineVec.h>
#include <vtkm/cont/ArrayHandleStride.h>
#include <vtkm/cont/DefaultTypes.h>
#include <vtkm/cont/internal/ArrayPortalFromExtractedComponents.h>
#include <memory>
#include <typeindex>
@ -553,52 +552,56 @@ public:
return ComponentArrayType(buffers);
}
///@{
/// \brief Convenience portal to access all components (in control environment).
/// \brief Extract the array knowing only the component type of the array.
///
/// This method returns a portal that allows you to access all the values in the contained
/// portal by knowing only the type of the base component. The `BaseComponentType` has to
/// be specified and must match the contained array (i.e.the result of `IsBaseComponentType`
/// must succeed for the given type).
/// This method returns an `ArrayHandle` that points to the data in the array. This method
/// differs from `AsArrayHandle` because you do not need to know the exact `ValueType` and
/// `StorageTag` of the array. Instead, you only need to know the base component type.
///
/// Note that the returned portal is not thread safe, but you may safely create multiple portals
/// for multiple threads.
/// `ExtractArrayFromComponents` works by calling the `ExtractComponent` method and then
/// combining them together in a fancy `ArrayHandle`. This allows you to ignore the storage
/// type of the underlying array as well as any `Vec` structure of the value type. However,
/// it also places some limitations on how the data can be pulled from the data.
///
/// First, you have to specify the base component type. This must match the data in the
/// underlying array (as reported by `IsBaseComponentType`).
///
/// Second, the array returned will have the `Vec`s flattened. For example, if the underlying
/// array has a `ValueType` of `Vec<Vec<T, 3>, 3>`, then this method will tread the data as
/// if it was `Vec<T, 9>`. There is no way to get an array with `Vec` of `Vec` values.
///
/// Third, because the `Vec` length of the values in the returned `ArrayHandle` must be
/// determined at runtime, that can break many assumptions of using `Vec` objects. The
/// type is not going to be a `Vec<T,N>` type but rather an internal class that is intended
/// to behave like that. The type should behave mostly like a `Vec`, but will have some
/// differences that can lead to unexpected behavior. For example, this `Vec`-like object
/// will not have a `NUM_COMPONENTS` constant static expression because it is not known
/// at compile time. (Use the `GetNumberOfComponents` method instead.) And for the same
/// reason you will not be able to pass these objects to classes overloaded or templated
/// on the `Vec` type. Also, these `Vec`-like objects cannot be created as new instances.
/// Thus, you will likely have to iterate over all components rather than do operations on
/// the whole `Vec`.
///
/// Fourth, because `ExtractArrayFromComponents` uses `ExtractComponent` to pull data from
/// the array (which in turn uses `ArrayExtractComponent`), there are some `ArrayHandle` types
/// that will require copying data to a new array. This could be problematic in cases where
/// you want to write to the array. To prevent data from being copied, set the optional
/// `allowCopy` to `vtkm::CopyFlag::Off`. This will cause an exception to be thrown if
/// the resulting array cannot reference the memory held in this `UnknownArrayHandle`.
///
template <typename BaseComponentType>
VTKM_CONT vtkm::cont::internal::ArrayPortalFromExtractedComponents<
typename vtkm::cont::ArrayHandleStride<BaseComponentType>::ReadPortalType>
ReadPortalForBaseComponentType() const
VTKM_CONT vtkm::cont::ArrayHandleRecombineVec<BaseComponentType> ExtractArrayFromComponents(
vtkm::CopyFlag allowCopy = vtkm::CopyFlag::On) const
{
vtkm::cont::ArrayHandleRecombineVec<BaseComponentType> result;
vtkm::IdComponent numComponents = this->GetNumberOfComponentsFlat();
vtkm::cont::internal::ArrayPortalFromExtractedComponents<
typename vtkm::cont::ArrayHandleStride<BaseComponentType>::ReadPortalType>
portal(numComponents);
for (vtkm::IdComponent cIndex = 0; cIndex < numComponents; ++cIndex)
{
auto array = this->ExtractComponent<BaseComponentType>(cIndex, vtkm::CopyFlag::On);
portal.AddArray(array, array.ReadPortal());
result.AppendComponentArray(this->ExtractComponent<BaseComponentType>(cIndex, allowCopy));
}
return portal;
return result;
}
template <typename BaseComponentType>
VTKM_CONT vtkm::cont::internal::ArrayPortalFromExtractedComponents<
typename vtkm::cont::ArrayHandleStride<BaseComponentType>::WritePortalType>
WritePortalForBaseComponentType() const
{
vtkm::IdComponent numComponents = this->GetNumberOfComponentsFlat();
vtkm::cont::internal::ArrayPortalFromExtractedComponents<
typename vtkm::cont::ArrayHandleStride<BaseComponentType>::WritePortalType>
portal(numComponents);
for (vtkm::IdComponent cIndex = 0; cIndex < numComponents; ++cIndex)
{
auto array = this->ExtractComponent<BaseComponentType>(cIndex, vtkm::CopyFlag::Off);
portal.AddArray(array, array.WritePortal());
}
return portal;
}
///@}
/// \brief Call a functor using the underlying array type.
///
/// `CastAndCall` attempts to cast the held array to a specific value type,

@ -1,96 +0,0 @@
//============================================================================
// Copyright (c) Kitware, Inc.
// All rights reserved.
// See LICENSE.txt for details.
//
// This software is distributed WITHOUT ANY WARRANTY; without even
// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
// PURPOSE. See the above copyright notice for more information.
//============================================================================
#ifndef vtk_m_cont_internal_ArrayPortalFromExtractedComponents_h
#define vtk_m_cont_internal_ArrayPortalFromExtractedComponents_h
#include <vtkm/cont/ArrayHandleStride.h>
#include <vtkm/internal/ArrayPortalHelpers.h>
#include <vtkm/Types.h>
#include <vtkm/VecTraits.h>
#include <vector>
namespace vtkm
{
namespace cont
{
class UnknownArrayHandle;
namespace internal
{
/// `ArrayPortalFromExtractedComponents` is a convenience class that allows you to treat
/// a group of arrays that were extracted from the components of an array and treat them
/// like a portal to the array itself. It is used internally by `UnknownArrayHandle` to
/// get read and write portals to the array
///
/// Note that this portal only works on the control environment.
///
template <typename PortalType>
class ArrayPortalFromExtractedComponents
{
private:
using T = typename PortalType::ValueType;
std::vector<vtkm::cont::ArrayHandleStride<T>> Arrays;
std::vector<PortalType> Portals;
mutable std::vector<T> Values;
friend UnknownArrayHandle;
void AddArray(const vtkm::cont::ArrayHandleStride<T>& array, const PortalType& portal)
{
this->Arrays.push_back(array);
this->Portals.push_back(portal);
}
public:
using ValueType = vtkm::VecCConst<T>;
ArrayPortalFromExtractedComponents(vtkm::IdComponent expectedArrays = 0)
{
this->Arrays.reserve(static_cast<std::size_t>(expectedArrays));
this->Portals.reserve(static_cast<std::size_t>(expectedArrays));
}
VTKM_CONT vtkm::Id GetNumberOfValues() const { return this->Portals[0].GetNumberOfValues(); }
VTKM_CONT ValueType Get(vtkm::Id index) const
{
// Note: this is not thread-safe
this->Values.clear();
for (auto&& portal : this->Portals)
{
this->Values.push_back(portal.Get(index));
}
return ValueType(this->Values.data(), static_cast<vtkm::IdComponent>(this->Values.size()));
}
template <typename VecType,
typename Writable = vtkm::internal::PortalSupportsSets<PortalType>,
typename = typename std::enable_if<Writable::value>::type>
VTKM_CONT void Set(vtkm::Id index, const VecType& value) const
{
using Traits = vtkm::VecTraits<VecType>;
for (vtkm::IdComponent cIndex = 0; cIndex < Traits::GetNumberOfComponents(value); ++cIndex)
{
this->Portals[static_cast<std::size_t>(cIndex)].Set(index,
Traits::GetComponent(value, index));
}
}
};
}
}
} // namespace vtkm::cont::internal
#endif //vtk_m_cont_internal_ArrayPortalFromExtractedComponents_h

@ -10,7 +10,6 @@
set(headers
ArrayHandleExecutionManager.h
ArrayPortalFromExtractedComponents.h
ArrayPortalFromIterators.h
ArrayTransfer.h
AtomicInterfaceControl.h

@ -443,14 +443,15 @@ void TryExtractComponent()
VTKM_TEST_ASSERT(unknownArray.GetNumberOfComponentsFlat() == FlatVec::NUM_COMPONENTS);
auto componentPortal = unknownArray.ReadPortalForBaseComponentType<ComponentType>();
auto originalPortal = originalArray.ReadPortal();
auto extractedArray = unknownArray.ExtractArrayFromComponents<ComponentType>();
VTKM_TEST_ASSERT(extractedArray.GetNumberOfComponents() == FlatVec::NUM_COMPONENTS);
auto extractedPortal = extractedArray.ReadPortal();
for (vtkm::Id valueIndex = 0; valueIndex < ARRAY_SIZE; ++valueIndex)
{
FlatVec originalData = originalPortal.Get(valueIndex);
auto componentData = componentPortal.Get(valueIndex);
VTKM_TEST_ASSERT(test_equal(originalData, componentData));
auto extractedData = extractedPortal.Get(valueIndex);
VTKM_TEST_ASSERT(test_equal(originalData, extractedData));
}
}

@ -86,7 +86,8 @@ struct OutputArrayDataFunctor
template <typename T>
VTKM_CONT void operator()(T, const vtkm::cont::UnknownArrayHandle& array, std::ostream& out) const
{
auto portal = array.ReadPortalForBaseComponentType<T>();
auto componentArray = array.ExtractArrayFromComponents<T>();
auto portal = componentArray.ReadPortal();
vtkm::Id numValues = portal.GetNumberOfValues();
for (vtkm::Id valueIndex = 0; valueIndex < numValues; ++valueIndex)