2019-08-06 00:15:21 +00:00
|
|
|
//============================================================================
|
|
|
|
// 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_ArrayHandleSOA_h
|
|
|
|
#define vtk_m_cont_ArrayHandleSOA_h
|
|
|
|
|
2020-09-10 23:54:12 +00:00
|
|
|
#include <vtkm/cont/ArrayExtractComponent.h>
|
2019-08-06 00:15:21 +00:00
|
|
|
#include <vtkm/cont/ArrayHandle.h>
|
|
|
|
|
|
|
|
#include <vtkm/Math.h>
|
|
|
|
#include <vtkm/VecTraits.h>
|
|
|
|
|
2020-08-13 14:32:58 +00:00
|
|
|
#include <vtkm/internal/ArrayPortalBasic.h>
|
2019-08-06 00:15:21 +00:00
|
|
|
#include <vtkm/internal/ArrayPortalHelpers.h>
|
|
|
|
|
2020-02-25 22:11:10 +00:00
|
|
|
#include <vtkmstd/integer_sequence.h>
|
2019-08-06 00:15:21 +00:00
|
|
|
|
|
|
|
#include <array>
|
|
|
|
#include <limits>
|
Use SFINAE to write Set/Get methods in ArrayPortalSOA
Because ArrayPortalSOA calls a delegate portal to get the actual values,
it can only implement its own Set or Get if the delegate portal supports
it. Previously this was done by calling an overloaded internal method
based on the result of PortalSupportsSets/Gets. However, regardless of
whether the delegate portal supported Set or Get, ArrayPortalSOA
provided one. Thus, if something else tried to use PortalSupportsSets/
Gets on ArrayPortalSOA, it would always report true even if it was not
really supported.
Instead, use SFINAE to remove the Set or Get if that method is not
supported in the delegate portal.
Since ArrayHandleSOA is only really used for portals from basic storage
arrays, it will be rare that Set or Get is not supported. However, a
device adapter is free to remove one of these methods on a device
portal. For example, if you call PrepareForInput on an ArrayHandle, it
is possible that the device adapter will create a portal that has no Set
method because the array is not writable.
Thanks to Allison Vacanti for recomending this solution.
2019-08-20 17:18:17 +00:00
|
|
|
#include <type_traits>
|
2019-08-06 00:15:21 +00:00
|
|
|
|
|
|
|
namespace vtkm
|
|
|
|
{
|
|
|
|
|
|
|
|
namespace internal
|
|
|
|
{
|
|
|
|
|
|
|
|
/// \brief An array portal that combines indices from multiple sources.
|
|
|
|
///
|
|
|
|
/// This will only work if \c VecTraits is defined for the type.
|
|
|
|
///
|
2020-08-13 14:32:58 +00:00
|
|
|
template <typename ValueType_, typename ComponentPortalType>
|
2019-08-06 00:15:21 +00:00
|
|
|
class ArrayPortalSOA
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
using ValueType = ValueType_;
|
|
|
|
|
|
|
|
private:
|
2020-08-13 14:32:58 +00:00
|
|
|
using ComponentType = typename ComponentPortalType::ValueType;
|
2019-08-06 00:15:21 +00:00
|
|
|
|
|
|
|
using VTraits = vtkm::VecTraits<ValueType>;
|
|
|
|
VTKM_STATIC_ASSERT((std::is_same<typename VTraits::ComponentType, ComponentType>::value));
|
|
|
|
static constexpr vtkm::IdComponent NUM_COMPONENTS = VTraits::NUM_COMPONENTS;
|
|
|
|
|
2020-08-13 14:32:58 +00:00
|
|
|
ComponentPortalType Portals[NUM_COMPONENTS];
|
2019-08-06 00:15:21 +00:00
|
|
|
vtkm::Id NumberOfValues;
|
|
|
|
|
|
|
|
public:
|
|
|
|
VTKM_SUPPRESS_EXEC_WARNINGS
|
|
|
|
VTKM_EXEC_CONT explicit ArrayPortalSOA(vtkm::Id numValues = 0)
|
|
|
|
: NumberOfValues(numValues)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
VTKM_SUPPRESS_EXEC_WARNINGS
|
2020-08-13 14:32:58 +00:00
|
|
|
VTKM_EXEC_CONT void SetPortal(vtkm::IdComponent index, const ComponentPortalType& portal)
|
2019-08-06 00:15:21 +00:00
|
|
|
{
|
|
|
|
this->Portals[index] = portal;
|
|
|
|
}
|
|
|
|
|
|
|
|
VTKM_EXEC_CONT vtkm::Id GetNumberOfValues() const { return this->NumberOfValues; }
|
|
|
|
|
2020-08-13 14:32:58 +00:00
|
|
|
template <typename SPT = ComponentPortalType,
|
Use SFINAE to write Set/Get methods in ArrayPortalSOA
Because ArrayPortalSOA calls a delegate portal to get the actual values,
it can only implement its own Set or Get if the delegate portal supports
it. Previously this was done by calling an overloaded internal method
based on the result of PortalSupportsSets/Gets. However, regardless of
whether the delegate portal supported Set or Get, ArrayPortalSOA
provided one. Thus, if something else tried to use PortalSupportsSets/
Gets on ArrayPortalSOA, it would always report true even if it was not
really supported.
Instead, use SFINAE to remove the Set or Get if that method is not
supported in the delegate portal.
Since ArrayHandleSOA is only really used for portals from basic storage
arrays, it will be rare that Set or Get is not supported. However, a
device adapter is free to remove one of these methods on a device
portal. For example, if you call PrepareForInput on an ArrayHandle, it
is possible that the device adapter will create a portal that has no Set
method because the array is not writable.
Thanks to Allison Vacanti for recomending this solution.
2019-08-20 17:18:17 +00:00
|
|
|
typename Supported = typename vtkm::internal::PortalSupportsGets<SPT>::type,
|
|
|
|
typename = typename std::enable_if<Supported::value>::type>
|
2019-08-06 00:15:21 +00:00
|
|
|
VTKM_EXEC_CONT ValueType Get(vtkm::Id valueIndex) const
|
|
|
|
{
|
2020-02-25 22:11:10 +00:00
|
|
|
return this->Get(valueIndex, vtkmstd::make_index_sequence<NUM_COMPONENTS>());
|
2019-08-06 00:15:21 +00:00
|
|
|
}
|
|
|
|
|
2020-08-13 14:32:58 +00:00
|
|
|
template <typename SPT = ComponentPortalType,
|
Use SFINAE to write Set/Get methods in ArrayPortalSOA
Because ArrayPortalSOA calls a delegate portal to get the actual values,
it can only implement its own Set or Get if the delegate portal supports
it. Previously this was done by calling an overloaded internal method
based on the result of PortalSupportsSets/Gets. However, regardless of
whether the delegate portal supported Set or Get, ArrayPortalSOA
provided one. Thus, if something else tried to use PortalSupportsSets/
Gets on ArrayPortalSOA, it would always report true even if it was not
really supported.
Instead, use SFINAE to remove the Set or Get if that method is not
supported in the delegate portal.
Since ArrayHandleSOA is only really used for portals from basic storage
arrays, it will be rare that Set or Get is not supported. However, a
device adapter is free to remove one of these methods on a device
portal. For example, if you call PrepareForInput on an ArrayHandle, it
is possible that the device adapter will create a portal that has no Set
method because the array is not writable.
Thanks to Allison Vacanti for recomending this solution.
2019-08-20 17:18:17 +00:00
|
|
|
typename Supported = typename vtkm::internal::PortalSupportsSets<SPT>::type,
|
|
|
|
typename = typename std::enable_if<Supported::value>::type>
|
2019-08-06 00:15:21 +00:00
|
|
|
VTKM_EXEC_CONT void Set(vtkm::Id valueIndex, const ValueType& value) const
|
|
|
|
{
|
2020-02-25 22:11:10 +00:00
|
|
|
this->Set(valueIndex, value, vtkmstd::make_index_sequence<NUM_COMPONENTS>());
|
2019-08-06 00:15:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
2020-07-03 15:27:56 +00:00
|
|
|
VTKM_SUPPRESS_EXEC_WARNINGS
|
2019-08-06 00:15:21 +00:00
|
|
|
template <std::size_t I>
|
|
|
|
VTKM_EXEC_CONT ComponentType GetComponent(vtkm::Id valueIndex) const
|
|
|
|
{
|
|
|
|
return this->Portals[I].Get(valueIndex);
|
|
|
|
}
|
|
|
|
|
|
|
|
template <std::size_t... I>
|
2020-02-25 22:11:10 +00:00
|
|
|
VTKM_EXEC_CONT ValueType Get(vtkm::Id valueIndex, vtkmstd::index_sequence<I...>) const
|
2019-08-06 00:15:21 +00:00
|
|
|
{
|
|
|
|
return ValueType{ this->GetComponent<I>(valueIndex)... };
|
|
|
|
}
|
|
|
|
|
2020-07-03 15:27:56 +00:00
|
|
|
VTKM_SUPPRESS_EXEC_WARNINGS
|
2019-08-06 00:15:21 +00:00
|
|
|
template <std::size_t I>
|
|
|
|
VTKM_EXEC_CONT bool SetComponent(vtkm::Id valueIndex, const ValueType& value) const
|
|
|
|
{
|
|
|
|
this->Portals[I].Set(valueIndex,
|
|
|
|
VTraits::GetComponent(value, static_cast<vtkm::IdComponent>(I)));
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
template <std::size_t... I>
|
|
|
|
VTKM_EXEC_CONT void Set(vtkm::Id valueIndex,
|
|
|
|
const ValueType& value,
|
2020-02-25 22:11:10 +00:00
|
|
|
vtkmstd::index_sequence<I...>) const
|
2019-08-06 00:15:21 +00:00
|
|
|
{
|
|
|
|
// Is there a better way to unpack an expression and execute them with no other side effects?
|
|
|
|
(void)std::initializer_list<bool>{ this->SetComponent<I>(valueIndex, value)... };
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
} // namespace internal
|
|
|
|
|
|
|
|
namespace cont
|
|
|
|
{
|
|
|
|
|
|
|
|
struct VTKM_ALWAYS_EXPORT StorageTagSOA
|
|
|
|
{
|
|
|
|
};
|
|
|
|
|
|
|
|
namespace internal
|
|
|
|
{
|
|
|
|
|
2020-12-09 21:44:59 +00:00
|
|
|
template <typename ComponentType, vtkm::IdComponent NUM_COMPONENTS>
|
|
|
|
class VTKM_ALWAYS_EXPORT
|
|
|
|
Storage<vtkm::Vec<ComponentType, NUM_COMPONENTS>, vtkm::cont::StorageTagSOA>
|
2019-08-06 00:15:21 +00:00
|
|
|
{
|
2020-12-09 21:44:59 +00:00
|
|
|
using ValueType = vtkm::Vec<ComponentType, NUM_COMPONENTS>;
|
2019-08-06 00:15:21 +00:00
|
|
|
|
2020-08-13 14:32:58 +00:00
|
|
|
public:
|
|
|
|
using ReadPortalType =
|
2020-12-09 21:44:59 +00:00
|
|
|
vtkm::internal::ArrayPortalSOA<ValueType, vtkm::internal::ArrayPortalBasicRead<ComponentType>>;
|
2020-08-13 14:32:58 +00:00
|
|
|
using WritePortalType =
|
2020-12-09 21:44:59 +00:00
|
|
|
vtkm::internal::ArrayPortalSOA<ValueType, vtkm::internal::ArrayPortalBasicWrite<ComponentType>>;
|
2019-08-06 00:15:21 +00:00
|
|
|
|
2022-06-28 20:26:38 +00:00
|
|
|
VTKM_CONT static std::vector<vtkm::cont::internal::Buffer> CreateBuffers()
|
|
|
|
{
|
|
|
|
return std::vector<vtkm::cont::internal::Buffer>(static_cast<std::size_t>(NUM_COMPONENTS));
|
|
|
|
}
|
2019-08-06 00:15:21 +00:00
|
|
|
|
2020-08-25 15:36:07 +00:00
|
|
|
VTKM_CONT static void ResizeBuffers(vtkm::Id numValues,
|
2022-06-28 20:26:38 +00:00
|
|
|
const std::vector<vtkm::cont::internal::Buffer>& buffers,
|
2020-08-25 15:36:07 +00:00
|
|
|
vtkm::CopyFlag preserve,
|
|
|
|
vtkm::cont::Token& token)
|
2019-08-06 00:15:21 +00:00
|
|
|
{
|
2020-08-13 14:32:58 +00:00
|
|
|
vtkm::BufferSizeType numBytes =
|
|
|
|
vtkm::internal::NumberOfValuesToNumberOfBytes<ComponentType>(numValues);
|
|
|
|
for (vtkm::IdComponent componentIndex = 0; componentIndex < NUM_COMPONENTS; ++componentIndex)
|
2019-08-06 00:15:21 +00:00
|
|
|
{
|
2020-08-13 14:32:58 +00:00
|
|
|
buffers[componentIndex].SetNumberOfBytes(numBytes, preserve, token);
|
2019-08-06 00:15:21 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-06-28 20:26:38 +00:00
|
|
|
VTKM_CONT static vtkm::Id GetNumberOfValues(
|
|
|
|
const std::vector<vtkm::cont::internal::Buffer>& buffers)
|
2019-08-06 00:15:21 +00:00
|
|
|
{
|
2020-08-13 14:32:58 +00:00
|
|
|
// Assume all buffers are the same size.
|
|
|
|
return static_cast<vtkm::Id>(buffers[0].GetNumberOfBytes()) /
|
|
|
|
static_cast<vtkm::Id>(sizeof(ComponentType));
|
2019-08-06 00:15:21 +00:00
|
|
|
}
|
|
|
|
|
2022-06-28 20:26:38 +00:00
|
|
|
VTKM_CONT static void Fill(const std::vector<vtkm::cont::internal::Buffer>& buffers,
|
2021-12-06 16:25:03 +00:00
|
|
|
const ValueType& fillValue,
|
|
|
|
vtkm::Id startIndex,
|
2022-01-11 14:15:41 +00:00
|
|
|
vtkm::Id endIndex,
|
2021-12-06 16:25:03 +00:00
|
|
|
vtkm::cont::Token& token)
|
|
|
|
{
|
|
|
|
constexpr vtkm::BufferSizeType sourceSize =
|
|
|
|
static_cast<vtkm::BufferSizeType>(sizeof(ComponentType));
|
|
|
|
vtkm::BufferSizeType startByte = startIndex * sourceSize;
|
2022-01-11 14:15:41 +00:00
|
|
|
vtkm::BufferSizeType endByte = endIndex * sourceSize;
|
2021-12-06 16:25:03 +00:00
|
|
|
for (vtkm::IdComponent componentIndex = 0; componentIndex < NUM_COMPONENTS; ++componentIndex)
|
|
|
|
{
|
|
|
|
ComponentType source = fillValue[componentIndex];
|
2022-01-11 14:15:41 +00:00
|
|
|
buffers[componentIndex].Fill(&source, sourceSize, startByte, endByte, token);
|
2021-12-06 16:25:03 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-06-28 20:26:38 +00:00
|
|
|
VTKM_CONT static ReadPortalType CreateReadPortal(
|
|
|
|
const std::vector<vtkm::cont::internal::Buffer>& buffers,
|
|
|
|
vtkm::cont::DeviceAdapterId device,
|
|
|
|
vtkm::cont::Token& token)
|
2019-08-06 00:15:21 +00:00
|
|
|
{
|
2020-08-25 15:36:07 +00:00
|
|
|
vtkm::Id numValues = GetNumberOfValues(buffers);
|
2020-08-13 14:32:58 +00:00
|
|
|
ReadPortalType portal(numValues);
|
2019-08-06 00:15:21 +00:00
|
|
|
for (vtkm::IdComponent componentIndex = 0; componentIndex < NUM_COMPONENTS; ++componentIndex)
|
|
|
|
{
|
2020-08-13 14:32:58 +00:00
|
|
|
VTKM_ASSERT(buffers[0].GetNumberOfBytes() == buffers[componentIndex].GetNumberOfBytes());
|
|
|
|
portal.SetPortal(componentIndex,
|
|
|
|
vtkm::internal::ArrayPortalBasicRead<ComponentType>(
|
|
|
|
reinterpret_cast<const ComponentType*>(
|
|
|
|
buffers[componentIndex].ReadPointerDevice(device, token)),
|
|
|
|
numValues));
|
2019-08-06 00:15:21 +00:00
|
|
|
}
|
2020-08-13 14:32:58 +00:00
|
|
|
return portal;
|
2019-08-06 00:15:21 +00:00
|
|
|
}
|
|
|
|
|
2022-06-28 20:26:38 +00:00
|
|
|
VTKM_CONT static WritePortalType CreateWritePortal(
|
|
|
|
const std::vector<vtkm::cont::internal::Buffer>& buffers,
|
|
|
|
vtkm::cont::DeviceAdapterId device,
|
|
|
|
vtkm::cont::Token& token)
|
2019-08-06 00:15:21 +00:00
|
|
|
{
|
2020-08-25 15:36:07 +00:00
|
|
|
vtkm::Id numValues = GetNumberOfValues(buffers);
|
2020-08-13 14:32:58 +00:00
|
|
|
WritePortalType portal(numValues);
|
2019-08-06 00:15:21 +00:00
|
|
|
for (vtkm::IdComponent componentIndex = 0; componentIndex < NUM_COMPONENTS; ++componentIndex)
|
|
|
|
{
|
2020-08-13 14:32:58 +00:00
|
|
|
VTKM_ASSERT(buffers[0].GetNumberOfBytes() == buffers[componentIndex].GetNumberOfBytes());
|
|
|
|
portal.SetPortal(componentIndex,
|
|
|
|
vtkm::internal::ArrayPortalBasicWrite<ComponentType>(
|
|
|
|
reinterpret_cast<ComponentType*>(
|
|
|
|
buffers[componentIndex].WritePointerDevice(device, token)),
|
|
|
|
numValues));
|
2019-08-06 00:15:21 +00:00
|
|
|
}
|
2020-08-13 14:32:58 +00:00
|
|
|
return portal;
|
2019-08-06 00:15:21 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2020-08-13 14:32:58 +00:00
|
|
|
} // namespace internal
|
2019-08-06 00:15:21 +00:00
|
|
|
|
2020-08-13 14:32:58 +00:00
|
|
|
/// \brief An `ArrayHandle` that for Vecs stores each component in a separate physical array.
|
2019-08-06 00:15:21 +00:00
|
|
|
///
|
2020-08-13 14:32:58 +00:00
|
|
|
/// `ArrayHandleSOA` behaves like a regular `ArrayHandle` (with a basic storage) except that
|
|
|
|
/// if you specify a `ValueType` of a `Vec` or a `Vec-like`, it will actually store each
|
2019-08-06 00:15:21 +00:00
|
|
|
/// component in a separate physical array. When data are retrieved from the array, they are
|
2020-08-13 14:32:58 +00:00
|
|
|
/// reconstructed into `Vec` objects as expected.
|
2019-08-06 00:15:21 +00:00
|
|
|
///
|
|
|
|
/// The intention of this array type is to help cover the most common ways data is lain out in
|
|
|
|
/// memory. Typically, arrays of data are either an "array of structures" like the basic storage
|
2020-08-13 14:32:58 +00:00
|
|
|
/// where you have a single array of structures (like `Vec`) or a "structure of arrays" where
|
|
|
|
/// you have an array of a basic type (like `float`) for each component of the data being
|
|
|
|
/// represented. The `ArrayHandleSOA` makes it easy to cover this second case without creating
|
2019-08-06 00:15:21 +00:00
|
|
|
/// special types.
|
|
|
|
///
|
2020-08-13 14:32:58 +00:00
|
|
|
/// `ArrayHandleSOA` can be constructed from a collection of `ArrayHandle` with basic storage.
|
|
|
|
/// This allows you to construct `Vec` arrays from components without deep copies.
|
2019-08-06 00:15:21 +00:00
|
|
|
///
|
2020-08-13 14:32:58 +00:00
|
|
|
template <typename T>
|
|
|
|
class ArrayHandleSOA : public ArrayHandle<T, vtkm::cont::StorageTagSOA>
|
2019-08-06 00:15:21 +00:00
|
|
|
{
|
2020-08-13 14:32:58 +00:00
|
|
|
using ComponentType = typename vtkm::VecTraits<T>::ComponentType;
|
|
|
|
static constexpr vtkm::IdComponent NUM_COMPONENTS = vtkm::VecTraits<T>::NUM_COMPONENTS;
|
|
|
|
|
|
|
|
using ComponentArrayType = vtkm::cont::ArrayHandle<ComponentType, vtkm::cont::StorageTagBasic>;
|
2019-08-06 00:15:21 +00:00
|
|
|
|
|
|
|
public:
|
|
|
|
VTKM_ARRAY_HANDLE_SUBCLASS(ArrayHandleSOA,
|
2020-08-13 14:32:58 +00:00
|
|
|
(ArrayHandleSOA<T>),
|
|
|
|
(ArrayHandle<T, vtkm::cont::StorageTagSOA>));
|
|
|
|
|
|
|
|
ArrayHandleSOA(std::initializer_list<vtkm::cont::internal::Buffer>&& componentBuffers)
|
|
|
|
: Superclass(std::move(componentBuffers))
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
ArrayHandleSOA(const std::array<ComponentArrayType, NUM_COMPONENTS>& componentArrays)
|
|
|
|
{
|
|
|
|
for (vtkm::IdComponent componentIndex = 0; componentIndex < NUM_COMPONENTS; ++componentIndex)
|
|
|
|
{
|
|
|
|
this->SetArray(componentIndex, componentArrays[componentIndex]);
|
|
|
|
}
|
|
|
|
}
|
2019-08-06 00:15:21 +00:00
|
|
|
|
2020-08-13 14:32:58 +00:00
|
|
|
ArrayHandleSOA(const std::vector<ComponentArrayType>& componentArrays)
|
2019-08-11 03:04:51 +00:00
|
|
|
{
|
2020-08-13 14:32:58 +00:00
|
|
|
VTKM_ASSERT(componentArrays.size() == NUM_COMPONENTS);
|
|
|
|
for (vtkm::IdComponent componentIndex = 0; componentIndex < NUM_COMPONENTS; ++componentIndex)
|
|
|
|
{
|
|
|
|
this->SetArray(componentIndex, componentArrays[componentIndex]);
|
|
|
|
}
|
2019-08-11 03:04:51 +00:00
|
|
|
}
|
|
|
|
|
2020-08-13 14:32:58 +00:00
|
|
|
ArrayHandleSOA(std::initializer_list<ComponentArrayType>&& componentArrays)
|
2020-07-23 23:54:03 +00:00
|
|
|
{
|
2020-08-13 14:32:58 +00:00
|
|
|
VTKM_ASSERT(componentArrays.size() == NUM_COMPONENTS);
|
|
|
|
vtkm::IdComponent componentIndex = 0;
|
|
|
|
for (auto&& array : componentArrays)
|
|
|
|
{
|
|
|
|
this->SetArray(componentIndex, array);
|
|
|
|
++componentIndex;
|
|
|
|
}
|
2020-07-23 23:54:03 +00:00
|
|
|
}
|
|
|
|
|
2019-08-11 03:04:51 +00:00
|
|
|
ArrayHandleSOA(std::initializer_list<std::vector<ComponentType>>&& componentVectors)
|
|
|
|
{
|
2020-08-13 14:32:58 +00:00
|
|
|
VTKM_ASSERT(componentVectors.size() == NUM_COMPONENTS);
|
2019-08-11 03:04:51 +00:00
|
|
|
vtkm::IdComponent componentIndex = 0;
|
2020-08-13 14:32:58 +00:00
|
|
|
for (auto&& vector : componentVectors)
|
2019-08-11 03:04:51 +00:00
|
|
|
{
|
|
|
|
// Note, std::vectors that come from std::initializer_list must be copied because the scope
|
|
|
|
// of the objects in the initializer list disappears.
|
2020-08-13 14:32:58 +00:00
|
|
|
this->SetArray(componentIndex, vtkm::cont::make_ArrayHandle(vector, vtkm::CopyFlag::On));
|
2019-08-11 03:04:51 +00:00
|
|
|
++componentIndex;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// This only works if all the templated arguments are of type std::vector<ComponentType>.
|
2020-08-13 14:32:58 +00:00
|
|
|
template <typename Allocator, typename... RemainingVectors>
|
2019-08-11 03:04:51 +00:00
|
|
|
ArrayHandleSOA(vtkm::CopyFlag copy,
|
2020-08-13 14:32:58 +00:00
|
|
|
const std::vector<ComponentType, Allocator>& vector0,
|
2020-07-16 16:32:32 +00:00
|
|
|
RemainingVectors&&... componentVectors)
|
2020-08-13 14:32:58 +00:00
|
|
|
: Superclass(std::vector<vtkm::cont::internal::Buffer>{
|
|
|
|
vtkm::cont::make_ArrayHandle(vector0, copy).GetBuffers()[0],
|
|
|
|
vtkm::cont::make_ArrayHandle(std::forward<RemainingVectors>(componentVectors), copy)
|
|
|
|
.GetBuffers()[0]... })
|
2020-07-16 16:32:32 +00:00
|
|
|
{
|
2020-08-13 14:32:58 +00:00
|
|
|
VTKM_STATIC_ASSERT(sizeof...(RemainingVectors) + 1 == NUM_COMPONENTS);
|
2020-07-16 16:32:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// This only works if all the templated arguments are of type std::vector<ComponentType>.
|
|
|
|
template <typename... RemainingVectors>
|
|
|
|
ArrayHandleSOA(vtkm::CopyFlag copy,
|
|
|
|
std::vector<ComponentType>&& vector0,
|
|
|
|
RemainingVectors&&... componentVectors)
|
2020-08-13 14:32:58 +00:00
|
|
|
: Superclass(std::vector<vtkm::cont::internal::Buffer>{
|
2020-07-16 16:32:32 +00:00
|
|
|
vtkm::cont::make_ArrayHandle(std::move(vector0), copy),
|
2020-08-13 14:32:58 +00:00
|
|
|
vtkm::cont::make_ArrayHandle(std::forward<RemainingVectors>(componentVectors), copy)
|
|
|
|
.GetBuffers()[0]... })
|
2019-08-11 03:04:51 +00:00
|
|
|
{
|
2020-08-13 14:32:58 +00:00
|
|
|
VTKM_STATIC_ASSERT(sizeof...(RemainingVectors) + 1 == NUM_COMPONENTS);
|
2019-08-11 03:04:51 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
ArrayHandleSOA(std::initializer_list<const ComponentType*> componentArrays,
|
|
|
|
vtkm::Id length,
|
2020-07-23 23:54:03 +00:00
|
|
|
vtkm::CopyFlag copy)
|
2019-08-11 03:04:51 +00:00
|
|
|
{
|
2020-08-13 14:32:58 +00:00
|
|
|
VTKM_ASSERT(componentArrays.size() == NUM_COMPONENTS);
|
2019-08-11 03:04:51 +00:00
|
|
|
vtkm::IdComponent componentIndex = 0;
|
|
|
|
for (auto&& vectorIter = componentArrays.begin(); vectorIter != componentArrays.end();
|
|
|
|
++vectorIter)
|
|
|
|
{
|
|
|
|
this->SetArray(componentIndex, vtkm::cont::make_ArrayHandle(*vectorIter, length, copy));
|
|
|
|
++componentIndex;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// This only works if all the templated arguments are of type std::vector<ComponentType>.
|
|
|
|
template <typename... RemainingArrays>
|
|
|
|
ArrayHandleSOA(vtkm::Id length,
|
|
|
|
vtkm::CopyFlag copy,
|
|
|
|
const ComponentType* array0,
|
|
|
|
const RemainingArrays&... componentArrays)
|
2020-08-13 14:32:58 +00:00
|
|
|
: Superclass(std::vector<vtkm::cont::internal::Buffer>{
|
|
|
|
vtkm::cont::make_ArrayHandle(array0, length, copy).GetBuffers()[0],
|
|
|
|
vtkm::cont::make_ArrayHandle(componentArrays, length, copy).GetBuffers()[0]... })
|
2019-08-11 03:04:51 +00:00
|
|
|
{
|
2020-08-13 14:32:58 +00:00
|
|
|
VTKM_STATIC_ASSERT(sizeof...(RemainingArrays) + 1 == NUM_COMPONENTS);
|
2019-08-11 03:04:51 +00:00
|
|
|
}
|
|
|
|
|
2020-08-13 14:32:58 +00:00
|
|
|
VTKM_CONT vtkm::cont::ArrayHandleBasic<ComponentType> GetArray(vtkm::IdComponent index) const
|
2019-08-06 00:15:21 +00:00
|
|
|
{
|
2022-06-28 20:26:38 +00:00
|
|
|
return ComponentArrayType({ this->GetBuffers()[index] });
|
2019-08-06 00:15:21 +00:00
|
|
|
}
|
|
|
|
|
2020-08-13 14:32:58 +00:00
|
|
|
VTKM_CONT void SetArray(vtkm::IdComponent index, const ComponentArrayType& array)
|
2019-08-06 00:15:21 +00:00
|
|
|
{
|
2020-08-13 14:32:58 +00:00
|
|
|
this->SetBuffer(index, array.GetBuffers()[0]);
|
2019-08-06 00:15:21 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
template <typename ValueType>
|
|
|
|
VTKM_CONT ArrayHandleSOA<ValueType> make_ArrayHandleSOA(
|
2019-08-11 03:04:51 +00:00
|
|
|
std::initializer_list<vtkm::cont::ArrayHandle<typename vtkm::VecTraits<ValueType>::ComponentType,
|
|
|
|
vtkm::cont::StorageTagBasic>>&& componentArrays)
|
2019-08-06 00:15:21 +00:00
|
|
|
{
|
2019-08-11 03:04:51 +00:00
|
|
|
return ArrayHandleSOA<ValueType>(std::move(componentArrays));
|
2019-08-06 00:15:21 +00:00
|
|
|
}
|
|
|
|
|
2019-08-11 03:04:51 +00:00
|
|
|
template <typename ComponentType, typename... RemainingArrays>
|
|
|
|
VTKM_CONT
|
|
|
|
ArrayHandleSOA<vtkm::Vec<ComponentType, vtkm::IdComponent(sizeof...(RemainingArrays) + 1)>>
|
|
|
|
make_ArrayHandleSOA(
|
|
|
|
const vtkm::cont::ArrayHandle<ComponentType, vtkm::cont::StorageTagBasic>& componentArray0,
|
|
|
|
const RemainingArrays&... componentArrays)
|
2019-08-06 00:15:21 +00:00
|
|
|
{
|
|
|
|
return { componentArray0, componentArrays... };
|
|
|
|
}
|
2019-08-11 03:04:51 +00:00
|
|
|
|
|
|
|
template <typename ValueType>
|
|
|
|
VTKM_CONT ArrayHandleSOA<ValueType> make_ArrayHandleSOA(
|
|
|
|
std::initializer_list<std::vector<typename vtkm::VecTraits<ValueType>::ComponentType>>&&
|
|
|
|
componentVectors)
|
|
|
|
{
|
|
|
|
return ArrayHandleSOA<ValueType>(std::move(componentVectors));
|
|
|
|
}
|
|
|
|
|
|
|
|
// This only works if all the templated arguments are of type std::vector<ComponentType>.
|
|
|
|
template <typename ComponentType, typename... RemainingVectors>
|
|
|
|
VTKM_CONT
|
|
|
|
ArrayHandleSOA<vtkm::Vec<ComponentType, vtkm::IdComponent(sizeof...(RemainingVectors) + 1)>>
|
|
|
|
make_ArrayHandleSOA(vtkm::CopyFlag copy,
|
|
|
|
const std::vector<ComponentType>& vector0,
|
2020-07-16 16:32:32 +00:00
|
|
|
RemainingVectors&&... componentVectors)
|
2019-08-11 03:04:51 +00:00
|
|
|
{
|
2020-07-23 23:54:03 +00:00
|
|
|
// Convert std::vector to ArrayHandle first so that it correctly handles a mix of rvalue args.
|
|
|
|
return { vtkm::cont::make_ArrayHandle(vector0, copy),
|
|
|
|
vtkm::cont::make_ArrayHandle(std::forward<RemainingVectors>(componentVectors),
|
|
|
|
copy)... };
|
2019-08-11 03:04:51 +00:00
|
|
|
}
|
|
|
|
|
2020-07-16 16:32:32 +00:00
|
|
|
// This only works if all the templated arguments are of type std::vector<ComponentType>.
|
2019-08-11 03:04:51 +00:00
|
|
|
template <typename ComponentType, typename... RemainingVectors>
|
|
|
|
VTKM_CONT
|
|
|
|
ArrayHandleSOA<vtkm::Vec<ComponentType, vtkm::IdComponent(sizeof...(RemainingVectors) + 1)>>
|
2020-07-16 16:32:32 +00:00
|
|
|
make_ArrayHandleSOA(vtkm::CopyFlag copy,
|
|
|
|
std::vector<ComponentType>&& vector0,
|
|
|
|
RemainingVectors&&... componentVectors)
|
|
|
|
{
|
2020-07-23 23:54:03 +00:00
|
|
|
// Convert std::vector to ArrayHandle first so that it correctly handles a mix of rvalue args.
|
2020-07-16 16:32:32 +00:00
|
|
|
return ArrayHandleSOA<
|
|
|
|
vtkm::Vec<ComponentType, vtkm::IdComponent(sizeof...(RemainingVectors) + 1)>>(
|
2020-07-23 23:54:03 +00:00
|
|
|
vtkm::cont::make_ArrayHandle(std::move(vector0), copy),
|
|
|
|
vtkm::cont::make_ArrayHandle(std::forward<RemainingVectors>(componentVectors), copy)...);
|
2020-07-16 16:32:32 +00:00
|
|
|
}
|
|
|
|
|
2020-07-23 23:54:03 +00:00
|
|
|
// This only works if all the templated arguments are rvalues of std::vector<ComponentType>.
|
|
|
|
template <typename ComponentType, typename... RemainingVectors>
|
|
|
|
VTKM_CONT
|
|
|
|
ArrayHandleSOA<vtkm::Vec<ComponentType, vtkm::IdComponent(sizeof...(RemainingVectors) + 1)>>
|
|
|
|
make_ArrayHandleSOAMove(std::vector<ComponentType>&& vector0,
|
|
|
|
RemainingVectors&&... componentVectors)
|
|
|
|
{
|
|
|
|
return { vtkm::cont::make_ArrayHandleMove(std::move(vector0)),
|
|
|
|
vtkm::cont::make_ArrayHandleMove(std::forward<RemainingVectors>(componentVectors))... };
|
|
|
|
}
|
|
|
|
|
2019-08-11 03:04:51 +00:00
|
|
|
template <typename ValueType>
|
|
|
|
VTKM_CONT ArrayHandleSOA<ValueType> make_ArrayHandleSOA(
|
|
|
|
std::initializer_list<const typename vtkm::VecTraits<ValueType>::ComponentType*>&&
|
|
|
|
componentVectors,
|
|
|
|
vtkm::Id length,
|
2020-07-23 23:54:03 +00:00
|
|
|
vtkm::CopyFlag copy)
|
2019-08-11 03:04:51 +00:00
|
|
|
{
|
|
|
|
return ArrayHandleSOA<ValueType>(std::move(componentVectors), length, copy);
|
|
|
|
}
|
|
|
|
|
|
|
|
// This only works if all the templated arguments are of type std::vector<ComponentType>.
|
|
|
|
template <typename ComponentType, typename... RemainingArrays>
|
|
|
|
VTKM_CONT
|
|
|
|
ArrayHandleSOA<vtkm::Vec<ComponentType, vtkm::IdComponent(sizeof...(RemainingArrays) + 1)>>
|
|
|
|
make_ArrayHandleSOA(vtkm::Id length,
|
|
|
|
vtkm::CopyFlag copy,
|
|
|
|
const ComponentType* array0,
|
|
|
|
const RemainingArrays*... componentArrays)
|
|
|
|
{
|
|
|
|
return ArrayHandleSOA<
|
|
|
|
vtkm::Vec<ComponentType, vtkm::IdComponent(sizeof...(RemainingArrays) + 1)>>(
|
|
|
|
length, copy, array0, componentArrays...);
|
|
|
|
}
|
|
|
|
|
2020-09-10 23:54:12 +00:00
|
|
|
namespace internal
|
|
|
|
{
|
|
|
|
|
|
|
|
template <>
|
|
|
|
struct ArrayExtractComponentImpl<vtkm::cont::StorageTagSOA>
|
|
|
|
{
|
|
|
|
template <typename T>
|
|
|
|
auto operator()(const vtkm::cont::ArrayHandle<T, vtkm::cont::StorageTagSOA>& src,
|
|
|
|
vtkm::IdComponent componentIndex,
|
|
|
|
vtkm::CopyFlag allowCopy) const
|
|
|
|
-> decltype(
|
|
|
|
ArrayExtractComponentImpl<vtkm::cont::StorageTagBasic>{}(vtkm::cont::ArrayHandleBasic<T>{},
|
|
|
|
componentIndex,
|
|
|
|
allowCopy))
|
|
|
|
{
|
|
|
|
using FirstLevelComponentType = typename vtkm::VecTraits<T>::ComponentType;
|
|
|
|
vtkm::cont::ArrayHandleSOA<T> array(src);
|
|
|
|
constexpr vtkm::IdComponent NUM_SUB_COMPONENTS =
|
|
|
|
vtkm::VecFlat<FirstLevelComponentType>::NUM_COMPONENTS;
|
|
|
|
return ArrayExtractComponentImpl<vtkm::cont::StorageTagBasic>{}(
|
|
|
|
array.GetArray(componentIndex / NUM_SUB_COMPONENTS),
|
|
|
|
componentIndex % NUM_SUB_COMPONENTS,
|
|
|
|
allowCopy);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
} // namespace internal
|
|
|
|
|
2019-08-06 00:15:21 +00:00
|
|
|
}
|
|
|
|
} // namespace vtkm::cont
|
|
|
|
|
|
|
|
//=============================================================================
|
|
|
|
// Specializations of serialization related classes
|
2019-09-12 21:19:36 +00:00
|
|
|
/// @cond SERIALIZATION
|
2019-08-06 00:15:21 +00:00
|
|
|
|
|
|
|
namespace vtkm
|
|
|
|
{
|
|
|
|
namespace cont
|
|
|
|
{
|
|
|
|
|
|
|
|
template <typename ValueType>
|
|
|
|
struct SerializableTypeString<vtkm::cont::ArrayHandleSOA<ValueType>>
|
|
|
|
{
|
|
|
|
static VTKM_CONT const std::string& Get()
|
|
|
|
{
|
|
|
|
static std::string name = "AH_SOA<" + SerializableTypeString<ValueType>::Get() + ">";
|
|
|
|
return name;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
template <typename ValueType>
|
|
|
|
struct SerializableTypeString<vtkm::cont::ArrayHandle<ValueType, vtkm::cont::StorageTagSOA>>
|
|
|
|
: SerializableTypeString<vtkm::cont::ArrayHandleSOA<ValueType>>
|
|
|
|
{
|
|
|
|
};
|
|
|
|
}
|
|
|
|
} // namespace vtkm::cont
|
|
|
|
|
|
|
|
namespace mangled_diy_namespace
|
|
|
|
{
|
|
|
|
|
|
|
|
template <typename ValueType>
|
|
|
|
struct Serialization<vtkm::cont::ArrayHandleSOA<ValueType>>
|
|
|
|
{
|
|
|
|
using BaseType = vtkm::cont::ArrayHandle<ValueType, vtkm::cont::StorageTagSOA>;
|
2020-08-13 14:32:58 +00:00
|
|
|
static constexpr vtkm::IdComponent NUM_COMPONENTS = vtkm::VecTraits<ValueType>::NUM_COMPONENTS;
|
2019-08-06 00:15:21 +00:00
|
|
|
|
|
|
|
static VTKM_CONT void save(BinaryBuffer& bb, const BaseType& obj)
|
|
|
|
{
|
|
|
|
for (vtkm::IdComponent componentIndex = 0; componentIndex < NUM_COMPONENTS; ++componentIndex)
|
|
|
|
{
|
2020-08-13 14:32:58 +00:00
|
|
|
vtkmdiy::save(bb, obj.GetBuffers()[componentIndex]);
|
2019-08-06 00:15:21 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static VTKM_CONT void load(BinaryBuffer& bb, BaseType& obj)
|
|
|
|
{
|
2020-08-13 14:32:58 +00:00
|
|
|
std::vector<vtkm::cont::internal::Buffer> buffers(NUM_COMPONENTS);
|
|
|
|
for (std::size_t componentIndex = 0; componentIndex < NUM_COMPONENTS; ++componentIndex)
|
2019-08-06 00:15:21 +00:00
|
|
|
{
|
2020-08-13 14:32:58 +00:00
|
|
|
vtkmdiy::load(bb, buffers[componentIndex]);
|
2019-08-06 00:15:21 +00:00
|
|
|
}
|
2020-08-13 14:32:58 +00:00
|
|
|
obj = BaseType(buffers);
|
2019-08-06 00:15:21 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
template <typename ValueType>
|
|
|
|
struct Serialization<vtkm::cont::ArrayHandle<ValueType, vtkm::cont::StorageTagSOA>>
|
|
|
|
: Serialization<vtkm::cont::ArrayHandleSOA<ValueType>>
|
|
|
|
{
|
|
|
|
};
|
|
|
|
|
|
|
|
} // namespace mangled_diy_namespace
|
2020-03-23 23:55:46 +00:00
|
|
|
// @endcond SERIALIZATION
|
2019-08-06 00:15:21 +00:00
|
|
|
|
|
|
|
//=============================================================================
|
|
|
|
// Precompiled instances
|
|
|
|
|
|
|
|
#ifndef vtkm_cont_ArrayHandleSOA_cxx
|
|
|
|
|
|
|
|
namespace vtkm
|
|
|
|
{
|
|
|
|
namespace cont
|
|
|
|
{
|
|
|
|
|
2020-08-17 14:18:24 +00:00
|
|
|
#define VTKM_ARRAYHANDLE_SOA_EXPORT(Type) \
|
|
|
|
extern template class VTKM_CONT_TEMPLATE_EXPORT ArrayHandle<vtkm::Vec<Type, 2>, StorageTagSOA>; \
|
|
|
|
extern template class VTKM_CONT_TEMPLATE_EXPORT ArrayHandle<vtkm::Vec<Type, 3>, StorageTagSOA>; \
|
2019-08-06 00:15:21 +00:00
|
|
|
extern template class VTKM_CONT_TEMPLATE_EXPORT ArrayHandle<vtkm::Vec<Type, 4>, StorageTagSOA>;
|
|
|
|
|
|
|
|
VTKM_ARRAYHANDLE_SOA_EXPORT(char)
|
|
|
|
VTKM_ARRAYHANDLE_SOA_EXPORT(vtkm::Int8)
|
|
|
|
VTKM_ARRAYHANDLE_SOA_EXPORT(vtkm::UInt8)
|
|
|
|
VTKM_ARRAYHANDLE_SOA_EXPORT(vtkm::Int16)
|
|
|
|
VTKM_ARRAYHANDLE_SOA_EXPORT(vtkm::UInt16)
|
|
|
|
VTKM_ARRAYHANDLE_SOA_EXPORT(vtkm::Int32)
|
|
|
|
VTKM_ARRAYHANDLE_SOA_EXPORT(vtkm::UInt32)
|
|
|
|
VTKM_ARRAYHANDLE_SOA_EXPORT(vtkm::Int64)
|
|
|
|
VTKM_ARRAYHANDLE_SOA_EXPORT(vtkm::UInt64)
|
|
|
|
VTKM_ARRAYHANDLE_SOA_EXPORT(vtkm::Float32)
|
|
|
|
VTKM_ARRAYHANDLE_SOA_EXPORT(vtkm::Float64)
|
|
|
|
|
|
|
|
#undef VTKM_ARRAYHANDLE_SOA_EXPORT
|
|
|
|
}
|
|
|
|
} // namespace vtkm::cont
|
|
|
|
|
|
|
|
#endif // !vtkm_cont_ArrayHandleSOA_cxx
|
|
|
|
|
|
|
|
#endif //vtk_m_cont_ArrayHandleSOA_h
|