Fix fast paths for ArrayRangeCompute

The precompiled `ArrayRangeCompute` function was not following proper fast
paths for special arrays. For example, when computing the range of an
`ArrayHandleUniformPointCoordinates`, the ranges should be taken from the
origin and spacing of the special array. However, the precompiled version
was calling the generic range computation, which was doing an unnecessary
reduction over the entire array. These fast paths have been fixed.

These mistakes in the code were caused by quirks in how templated method
overloading works. To prevent this mistake from happening again in the
precompiled `ArrayRangeCompute` function and elsewhere, all templated forms
of `ArrayRangeCompute` have been deprecated. Most will call
`ArrayRangeCompute` with no issues. For those that need the templated
version, `ArrayRangeComputeTemplate` replaces the old templated
`ArrayRangeCompute`. There is exactly one templated declaration of
`ArrayRangeComputeTemplate` that uses a class, `ArrayRangeComputeImpl`,
with partial specialization to ensure the correct form is used.
This commit is contained in:
Kenneth Moreland 2023-03-06 12:35:38 -07:00
parent 4b19139f3d
commit 58fc99c2f8
13 changed files with 305 additions and 290 deletions

@ -0,0 +1,18 @@
# Fast paths for `ArrayRangeCompute` fixed
The precompiled `ArrayRangeCompute` function was not following proper fast
paths for special arrays. For example, when computing the range of an
`ArrayHandleUniformPointCoordinates`, the ranges should be taken from the
origin and spacing of the special array. However, the precompiled version
was calling the generic range computation, which was doing an unnecessary
reduction over the entire array. These fast paths have been fixed.
These mistakes in the code were caused by quirks in how templated method
overloading works. To prevent this mistake from happening again in the
precompiled `ArrayRangeCompute` function and elsewhere, all templated forms
of `ArrayRangeCompute` have been deprecated. Most will call
`ArrayRangeCompute` with no issues. For those that need the templated
version, `ArrayRangeComputeTemplate` replaces the old templated
`ArrayRangeCompute`. There is exactly one templated declaration of
`ArrayRangeComputeTemplate` that uses a class, `ArrayRangeComputeImpl`,
with partial specialization to ensure the correct form is used.

@ -11,6 +11,8 @@
#define vtk_m_cont_ArrayHandleCartesianProduct_h
#include <vtkm/Assert.h>
#include <vtkm/Range.h>
#include <vtkm/VecTraits.h>
#include <vtkm/cont/ArrayExtractComponent.h>
#include <vtkm/cont/ArrayHandle.h>
@ -486,6 +488,77 @@ struct ArrayExtractComponentImpl<vtkm::cont::StorageTagCartesianProduct<STs...>>
}
};
template <typename S>
struct ArrayRangeComputeImpl;
template <typename ST1, typename ST2, typename ST3>
struct VTKM_CONT_EXPORT ArrayRangeComputeImpl<vtkm::cont::StorageTagCartesianProduct<ST1, ST2, ST3>>
{
template <typename T>
VTKM_CONT vtkm::cont::ArrayHandle<vtkm::Range> operator()(
const vtkm::cont::ArrayHandle<vtkm::Vec<T, 3>,
vtkm::cont::StorageTagCartesianProduct<ST1, ST2, ST3>>& input_,
vtkm::cont::DeviceAdapterId device) const
{
vtkm::cont::ArrayHandle<vtkm::Range> result;
result.Allocate(3);
auto resultPortal = result.WritePortal();
const vtkm::cont::ArrayHandleCartesianProduct<vtkm::cont::ArrayHandle<T, ST1>,
vtkm::cont::ArrayHandle<T, ST2>,
vtkm::cont::ArrayHandle<T, ST3>>& input = input_;
vtkm::cont::ArrayHandle<vtkm::Range> componentRangeArray;
vtkm::IdComponent index = 0;
vtkm::cont::ArrayHandle<T, ST1> firstArray = input.GetFirstArray();
componentRangeArray = vtkm::cont::internal::ArrayRangeComputeImpl<ST1>{}(firstArray, device);
vtkm::Id numSubComponents = componentRangeArray.GetNumberOfValues();
if (numSubComponents > 1)
{
result.Allocate(result.GetNumberOfValues() + numSubComponents - 1, vtkm::CopyFlag::On);
resultPortal = result.WritePortal();
}
auto componentRangePortal = componentRangeArray.ReadPortal();
for (vtkm::IdComponent subComponent = 0; subComponent < numSubComponents; ++subComponent)
{
resultPortal.Set(index, componentRangePortal.Get(subComponent));
++index;
}
vtkm::cont::ArrayHandle<T, ST2> secondArray = input.GetSecondArray();
componentRangeArray = vtkm::cont::internal::ArrayRangeComputeImpl<ST2>{}(secondArray, device);
numSubComponents = componentRangeArray.GetNumberOfValues();
if (numSubComponents > 1)
{
result.Allocate(result.GetNumberOfValues() + numSubComponents - 1, vtkm::CopyFlag::On);
resultPortal = result.WritePortal();
}
componentRangePortal = componentRangeArray.ReadPortal();
for (vtkm::IdComponent subComponent = 0; subComponent < numSubComponents; ++subComponent)
{
resultPortal.Set(index, componentRangePortal.Get(subComponent));
++index;
}
vtkm::cont::ArrayHandle<T, ST3> thirdArray = input.GetThirdArray();
componentRangeArray = vtkm::cont::internal::ArrayRangeComputeImpl<ST3>{}(thirdArray, device);
numSubComponents = componentRangeArray.GetNumberOfValues();
if (numSubComponents > 1)
{
result.Allocate(result.GetNumberOfValues() + numSubComponents - 1, vtkm::CopyFlag::On);
resultPortal = result.WritePortal();
}
componentRangePortal = componentRangeArray.ReadPortal();
for (vtkm::IdComponent subComponent = 0; subComponent < numSubComponents; ++subComponent)
{
resultPortal.Set(index, componentRangePortal.Get(subComponent));
++index;
}
return result;
}
};
} // namespace internal
}

