vtk-m/vtkm/cont/ArrayHandleOffsetsToNumComponents.h
Kenneth Moreland b9430c52e6 Create ArrayHandleOffsetsToNumComponents
This is a fancy array that takes an array of offsets and converts it to
an array of the number of components for each packed entry.

This replaces the use of `ArrayHandleDecorator` in `CellSetExplicit`.
The two implementation should do the same thing, but the new
`ArrayHandleOffsetsToNumComponents` should be less complex for
compilers.
2021-02-17 10:44:47 -07:00

187 lines
6.8 KiB
C++

//============================================================================
// Copyright (c) Kitware, Inc.
// All rights reserved.
// See LICENSE.txt for details.
//
// This software is distributed WITHOUT ANY WARRANTY; without even
// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
// PURPOSE. See the above copyright notice for more information.
//============================================================================
#ifndef vtk_m_cont_ArrayHandleOffsetsToNumComponents_h
#define vtk_m_cont_ArrayHandleOffsetsToNumComponents_h
#include <vtkm/cont/ArrayHandle.h>
namespace vtkm
{
namespace internal
{
// Note that `ArrayPortalOffsetsToNumComponents` requires a source portal with +1 entry
// to avoid branching. See `ArrayHandleOffsetsToNumComponents` for details.
template <typename OffsetsPortal>
class VTKM_ALWAYS_EXPORT ArrayPortalOffsetsToNumComponents
{
OffsetsPortal Portal;
public:
ArrayPortalOffsetsToNumComponents() = default;
ArrayPortalOffsetsToNumComponents(const OffsetsPortal& portal)
: Portal(portal)
{
}
using ValueType = vtkm::IdComponent;
VTKM_EXEC_CONT vtkm::Id GetNumberOfValues() const { return this->Portal.GetNumberOfValues() - 1; }
VTKM_EXEC_CONT vtkm::IdComponent Get(vtkm::Id index) const
{
return static_cast<vtkm::IdComponent>(this->Portal.Get(index + 1) - this->Portal.Get(index));
}
};
}
} // namespace vtkm::internal
namespace vtkm
{
namespace cont
{
template <typename OffsetsStorageTag>
struct VTKM_ALWAYS_EXPORT StorageTagOffsetsToNumComponents
{
};
namespace internal
{
template <typename OffsetsStorageTag>
class VTKM_ALWAYS_EXPORT
Storage<vtkm::IdComponent, vtkm::cont::StorageTagOffsetsToNumComponents<OffsetsStorageTag>>
{
using OffsetsStorage = vtkm::cont::internal::Storage<vtkm::Id, OffsetsStorageTag>;
public:
using ReadPortalType =
vtkm::internal::ArrayPortalOffsetsToNumComponents<typename OffsetsStorage::ReadPortalType>;
// Writing to ArrayHandleOffsetsToNumComponents not really supported, but we need to define this.
using WritePortalType = ReadPortalType;
VTKM_CONT static constexpr vtkm::IdComponent GetNumberOfBuffers()
{
return OffsetsStorage::GetNumberOfBuffers();
}
VTKM_CONT static vtkm::Id GetNumberOfValues(const vtkm::cont::internal::Buffer* buffers)
{
vtkm::Id numOffsets = OffsetsStorage::GetNumberOfValues(buffers);
if (numOffsets < 1)
{
throw vtkm::cont::ErrorBadValue(
"ArrayHandleOffsetsToNumComponents requires an offsets array with at least one value.");
}
return numOffsets - 1;
}
VTKM_CONT static void ResizeBuffers(vtkm::Id numValues,
vtkm::cont::internal::Buffer* buffers,
vtkm::CopyFlag,
vtkm::cont::Token&)
{
if (numValues == GetNumberOfValues(buffers))
{
// In general, we don't allow resizing of the array, but if it was "allocated" to the
// correct size, we will allow that.
}
else
{
throw vtkm::cont::ErrorBadAllocation(
"Cannot allocate/resize ArrayHandleOffsetsToNumComponents.");
}
}
VTKM_CONT static ReadPortalType CreateReadPortal(const vtkm::cont::internal::Buffer* buffers,
vtkm::cont::DeviceAdapterId device,
vtkm::cont::Token& token)
{
VTKM_ASSERT(OffsetsStorage::GetNumberOfValues(buffers) > 0);
return ReadPortalType(OffsetsStorage::CreateReadPortal(buffers, device, token));
}
VTKM_CONT static WritePortalType CreateWritePortal(const vtkm::cont::internal::Buffer*,
vtkm::cont::DeviceAdapterId,
vtkm::cont::Token&)
{
throw vtkm::cont::ErrorBadAllocation("Cannot write to implicit arrays.");
}
};
} // namespace internal
/// \brief An `ArrayHandle` that converts an array of offsets to an array of `Vec` sizes.
///
/// It is common in VTK-m to pack small vectors of variable sizes into a single contiguous
/// array. For example, cells in an explicit cell set can each have a different amount of
/// vertices (triangles = 3, quads = 4, tetra = 4, hexa = 8, etc.). Generally, to access
/// items in this list, you need an array of components in each entry and the offset for
/// each entry. However, if you have just the array of offsets in sorted order, you can
/// easily derive the number of components for each entry by subtracting adjacent entries.
/// This works best if the offsets array has a size that is one more than the number of
/// packed vectors with the first entry set to 0 and the last entry set to the total size
/// of the packed array (the offset to the end).
///
/// `ArrayHandleOffsetsToNumComponents` decorates an array in exactly this manner. It
/// takes an offsets array and makes it behave like an array of counts. Note that the
/// offsets array must conform to the conditions described above: the offsets are in
/// sorted order and there is one additional entry in the offsets (ending in an offset
/// pointing past the end of the array).
///
/// When packing data of this nature, it is common to start with an array that is the
/// number of components. You can convert that to an offsets array using the
/// `vtkm::cont::ConvertNumComponentsToOffsets` function. This will create an offsets array
/// with one extra entry as previously described. You can then throw out the original
/// number of components array and use the offsets with `ArrayHandleOffsetsToNumComponents`
/// to represent both the offsets and num components while storing only one array.
///
template <class OffsetsArray>
class VTKM_ALWAYS_EXPORT ArrayHandleOffsetsToNumComponents
: public vtkm::cont::ArrayHandle<
vtkm::IdComponent,
vtkm::cont::StorageTagOffsetsToNumComponents<typename OffsetsArray::StorageTag>>
{
VTKM_IS_ARRAY_HANDLE(OffsetsArray);
VTKM_STATIC_ASSERT_MSG((std::is_same<typename OffsetsArray::ValueType, vtkm::Id>::value),
"Offsets array must have a value type of vtkm::Id.");
public:
VTKM_ARRAY_HANDLE_SUBCLASS(
ArrayHandleOffsetsToNumComponents,
(ArrayHandleOffsetsToNumComponents<OffsetsArray>),
(vtkm::cont::ArrayHandle<
vtkm::IdComponent,
vtkm::cont::StorageTagOffsetsToNumComponents<typename OffsetsArray::StorageTag>>));
VTKM_CONT ArrayHandleOffsetsToNumComponents(const OffsetsArray& array)
: Superclass(array.GetBuffers())
{
}
};
template <typename OffsetsStorageTag>
VTKM_CONT vtkm::cont::ArrayHandleOffsetsToNumComponents<
vtkm::cont::ArrayHandle<vtkm::Id, OffsetsStorageTag>>
make_ArrayHandleOffsetsToNumComponents(
const vtkm::cont::ArrayHandle<vtkm::Id, OffsetsStorageTag>& array)
{
// Converts to correct type.
return array;
}
}
} // namespace vtkm::cont
#endif //vtk_m_cont_ArrayHandleOffsetsToNumComponents_h