@ -12,6 +12,9 @@
#include <vtkm/cont/ArrayHandleImplicit.h>
#include <vtkm/Range.h>
#include <vtkm/VecFlat.h>
namespace vtkm
{
namespace cont
@ -90,6 +93,36 @@ vtkm::cont::ArrayHandleConstant<T> make_ArrayHandleConstant(T value, vtkm::Id nu
{
return vtkm::cont::ArrayHandleConstant<T>(value, numberOfValues);
}
namespace internal
{
template <typename S>
struct ArrayRangeComputeImpl;
template <>
struct VTKM_CONT_EXPORT ArrayRangeComputeImpl<vtkm::cont::StorageTagConstant>
{
template <typename T>
VTKM_CONT vtkm::cont::ArrayHandle<vtkm::Range> operator()(
const vtkm::cont::ArrayHandle<T, vtkm::cont::StorageTagConstant>& input,
vtkm::cont::DeviceAdapterId) const
{
auto value = vtkm::make_VecFlat(input.ReadPortal().Get(0));
vtkm::cont::ArrayHandle<vtkm::Range> result;
result.Allocate(value.GetNumberOfComponents());
auto resultPortal = result.WritePortal();
for (vtkm::IdComponent index = 0; index < value.GetNumberOfComponents(); ++index)
{
resultPortal.Set(index, vtkm::Range{ value[index], value[index] });
}
return result;
}
};
} // namespace internal
}
} // vtkm::cont

@ -12,6 +12,7 @@
#include <vtkm/cont/ArrayHandleImplicit.h>
#include <vtkm/Range.h>
#include <vtkm/TypeTraits.h>
#include <vtkm/VecTraits.h>
@ -152,6 +153,52 @@ make_ArrayHandleCounting(CountingValueType start, CountingValueType step, vtkm::
{
return vtkm::cont::ArrayHandleCounting<CountingValueType>(start, step, length);
}
namespace internal
{
template <typename S>
struct ArrayRangeComputeImpl;
template <>
struct VTKM_CONT_EXPORT ArrayRangeComputeImpl<vtkm::cont::StorageTagCounting>
{
template <typename T>
VTKM_CONT vtkm::cont::ArrayHandle<vtkm::Range> operator()(
const vtkm::cont::ArrayHandle<T, vtkm::cont::StorageTagCounting>& input,
vtkm::cont::DeviceAdapterId) const
{
using Traits = vtkm::VecTraits<T>;
vtkm::cont::ArrayHandle<vtkm::Range> result;
result.Allocate(Traits::NUM_COMPONENTS);
auto portal = result.WritePortal();
if (portal.GetNumberOfValues() > 0)
{
T first = input.ReadPortal().Get(0);
T last = input.ReadPortal().Get(input.GetNumberOfValues() - 1);
for (vtkm::IdComponent cIndex = 0; cIndex < Traits::NUM_COMPONENTS; ++cIndex)
{
auto firstComponent = Traits::GetComponent(first, cIndex);
auto lastComponent = Traits::GetComponent(last, cIndex);
portal.Set(cIndex,
vtkm::Range(vtkm::Min(firstComponent, lastComponent),
vtkm::Max(firstComponent, lastComponent)));
}
}
else
{
// Array is empty
for (vtkm::IdComponent cIndex = 0; cIndex < Traits::NUM_COMPONENTS; ++cIndex)
{
portal.Set(cIndex, vtkm::Range{});
}
}
return result;
}
};
} // namespace internal
}
} // namespace vtkm::cont

@ -10,6 +10,7 @@
#ifndef vtk_m_cont_ArrayHandleIndex_h
#define vtk_m_cont_ArrayHandleIndex_h
#include <vtkm/Range.h>
#include <vtkm/cont/ArrayHandleImplicit.h>
namespace vtkm
@ -71,6 +72,29 @@ VTKM_CONT inline vtkm::cont::ArrayHandleIndex make_ArrayHandleIndex(vtkm::Id len
{
return vtkm::cont::ArrayHandleIndex(length);
}
namespace internal
{
template <typename S>
struct ArrayRangeComputeImpl;
template <>
struct VTKM_CONT_EXPORT ArrayRangeComputeImpl<vtkm::cont::StorageTagIndex>
{
VTKM_CONT vtkm::cont::ArrayHandle<vtkm::Range> operator()(
const vtkm::cont::ArrayHandle<vtkm::Id, vtkm::cont::StorageTagIndex>& input,
vtkm::cont::DeviceAdapterId) const
{
vtkm::cont::ArrayHandle<vtkm::Range> result;
result.Allocate(1);
result.WritePortal().Set(0, vtkm::Range(0, input.GetNumberOfValues() - 1));
return result;
}
};
} // namespace internal
}
} // namespace vtkm::cont

@ -86,6 +86,28 @@ ArrayExtractComponentImpl<vtkm::cont::StorageTagUniformPoints>::operator()(
}
}
VTKM_CONT vtkm::cont::ArrayHandle<vtkm::Range>
ArrayRangeComputeImpl<vtkm::cont::StorageTagUniformPoints>::operator()(
const vtkm::cont::ArrayHandleUniformPointCoordinates& input,
vtkm::cont::DeviceAdapterId vtkmNotUsed(device)) const
{
vtkm::internal::ArrayPortalUniformPointCoordinates portal = input.ReadPortal();
// In this portal we know that the min value is the first entry and the
// max value is the last entry.
vtkm::Vec3f minimum = portal.Get(0);
vtkm::Vec3f maximum = portal.Get(portal.GetNumberOfValues() - 1);
vtkm::cont::ArrayHandle<vtkm::Range> rangeArray;
rangeArray.Allocate(3);
vtkm::cont::ArrayHandle<vtkm::Range>::WritePortalType outPortal = rangeArray.WritePortal();
outPortal.Set(0, vtkm::Range(minimum[0], maximum[0]));
outPortal.Set(1, vtkm::Range(minimum[1], maximum[1]));
outPortal.Set(2, vtkm::Range(minimum[2], maximum[2]));
return rangeArray;
}
} // namespace internal
}

@ -10,6 +10,7 @@
#ifndef vtk_m_cont_ArrayHandleUniformPointCoordinates_h
#define vtk_m_cont_ArrayHandleUniformPointCoordinates_h
#include <vtkm/Range.h>
#include <vtkm/cont/ArrayExtractComponent.h>
#include <vtkm/cont/ArrayHandleImplicit.h>
#include <vtkm/internal/ArrayPortalUniformPointCoordinates.h>
@ -83,6 +84,17 @@ struct VTKM_CONT_EXPORT ArrayExtractComponentImpl<vtkm::cont::StorageTagUniformP
vtkm::CopyFlag allowCopy) const;
};
template <typename S>
struct ArrayRangeComputeImpl;
template <>
struct VTKM_CONT_EXPORT ArrayRangeComputeImpl<vtkm::cont::StorageTagUniformPoints>
{
VTKM_CONT vtkm::cont::ArrayHandle<vtkm::Range> operator()(
const vtkm::cont::ArrayHandleUniformPointCoordinates& input,
vtkm::cont::DeviceAdapterId device) const;
};
} // namespace internal
}

@ -12,118 +12,16 @@
#include <vtkm/TypeList.h>
namespace vtkm
{
namespace cont
{
void ThrowArrayRangeComputeFailed()
{
throw vtkm::cont::ErrorExecution("Failed to run ArrayRangeComputation on any device.");
}
#define VTKM_ARRAY_RANGE_COMPUTE_IMPL_T(T, Storage) \
VTKM_CONT \
vtkm::cont::ArrayHandle<vtkm::Range> ArrayRangeCompute( \
const vtkm::cont::ArrayHandle<T, Storage>& input, vtkm::cont::DeviceAdapterId device) \
{ \
return detail::ArrayRangeComputeImpl(input, device); \
} \
struct SwallowSemicolon
#define VTKM_ARRAY_RANGE_COMPUTE_IMPL_VEC(T, N, Storage) \
VTKM_CONT \
vtkm::cont::ArrayHandle<vtkm::Range> ArrayRangeCompute( \
const vtkm::cont::ArrayHandle<vtkm::Vec<T, N>, Storage>& input, \
vtkm::cont::DeviceAdapterId device) \
{ \
return detail::ArrayRangeComputeImpl(input, device); \
} \
struct SwallowSemicolon
#define VTKM_ARRAY_RANGE_COMPUTE_IMPL_ALL_SCALAR_T(Storage) \
VTKM_ARRAY_RANGE_COMPUTE_IMPL_T(vtkm::Int8, Storage); \
VTKM_ARRAY_RANGE_COMPUTE_IMPL_T(vtkm::UInt8, Storage); \
VTKM_ARRAY_RANGE_COMPUTE_IMPL_T(vtkm::Int16, Storage); \
VTKM_ARRAY_RANGE_COMPUTE_IMPL_T(vtkm::UInt16, Storage); \
VTKM_ARRAY_RANGE_COMPUTE_IMPL_T(vtkm::Int32, Storage); \
VTKM_ARRAY_RANGE_COMPUTE_IMPL_T(vtkm::UInt32, Storage); \
VTKM_ARRAY_RANGE_COMPUTE_IMPL_T(vtkm::Int64, Storage); \
VTKM_ARRAY_RANGE_COMPUTE_IMPL_T(vtkm::UInt64, Storage); \
VTKM_ARRAY_RANGE_COMPUTE_IMPL_T(vtkm::Float32, Storage); \
VTKM_ARRAY_RANGE_COMPUTE_IMPL_T(vtkm::Float64, Storage); \
VTKM_ARRAY_RANGE_COMPUTE_IMPL_T(char, Storage); \
VTKM_ARRAY_RANGE_COMPUTE_IMPL_T(signed VTKM_UNUSED_INT_TYPE, Storage); \
VTKM_ARRAY_RANGE_COMPUTE_IMPL_T(unsigned VTKM_UNUSED_INT_TYPE, Storage)
#define VTKM_ARRAY_RANGE_COMPUTE_IMPL_ALL_VEC(N, Storage) \
VTKM_ARRAY_RANGE_COMPUTE_IMPL_VEC(vtkm::Int8, N, Storage); \
VTKM_ARRAY_RANGE_COMPUTE_IMPL_VEC(vtkm::UInt8, N, Storage); \
VTKM_ARRAY_RANGE_COMPUTE_IMPL_VEC(vtkm::Int16, N, Storage); \
VTKM_ARRAY_RANGE_COMPUTE_IMPL_VEC(vtkm::UInt16, N, Storage); \
VTKM_ARRAY_RANGE_COMPUTE_IMPL_VEC(vtkm::Int32, N, Storage); \
VTKM_ARRAY_RANGE_COMPUTE_IMPL_VEC(vtkm::UInt32, N, Storage); \
VTKM_ARRAY_RANGE_COMPUTE_IMPL_VEC(vtkm::Int64, N, Storage); \
VTKM_ARRAY_RANGE_COMPUTE_IMPL_VEC(vtkm::UInt64, N, Storage); \
VTKM_ARRAY_RANGE_COMPUTE_IMPL_VEC(vtkm::Float32, N, Storage); \
VTKM_ARRAY_RANGE_COMPUTE_IMPL_VEC(vtkm::Float64, N, Storage); \
VTKM_ARRAY_RANGE_COMPUTE_IMPL_VEC(char, N, Storage); \
VTKM_ARRAY_RANGE_COMPUTE_IMPL_VEC(signed VTKM_UNUSED_INT_TYPE, N, Storage); \
VTKM_ARRAY_RANGE_COMPUTE_IMPL_VEC(unsigned VTKM_UNUSED_INT_TYPE, N, Storage)
VTKM_ARRAY_RANGE_COMPUTE_IMPL_ALL_SCALAR_T(vtkm::cont::StorageTagBasic);
VTKM_ARRAY_RANGE_COMPUTE_IMPL_ALL_VEC(2, vtkm::cont::StorageTagBasic);
VTKM_ARRAY_RANGE_COMPUTE_IMPL_ALL_VEC(3, vtkm::cont::StorageTagBasic);
VTKM_ARRAY_RANGE_COMPUTE_IMPL_ALL_VEC(4, vtkm::cont::StorageTagBasic);
VTKM_ARRAY_RANGE_COMPUTE_IMPL_ALL_VEC(2, vtkm::cont::StorageTagSOA);
VTKM_ARRAY_RANGE_COMPUTE_IMPL_ALL_VEC(3, vtkm::cont::StorageTagSOA);
VTKM_ARRAY_RANGE_COMPUTE_IMPL_ALL_VEC(4, vtkm::cont::StorageTagSOA);
VTKM_ARRAY_RANGE_COMPUTE_IMPL_ALL_SCALAR_T(vtkm::cont::StorageTagStride);
VTKM_ARRAY_RANGE_COMPUTE_IMPL_VEC(vtkm::Float32, 3, vtkm::cont::StorageTagXGCCoordinates);
VTKM_ARRAY_RANGE_COMPUTE_IMPL_VEC(vtkm::Float64, 3, vtkm::cont::StorageTagXGCCoordinates);
#undef VTKM_ARRAY_RANGE_COMPUTE_IMPL_T
#undef VTKM_ARRAY_RANGE_COMPUTE_IMPL_VEC
#undef VTKM_ARRAY_RANGE_COMPUTE_IMPL_ALL_SCALAR_T
#undef VTKM_ARRAY_RANGE_COMPUTE_IMPL_ALL_VEC
// Special implementation for regular point coordinates, which are easy
// to determine.
VTKM_CONT
vtkm::cont::ArrayHandle<vtkm::Range> ArrayRangeCompute(
const vtkm::cont::ArrayHandle<vtkm::Vec3f,
vtkm::cont::ArrayHandleUniformPointCoordinates::StorageTag>& array,
vtkm::cont::DeviceAdapterId)
{
vtkm::internal::ArrayPortalUniformPointCoordinates portal = array.ReadPortal();
// In this portal we know that the min value is the first entry and the
// max value is the last entry.
vtkm::Vec3f minimum = portal.Get(0);
vtkm::Vec3f maximum = portal.Get(portal.GetNumberOfValues() - 1);
vtkm::cont::ArrayHandle<vtkm::Range> rangeArray;
rangeArray.Allocate(3);
vtkm::cont::ArrayHandle<vtkm::Range>::WritePortalType outPortal = rangeArray.WritePortal();
outPortal.Set(0, vtkm::Range(minimum[0], maximum[0]));
outPortal.Set(1, vtkm::Range(minimum[1], maximum[1]));
outPortal.Set(2, vtkm::Range(minimum[2], maximum[2]));
return rangeArray;
}
vtkm::cont::ArrayHandle<vtkm::Range> ArrayRangeCompute(
const vtkm::cont::ArrayHandle<vtkm::Id, vtkm::cont::StorageTagIndex>& input,
vtkm::cont::DeviceAdapterId)
{
vtkm::cont::ArrayHandle<vtkm::Range> result;
result.Allocate(1);
result.WritePortal().Set(0, vtkm::Range(0, input.GetNumberOfValues() - 1));
return result;
}
#include <vtkm/cont/ArrayHandleBasic.h>
#include <vtkm/cont/ArrayHandleCartesianProduct.h>
#include <vtkm/cont/ArrayHandleCompositeVector.h>
#include <vtkm/cont/ArrayHandleConstant.h>
#include <vtkm/cont/ArrayHandleCounting.h>
#include <vtkm/cont/ArrayHandleIndex.h>
#include <vtkm/cont/ArrayHandleSOA.h>
#include <vtkm/cont/ArrayHandleStride.h>
#include <vtkm/cont/ArrayHandleUniformPointCoordinates.h>
#include <vtkm/cont/ArrayHandleXGCCoordinates.h>
namespace
{
@ -152,7 +50,7 @@ struct ComputeRangeFunctor
vtkm::cont::DeviceAdapterId device,
vtkm::cont::ArrayHandle<vtkm::Range>& ranges) const
{
ranges = vtkm::cont::ArrayRangeCompute(array, device);
ranges = vtkm::cont::ArrayRangeComputeTemplate(array, device);
}
// Used with vtkm::ListForEach to get components
@ -172,7 +70,7 @@ struct ComputeRangeFunctor
{
vtkm::cont::ArrayHandleStride<T> componentArray = array.ExtractComponent<T>(componentI);
vtkm::cont::ArrayHandle<vtkm::Range> componentRange =
vtkm::cont::ArrayRangeCompute(componentArray, device);
vtkm::cont::ArrayRangeComputeTemplate(componentArray, device);
rangePortal.Set(componentI, componentRange.ReadPortal().Get(0));
}
success = true;
@ -191,6 +89,21 @@ vtkm::cont::ArrayHandle<vtkm::Range> ComputeForStorage(const vtkm::cont::Unknown
} // anonymous namespace
namespace vtkm
{
namespace cont
{
namespace internal
{
void ThrowArrayRangeComputeFailed()
{
throw vtkm::cont::ErrorExecution("Failed to run ArrayRangeComputation on any device.");
}
} // namespace internal
vtkm::cont::ArrayHandle<vtkm::Range> ArrayRangeCompute(const vtkm::cont::UnknownArrayHandle& array,
vtkm::cont::DeviceAdapterId device)
{
@ -214,7 +127,7 @@ vtkm::cont::ArrayHandle<vtkm::Range> ArrayRangeCompute(const vtkm::cont::Unknown
{
vtkm::cont::ArrayHandleUniformPointCoordinates uniformPoints;
array.AsArrayHandle(uniformPoints);
return vtkm::cont::ArrayRangeCompute(uniformPoints, device);
return vtkm::cont::ArrayRangeComputeTemplate(uniformPoints, device);
}
using CartesianProductStorage =
vtkm::cont::StorageTagCartesianProduct<vtkm::cont::StorageTagBasic,
@ -234,7 +147,7 @@ vtkm::cont::ArrayHandle<vtkm::Range> ArrayRangeCompute(const vtkm::cont::Unknown
}
if (array.IsStorageType<vtkm::cont::StorageTagIndex>())
{
return ArrayRangeCompute(array.AsArrayHandle<vtkm::cont::ArrayHandleIndex>(), device);
return ArrayRangeComputeTemplate(array.AsArrayHandle<vtkm::cont::ArrayHandleIndex>(), device);
}
}
catch (vtkm::cont::ErrorBadType&)

@ -31,7 +31,6 @@ namespace vtkm
namespace cont
{
///@{
/// \brief Compute the range of the data in an array handle.
///
/// Given an `ArrayHandle`, this function computes the range (min and max) of
@ -48,179 +47,27 @@ namespace cont
/// Note that the ArrayRangeCompute.h header file contains only precompiled overloads
/// of ArrayRangeCompute. This is so that ArrayRangeCompute.h can be included in
/// code that does not use a device compiler. If you need to compute array ranges
/// for arbitrary `ArrayHandle`s not in this precompiled list, you need to include
/// ArrayRangeComputeTemplate.h. This contains a templated version of ArrayRangeCompute
/// that will compile for any `ArrayHandle` type not already handled.
/// for arbitrary `ArrayHandle`s not in this precompiled list, you need to use
/// `ArrayRangeComputeTemplate` (declared in `ArrayRangeComputeTemplate`), which
/// will compile for any `ArrayHandle` type not already handled.
///
VTKM_CONT_EXPORT vtkm::cont::ArrayHandle<vtkm::Range> ArrayRangeCompute(
const vtkm::cont::UnknownArrayHandle& array,
vtkm::cont::DeviceAdapterId device = vtkm::cont::DeviceAdapterTagAny{});
#define VTK_M_ARRAY_RANGE_COMPUTE_EXPORT_T(T, Storage) \
VTKM_CONT_EXPORT \
VTKM_CONT \
vtkm::cont::ArrayHandle<vtkm::Range> ArrayRangeCompute( \
const vtkm::cont::ArrayHandle<T, Storage>& input, \
vtkm::cont::DeviceAdapterId device = vtkm::cont::DeviceAdapterTagAny())
#define VTK_M_ARRAY_RANGE_COMPUTE_EXPORT_VEC(T, N, Storage) \
VTKM_CONT_EXPORT \
VTKM_CONT \
vtkm::cont::ArrayHandle<vtkm::Range> ArrayRangeCompute( \
const vtkm::cont::ArrayHandle<vtkm::Vec<T, N>, Storage>& input, \
vtkm::cont::DeviceAdapterId device = vtkm::cont::DeviceAdapterTagAny())
#define VTK_M_ARRAY_RANGE_COMPUTE_EXPORT_ALL_SCALAR_T(Storage) \
VTK_M_ARRAY_RANGE_COMPUTE_EXPORT_T(vtkm::Int8, Storage); \
VTK_M_ARRAY_RANGE_COMPUTE_EXPORT_T(vtkm::UInt8, Storage); \
VTK_M_ARRAY_RANGE_COMPUTE_EXPORT_T(vtkm::Int16, Storage); \
VTK_M_ARRAY_RANGE_COMPUTE_EXPORT_T(vtkm::UInt16, Storage); \
VTK_M_ARRAY_RANGE_COMPUTE_EXPORT_T(vtkm::Int32, Storage); \
VTK_M_ARRAY_RANGE_COMPUTE_EXPORT_T(vtkm::UInt32, Storage); \
VTK_M_ARRAY_RANGE_COMPUTE_EXPORT_T(vtkm::Int64, Storage); \
VTK_M_ARRAY_RANGE_COMPUTE_EXPORT_T(vtkm::UInt64, Storage); \
VTK_M_ARRAY_RANGE_COMPUTE_EXPORT_T(vtkm::Float32, Storage); \
VTK_M_ARRAY_RANGE_COMPUTE_EXPORT_T(vtkm::Float64, Storage); \
VTK_M_ARRAY_RANGE_COMPUTE_EXPORT_T(char, Storage); \
VTK_M_ARRAY_RANGE_COMPUTE_EXPORT_T(signed VTKM_UNUSED_INT_TYPE, Storage); \
VTK_M_ARRAY_RANGE_COMPUTE_EXPORT_T(unsigned VTKM_UNUSED_INT_TYPE, Storage)
#define VTK_M_ARRAY_RANGE_COMPUTE_EXPORT_ALL_VEC(N, Storage) \
VTK_M_ARRAY_RANGE_COMPUTE_EXPORT_VEC(vtkm::Int8, N, Storage); \
VTK_M_ARRAY_RANGE_COMPUTE_EXPORT_VEC(vtkm::UInt8, N, Storage); \
VTK_M_ARRAY_RANGE_COMPUTE_EXPORT_VEC(vtkm::Int16, N, Storage); \
VTK_M_ARRAY_RANGE_COMPUTE_EXPORT_VEC(vtkm::UInt16, N, Storage); \
VTK_M_ARRAY_RANGE_COMPUTE_EXPORT_VEC(vtkm::Int32, N, Storage); \
VTK_M_ARRAY_RANGE_COMPUTE_EXPORT_VEC(vtkm::UInt32, N, Storage); \
VTK_M_ARRAY_RANGE_COMPUTE_EXPORT_VEC(vtkm::Int64, N, Storage); \
VTK_M_ARRAY_RANGE_COMPUTE_EXPORT_VEC(vtkm::UInt64, N, Storage); \
VTK_M_ARRAY_RANGE_COMPUTE_EXPORT_VEC(vtkm::Float32, N, Storage); \
VTK_M_ARRAY_RANGE_COMPUTE_EXPORT_VEC(vtkm::Float64, N, Storage); \
VTK_M_ARRAY_RANGE_COMPUTE_EXPORT_VEC(char, N, Storage); \
VTK_M_ARRAY_RANGE_COMPUTE_EXPORT_VEC(signed VTKM_UNUSED_INT_TYPE, N, Storage); \
VTK_M_ARRAY_RANGE_COMPUTE_EXPORT_VEC(unsigned VTKM_UNUSED_INT_TYPE, N, Storage)
VTK_M_ARRAY_RANGE_COMPUTE_EXPORT_ALL_SCALAR_T(vtkm::cont::StorageTagBasic);
VTK_M_ARRAY_RANGE_COMPUTE_EXPORT_ALL_VEC(2, vtkm::cont::StorageTagBasic);
VTK_M_ARRAY_RANGE_COMPUTE_EXPORT_ALL_VEC(3, vtkm::cont::StorageTagBasic);
VTK_M_ARRAY_RANGE_COMPUTE_EXPORT_ALL_VEC(4, vtkm::cont::StorageTagBasic);
VTK_M_ARRAY_RANGE_COMPUTE_EXPORT_ALL_VEC(2, vtkm::cont::StorageTagSOA);
VTK_M_ARRAY_RANGE_COMPUTE_EXPORT_ALL_VEC(3, vtkm::cont::StorageTagSOA);
VTK_M_ARRAY_RANGE_COMPUTE_EXPORT_ALL_VEC(4, vtkm::cont::StorageTagSOA);
VTK_M_ARRAY_RANGE_COMPUTE_EXPORT_ALL_SCALAR_T(vtkm::cont::StorageTagStride);
VTK_M_ARRAY_RANGE_COMPUTE_EXPORT_VEC(vtkm::Float32, 3, vtkm::cont::StorageTagXGCCoordinates);
VTK_M_ARRAY_RANGE_COMPUTE_EXPORT_VEC(vtkm::Float64, 3, vtkm::cont::StorageTagXGCCoordinates);
#undef VTK_M_ARRAY_RANGE_COMPUTE_EXPORT_T
#undef VTK_M_ARRAY_RANGE_COMPUTE_EXPORT_VEC
#undef VTK_M_ARRAY_RANGE_COMPUTE_EXPORT_ALL_SCALAR_T
#undef VTK_M_ARRAY_RANGE_COMPUTE_EXPORT_ALL_VEC
VTKM_CONT_EXPORT VTKM_CONT vtkm::cont::ArrayHandle<vtkm::Range> ArrayRangeCompute(
const vtkm::cont::ArrayHandle<vtkm::Vec3f,
vtkm::cont::ArrayHandleUniformPointCoordinates::StorageTag>& array,
vtkm::cont::DeviceAdapterId device = vtkm::cont::DeviceAdapterTagAny());
// Implementation of cartesian products
template <typename T, typename ST1, typename ST2, typename ST3>
VTKM_CONT inline vtkm::cont::ArrayHandle<vtkm::Range> ArrayRangeCompute(
const vtkm::cont::ArrayHandle<vtkm::Vec<T, 3>,
vtkm::cont::StorageTagCartesianProduct<ST1, ST2, ST3>>& input_,
vtkm::cont::DeviceAdapterId device = vtkm::cont::DeviceAdapterTagAny())
namespace internal
{
vtkm::cont::ArrayHandle<vtkm::Range> result;
result.Allocate(3);
vtkm::cont::ArrayHandle<vtkm::Range> componentRangeArray;
vtkm::Range componentRange;
vtkm::cont::ArrayHandleCartesianProduct<vtkm::cont::ArrayHandle<T, ST1>,
vtkm::cont::ArrayHandle<T, ST2>,
vtkm::cont::ArrayHandle<T, ST3>>
input = input_;
vtkm::cont::ArrayHandle<T, ST1> firstArray = input.GetFirstArray();
componentRangeArray = vtkm::cont::ArrayRangeCompute(firstArray, device);
componentRange = componentRangeArray.ReadPortal().Get(0);
result.WritePortal().Set(0, componentRange);
vtkm::cont::ArrayHandle<T, ST2> secondArray = input.GetSecondArray();
componentRangeArray = vtkm::cont::ArrayRangeCompute(secondArray, device);
componentRange = componentRangeArray.ReadPortal().Get(0);
result.WritePortal().Set(1, componentRange);
vtkm::cont::ArrayHandle<T, ST3> thirdArray = input.GetThirdArray();
componentRangeArray = vtkm::cont::ArrayRangeCompute(thirdArray, device);
componentRange = componentRangeArray.ReadPortal().Get(0);
result.WritePortal().Set(2, componentRange);
return result;
}
// Implementation of constant arrays
template <typename T>
VTKM_CONT inline vtkm::cont::ArrayHandle<vtkm::Range> ArrayRangeCompute(
const vtkm::cont::ArrayHandle<T, vtkm::cont::StorageTagConstant>& input,
vtkm::cont::DeviceAdapterId vtkmNotUsed(device) = vtkm::cont::DeviceAdapterTagAny{})
{
using Traits = vtkm::VecTraits<T>;
const T value = vtkm::cont::ArrayHandleConstant<T>(input).GetValue();
vtkm::IdComponent numComponents = Traits::GetNumberOfComponents(value);
vtkm::cont::ArrayHandle<vtkm::Range> result;
result.Allocate(numComponents);
auto portal = result.WritePortal();
for (vtkm::IdComponent cIndex = 0; cIndex < numComponents; ++cIndex)
{
auto component = Traits::GetComponent(value, cIndex);
portal.Set(cIndex, vtkm::Range(component, component));
}
return result;
}
// Implementation of counting arrays
template <typename T>
VTKM_CONT inline vtkm::cont::ArrayHandle<vtkm::Range> ArrayRangeCompute(
const vtkm::cont::ArrayHandle<T, vtkm::cont::StorageTagCounting>& input,
vtkm::cont::DeviceAdapterId vtkmNotUsed(device) = vtkm::cont::DeviceAdapterTagAny{})
{
using Traits = vtkm::VecTraits<T>;
vtkm::cont::ArrayHandle<vtkm::Range> result;
result.Allocate(Traits::NUM_COMPONENTS);
auto portal = result.WritePortal();
if (portal.GetNumberOfValues() > 0)
{
T first = input.ReadPortal().Get(0);
T last = input.ReadPortal().Get(input.GetNumberOfValues() - 1);
for (vtkm::IdComponent cIndex = 0; cIndex < Traits::NUM_COMPONENTS; ++cIndex)
{
auto firstComponent = Traits::GetComponent(first, cIndex);
auto lastComponent = Traits::GetComponent(last, cIndex);
portal.Set(cIndex,
vtkm::Range(vtkm::Min(firstComponent, lastComponent),
vtkm::Max(firstComponent, lastComponent)));
}
}
else
{
// Array is empty
for (vtkm::IdComponent cIndex = 0; cIndex < Traits::NUM_COMPONENTS; ++cIndex)
{
portal.Set(cIndex, vtkm::Range{});
}
}
return result;
}
// Implementation of index arrays
VTKM_CONT_EXPORT vtkm::cont::ArrayHandle<vtkm::Range> ArrayRangeCompute(
const vtkm::cont::ArrayHandle<vtkm::Id, vtkm::cont::StorageTagIndex>& input,
vtkm::cont::DeviceAdapterId device = vtkm::cont::DeviceAdapterTagAny{});
///@}
VTKM_CONT_EXPORT void ThrowArrayRangeComputeFailed();
} // namespace internal
VTKM_DEPRECATED(2.1, "Moved to vtkm::cont::internal.")
inline void ThrowArrayRangeComputeFailed()
{
internal::ThrowArrayRangeComputeFailed();
}
}
} // namespace vtkm::cont

@ -13,6 +13,7 @@
#include <vtkm/cont/ArrayRangeCompute.h>
#include <vtkm/BinaryOperators.h>
#include <vtkm/Deprecated.h>
#include <vtkm/VecTraits.h>
#include <vtkm/cont/Algorithm.h>
@ -42,8 +43,13 @@ struct ArrayRangeComputeFunctor
}
};
} // namespace detail
namespace internal
{
template <typename T, typename S>
inline vtkm::cont::ArrayHandle<vtkm::Range> ArrayRangeComputeImpl(
inline vtkm::cont::ArrayHandle<vtkm::Range> ArrayRangeComputeGeneric(
const vtkm::cont::ArrayHandle<T, S>& input,
vtkm::cont::DeviceAdapterId device)
{
@ -74,7 +80,7 @@ inline vtkm::cont::ArrayHandle<vtkm::Range> ArrayRangeComputeImpl(
initial[1] = T(std::numeric_limits<CT>::lowest());
const bool rangeComputed = vtkm::cont::TryExecuteOnDevice(
device, detail::ArrayRangeComputeFunctor{}, input, initial, result);
device, vtkm::cont::detail::ArrayRangeComputeFunctor{}, input, initial, result);
if (!rangeComputed)
{
ThrowArrayRangeComputeFailed();
@ -93,17 +99,38 @@ inline vtkm::cont::ArrayHandle<vtkm::Range> ArrayRangeComputeImpl(
return range;
}
} // namespace detail
template <typename S>
struct ArrayRangeComputeImpl
{
template <typename T>
vtkm::cont::ArrayHandle<vtkm::Range> operator()(const vtkm::cont::ArrayHandle<T, S>& input,
vtkm::cont::DeviceAdapterId device) const
{
return vtkm::cont::internal::ArrayRangeComputeGeneric(input, device);
}
};
} // namespace internal
template <typename ArrayHandleType>
inline vtkm::cont::ArrayHandle<vtkm::Range> ArrayRangeCompute(
inline vtkm::cont::ArrayHandle<vtkm::Range> ArrayRangeComputeTemplate(
const ArrayHandleType& input,
vtkm::cont::DeviceAdapterId device = vtkm::cont::DeviceAdapterTagAny{})
{
VTKM_IS_ARRAY_HANDLE(ArrayHandleType);
return detail::ArrayRangeComputeImpl(input, device);
return internal::ArrayRangeComputeImpl<typename ArrayHandleType::StorageTag>{}(input, device);
}
template <typename ArrayHandleType>
VTKM_DEPRECATED(2.1, "Use precompiled ArrayRangeCompute or ArrayRangeComputeTemplate.")
inline vtkm::cont::ArrayHandle<vtkm::Range> ArrayRangeCompute(
const ArrayHandleType& input,
vtkm::cont::DeviceAdapterId device = vtkm::cont::DeviceAdapterTagAny{})
{
return ArrayRangeComputeTemplate(input, device);
}
}
} // namespace vtkm::cont

@ -65,7 +65,6 @@ template <typename T, typename S>
void CheckRange(const vtkm::cont::ArrayHandle<T, S>& array)
{
VerifyRange(array, vtkm::cont::ArrayRangeCompute(array));
VerifyRange(array, vtkm::cont::ArrayRangeCompute(vtkm::cont::UnknownArrayHandle{ array }));
}
template <typename T, typename S>

@ -576,7 +576,8 @@ template <typename FieldType>
inline void ContourTreeMesh<FieldType>::ComputeMaxNeighbors()
{
auto neighborCounts = make_ArrayHandleOffsetsToNumComponents(this->NeighborOffsets);
vtkm::cont::ArrayHandle<vtkm::Range> rangeArray = vtkm::cont::ArrayRangeCompute(neighborCounts);
vtkm::cont::ArrayHandle<vtkm::Range> rangeArray =
vtkm::cont::ArrayRangeComputeTemplate(neighborCounts);
this->MaxNeighbors = static_cast<vtkm::Id>(rangeArray.ReadPortal().Get(0).Max);
}

@ -29,7 +29,6 @@
#include <vtkm/cont/ArrayHandleConstant.h>
#include <vtkm/cont/ArrayHandleTransform.h>
#include <vtkm/cont/ArrayRangeCompute.h>
#include <vtkm/cont/ArrayRangeComputeTemplate.h>
#include <vtkm/cont/BitField.h>
#include <vtkm/cont/Invoker.h>
#include <vtkm/cont/Logging.h>