vtk-m/vtkm/cont/ArrayHandleCompositeVector.h

704 lines
26 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.
//
// Copyright 2014 Sandia Corporation.
// Copyright 2014 UT-Battelle, LLC.
// Copyright 2014 Los Alamos National Security.
//
// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
// the U.S. Government retains certain rights in this software.
//
// Under the terms of Contract DE-AC52-06NA25396 with Los Alamos National
// Laboratory (LANL), the U.S. Government retains certain rights in
// this software.
//============================================================================
#ifndef vtk_m_ArrayHandleCompositeVector_h
#define vtk_m_ArrayHandleCompositeVector_h
#include <vtkm/cont/ArrayHandle.h>
#include <vtkm/cont/ErrorBadValue.h>
#include <vtkm/cont/ErrorInternal.h>
#include <vtkm/StaticAssert.h>
#include <vtkm/VecTraits.h>
#include <vtkm/internal/FunctionInterface.h>
#include <sstream>
namespace vtkm
{
namespace cont
{
namespace internal
{
namespace detail
{
template <typename ValueType>
struct VTKM_ALWAYS_EXPORT CompositeVectorSwizzleFunctor
{
static const vtkm::IdComponent NUM_COMPONENTS = vtkm::VecTraits<ValueType>::NUM_COMPONENTS;
using ComponentMapType = vtkm::Vec<vtkm::IdComponent, NUM_COMPONENTS>;
// Caution! This is a reference.
const ComponentMapType& SourceComponents;
VTKM_EXEC_CONT
CompositeVectorSwizzleFunctor(const ComponentMapType& sourceComponents)
: SourceComponents(sourceComponents)
{
}
// Currently only supporting 1-4 components.
template <typename T1>
VTKM_EXEC_CONT ValueType operator()(const T1& p1) const
{
return ValueType(vtkm::VecTraits<T1>::GetComponent(p1, this->SourceComponents[0]));
}
template <typename T1, typename T2>
VTKM_EXEC_CONT ValueType operator()(const T1& p1, const T2& p2) const
{
return ValueType(vtkm::VecTraits<T1>::GetComponent(p1, this->SourceComponents[0]),
vtkm::VecTraits<T2>::GetComponent(p2, this->SourceComponents[1]));
}
template <typename T1, typename T2, typename T3>
VTKM_EXEC_CONT ValueType operator()(const T1& p1, const T2& p2, const T3& p3) const
{
return ValueType(vtkm::VecTraits<T1>::GetComponent(p1, this->SourceComponents[0]),
vtkm::VecTraits<T2>::GetComponent(p2, this->SourceComponents[1]),
vtkm::VecTraits<T3>::GetComponent(p3, this->SourceComponents[2]));
}
template <typename T1, typename T2, typename T3, typename T4>
VTKM_EXEC_CONT ValueType operator()(const T1& p1, const T2& p2, const T3& p3, const T4& p4) const
{
return ValueType(vtkm::VecTraits<T1>::GetComponent(p1, this->SourceComponents[0]),
vtkm::VecTraits<T2>::GetComponent(p2, this->SourceComponents[1]),
vtkm::VecTraits<T3>::GetComponent(p3, this->SourceComponents[2]),
vtkm::VecTraits<T4>::GetComponent(p4, this->SourceComponents[3]));
}
};
template <typename ReturnValueType>
struct VTKM_ALWAYS_EXPORT CompositeVectorPullValueFunctor
{
vtkm::Id Index;
VTKM_EXEC
CompositeVectorPullValueFunctor(vtkm::Id index)
: Index(index)
{
}
// This form is to pull values out of array arguments.
VTKM_SUPPRESS_EXEC_WARNINGS
template <typename PortalType>
VTKM_EXEC_CONT typename PortalType::ValueType operator()(const PortalType& portal) const
{
return portal.Get(this->Index);
}
// This form is an identity to pass the return value back.
VTKM_EXEC_CONT
const ReturnValueType& operator()(const ReturnValueType& value) const { return value; }
};
struct CompositeVectorArrayToPortalCont
{
template <typename ArrayHandleType, vtkm::IdComponent Index>
struct ReturnType
{
using type = typename ArrayHandleType::PortalConstControl;
};
template <typename ArrayHandleType, vtkm::IdComponent Index>
VTKM_CONT typename ReturnType<ArrayHandleType, Index>::type operator()(
const ArrayHandleType& array,
vtkm::internal::IndexTag<Index>) const
{
return array.GetPortalConstControl();
}
};
template <typename DeviceAdapterTag>
struct CompositeVectorArrayToPortalExec
{
template <typename ArrayHandleType, vtkm::IdComponent Index>
struct ReturnType
{
using type = typename ArrayHandleType::template ExecutionTypes<DeviceAdapterTag>::PortalConst;
};
template <typename ArrayHandleType, vtkm::IdComponent Index>
VTKM_CONT typename ReturnType<ArrayHandleType, Index>::type operator()(
const ArrayHandleType& array,
vtkm::internal::IndexTag<Index>) const
{
return array.PrepareForInput(DeviceAdapterTag());
}
};
struct CheckArraySizeFunctor
{
vtkm::Id ExpectedSize;
CheckArraySizeFunctor(vtkm::Id expectedSize)
: ExpectedSize(expectedSize)
{
}
template <typename T, vtkm::IdComponent Index>
void operator()(const T& a, vtkm::internal::IndexTag<Index>) const
{
if (a.GetNumberOfValues() != this->ExpectedSize)
{
std::stringstream message;
message << "All input arrays to ArrayHandleCompositeVector must be the same size.\n"
<< "Array " << Index - 1 << " has " << a.GetNumberOfValues() << ". Expected "
<< this->ExpectedSize << ".";
throw vtkm::cont::ErrorBadValue(message.str().c_str());
}
}
};
} // namespace detail
/// \brief A portal that gets values from components of other portals.
///
/// This is the portal used within ArrayHandleCompositeVector.
///
template <typename SignatureWithPortals>
class VTKM_ALWAYS_EXPORT ArrayPortalCompositeVector
{
using PortalTypes = vtkm::internal::FunctionInterface<SignatureWithPortals>;
public:
using ValueType = typename PortalTypes::ResultType;
static const vtkm::IdComponent NUM_COMPONENTS = vtkm::VecTraits<ValueType>::NUM_COMPONENTS;
// Used internally.
using ComponentMapType = vtkm::Vec<vtkm::IdComponent, NUM_COMPONENTS>;
VTKM_STATIC_ASSERT(NUM_COMPONENTS == PortalTypes::ARITY);
VTKM_SUPPRESS_EXEC_WARNINGS
VTKM_EXEC_CONT
ArrayPortalCompositeVector() {}
VTKM_SUPPRESS_EXEC_WARNINGS
VTKM_CONT
ArrayPortalCompositeVector(const PortalTypes portals,
vtkm::Vec<vtkm::IdComponent, NUM_COMPONENTS> sourceComponents)
: Portals(portals)
, SourceComponents(sourceComponents)
{
}
VTKM_SUPPRESS_EXEC_WARNINGS
VTKM_EXEC_CONT
vtkm::Id GetNumberOfValues() const
{
return this->Portals.template GetParameter<1>().GetNumberOfValues();
}
VTKM_SUPPRESS_EXEC_WARNINGS
VTKM_EXEC_CONT
ValueType Get(vtkm::Id index) const
{
// This might be inefficient because we are copying all the portals only
// because they are coupled with the return value.
PortalTypes localPortals = this->Portals;
localPortals.InvokeExec(
detail::CompositeVectorSwizzleFunctor<ValueType>(this->SourceComponents),
detail::CompositeVectorPullValueFunctor<ValueType>(index));
return localPortals.GetReturnValue();
}
VTKM_SUPPRESS_EXEC_WARNINGS
VTKM_EXEC_CONT
void Set(vtkm::Id vtkmNotUsed(index), const ValueType& vtkmNotUsed(value)) const
{
// There is no technical reason why this cannot be implemented. As of this
// writing no one has needed to write to a composite vector yet.
VTKM_ASSERT(false &&
"Set not yet implemented for composite vector. Do you volunteer to implement it?");
}
private:
PortalTypes Portals;
ComponentMapType SourceComponents;
};
template <typename SignatureWithArrays>
struct VTKM_ALWAYS_EXPORT StorageTagCompositeVector
{
};
/// A convenience class that provides a typedef to the appropriate tag for
/// a composite storage.
template <typename SignatureWithArrays>
struct ArrayHandleCompositeVectorTraits
{
using Tag = vtkm::cont::internal::StorageTagCompositeVector<SignatureWithArrays>;
using ValueType = typename vtkm::internal::FunctionInterface<SignatureWithArrays>::ResultType;
using StorageType = vtkm::cont::internal::Storage<ValueType, Tag>;
using Superclass = vtkm::cont::ArrayHandle<ValueType, Tag>;
};
// It may seem weird that this specialization throws an exception for
// everything, but that is because all the functionality is handled in the
// ArrayTransfer class.
template <typename SignatureWithArrays>
class Storage<typename ArrayHandleCompositeVectorTraits<SignatureWithArrays>::ValueType,
vtkm::cont::internal::StorageTagCompositeVector<SignatureWithArrays>>
{
using FunctionInterfaceWithArrays = vtkm::internal::FunctionInterface<SignatureWithArrays>;
static const vtkm::IdComponent NUM_COMPONENTS = FunctionInterfaceWithArrays::ARITY;
using ComponentMapType = vtkm::Vec<vtkm::IdComponent, NUM_COMPONENTS>;
using FunctionInterfaceWithPortals =
typename FunctionInterfaceWithArrays::template StaticTransformType<
detail::CompositeVectorArrayToPortalCont>::type;
using SignatureWithPortals = typename FunctionInterfaceWithPortals::Signature;
public:
using PortalType = ArrayPortalCompositeVector<SignatureWithPortals>;
using PortalConstType = PortalType;
using ValueType = typename PortalType::ValueType;
VTKM_CONT
Storage()
: Valid(false)
{
}
VTKM_CONT
Storage(const FunctionInterfaceWithArrays& arrays, const ComponentMapType& sourceComponents)
: Arrays(arrays)
, SourceComponents(sourceComponents)
, Valid(true)
{
arrays.ForEachCont(detail::CheckArraySizeFunctor(this->GetNumberOfValues()));
}
VTKM_CONT
PortalType GetPortal()
{
throw vtkm::cont::ErrorBadValue("Composite vector arrays are read only.");
}
VTKM_CONT
PortalConstType GetPortalConst() const
{
if (!this->Valid)
{
throw vtkm::cont::ErrorBadValue(
"Tried to use an ArrayHandleCompositeHandle without dependent arrays.");
}
return PortalConstType(
this->Arrays.StaticTransformCont(detail::CompositeVectorArrayToPortalCont()),
this->SourceComponents);
}
VTKM_CONT
vtkm::Id GetNumberOfValues() const
{
if (!this->Valid)
{
throw vtkm::cont::ErrorBadValue(
"Tried to use an ArrayHandleCompositeHandle without dependent arrays.");
}
return this->Arrays.template GetParameter<1>().GetNumberOfValues();
}
VTKM_CONT
void Allocate(vtkm::Id vtkmNotUsed(numberOfValues))
{
throw vtkm::cont::ErrorInternal(
"The allocate method for the composite vector storage should never "
"have been called. The allocate is generally only called by the "
"execution array manager, and the array transfer for the composite "
"storage should prevent the execution array manager from being "
"directly used.");
}
VTKM_CONT
void Shrink(vtkm::Id vtkmNotUsed(numberOfValues))
{
throw vtkm::cont::ErrorBadValue("Composite vector arrays are read-only.");
}
VTKM_CONT
void ReleaseResources()
{
if (this->Valid)
{
// TODO: Implement this.
}
}
VTKM_CONT
const FunctionInterfaceWithArrays& GetArrays() const
{
VTKM_ASSERT(this->Valid);
return this->Arrays;
}
VTKM_CONT
const ComponentMapType& GetSourceComponents() const
{
VTKM_ASSERT(this->Valid);
return this->SourceComponents;
}
private:
FunctionInterfaceWithArrays Arrays;
ComponentMapType SourceComponents;
bool Valid;
};
template <typename SignatureWithArrays, typename DeviceAdapterTag>
class ArrayTransfer<typename ArrayHandleCompositeVectorTraits<SignatureWithArrays>::ValueType,
vtkm::cont::internal::StorageTagCompositeVector<SignatureWithArrays>,
DeviceAdapterTag>
{
VTKM_IS_DEVICE_ADAPTER_TAG(DeviceAdapterTag);
using StorageType = typename ArrayHandleCompositeVectorTraits<SignatureWithArrays>::StorageType;
using FunctionWithArrays = vtkm::internal::FunctionInterface<SignatureWithArrays>;
using FunctionWithPortals = typename FunctionWithArrays::template StaticTransformType<
detail::CompositeVectorArrayToPortalExec<DeviceAdapterTag>>::type;
using SignatureWithPortals = typename FunctionWithPortals::Signature;
public:
using ValueType = typename ArrayHandleCompositeVectorTraits<SignatureWithArrays>::ValueType;
// These are not currently fully implemented.
using PortalControl = typename StorageType::PortalType;
using PortalConstControl = typename StorageType::PortalConstType;
using PortalExecution = ArrayPortalCompositeVector<SignatureWithPortals>;
using PortalConstExecution = ArrayPortalCompositeVector<SignatureWithPortals>;
VTKM_CONT
ArrayTransfer(StorageType* storage)
: Storage(storage)
{
}
VTKM_CONT
vtkm::Id GetNumberOfValues() const { return this->Storage->GetNumberOfValues(); }
VTKM_CONT
PortalConstExecution PrepareForInput(bool vtkmNotUsed(updateData)) const
{
return PortalConstExecution(this->Storage->GetArrays().StaticTransformCont(
detail::CompositeVectorArrayToPortalExec<DeviceAdapterTag>()),
this->Storage->GetSourceComponents());
}
VTKM_CONT
PortalExecution PrepareForInPlace(bool vtkmNotUsed(updateData))
{
// It may be the case a composite vector could be used for in place
// operations, but this is not implemented currently.
throw vtkm::cont::ErrorBadValue(
"Composite vector arrays cannot be used for output or in place.");
}
VTKM_CONT
PortalExecution PrepareForOutput(vtkm::Id vtkmNotUsed(numberOfValues))
{
// It may be the case a composite vector could be used for output if you
// want the delegate arrays to be resized, but this is not implemented
// currently.
throw vtkm::cont::ErrorBadValue("Composite vector arrays cannot be used for output.");
}
VTKM_CONT
void RetrieveOutputData(StorageType* vtkmNotUsed(storage)) const
{
throw vtkm::cont::ErrorBadValue("Composite vector arrays cannot be used for output.");
}
VTKM_CONT
void Shrink(vtkm::Id vtkmNotUsed(numberOfValues))
{
throw vtkm::cont::ErrorBadValue("Composite vector arrays cannot be resized.");
}
VTKM_CONT
void ReleaseResources() { this->Storage->ReleaseResources(); }
private:
StorageType* Storage;
};
} // namespace internal
/// \brief An \c ArrayHandle that combines components from other arrays.
///
/// \c ArrayHandleCompositeVector is a specialization of \c ArrayHandle that
/// derives its content from other arrays. It takes up to 4 other \c
/// ArrayHandle objects and mimics an array that contains vectors with
/// components that come from these delegate arrays.
///
/// The easiest way to create and type an \c ArrayHandleCompositeVector is
/// to use the \c make_ArrayHandleCompositeVector functions.
///
template <typename Signature>
class ArrayHandleCompositeVector
: public internal::ArrayHandleCompositeVectorTraits<Signature>::Superclass
{
using StorageType = typename internal::ArrayHandleCompositeVectorTraits<Signature>::StorageType;
using ComponentMapType =
typename internal::ArrayPortalCompositeVector<Signature>::ComponentMapType;
public:
VTKM_ARRAY_HANDLE_SUBCLASS(
ArrayHandleCompositeVector,
(ArrayHandleCompositeVector<Signature>),
(typename internal::ArrayHandleCompositeVectorTraits<Signature>::Superclass));
VTKM_CONT
ArrayHandleCompositeVector(const vtkm::internal::FunctionInterface<Signature>& arrays,
const ComponentMapType& sourceComponents)
: Superclass(StorageType(arrays, sourceComponents))
{
}
/// Template constructors for passing in types. You'll get weird compile
/// errors if the argument types do not actually match the types in the
/// signature.
///
template <typename ArrayHandleType1>
VTKM_CONT ArrayHandleCompositeVector(const ArrayHandleType1& array1,
vtkm::IdComponent sourceComponent1)
: Superclass(StorageType(vtkm::internal::make_FunctionInterface<ValueType>(array1),
ComponentMapType(sourceComponent1)))
{
}
template <typename ArrayHandleType1, typename ArrayHandleType2>
VTKM_CONT ArrayHandleCompositeVector(const ArrayHandleType1& array1,
vtkm::IdComponent sourceComponent1,
const ArrayHandleType2& array2,
vtkm::IdComponent sourceComponent2)
: Superclass(StorageType(vtkm::internal::make_FunctionInterface<ValueType>(array1, array2),
ComponentMapType(sourceComponent1, sourceComponent2)))
{
}
template <typename ArrayHandleType1, typename ArrayHandleType2, typename ArrayHandleType3>
VTKM_CONT ArrayHandleCompositeVector(const ArrayHandleType1& array1,
vtkm::IdComponent sourceComponent1,
const ArrayHandleType2& array2,
vtkm::IdComponent sourceComponent2,
const ArrayHandleType3& array3,
vtkm::IdComponent sourceComponent3)
: Superclass(
StorageType(vtkm::internal::make_FunctionInterface<ValueType>(array1, array2, array3),
ComponentMapType(sourceComponent1, sourceComponent2, sourceComponent3)))
{
}
template <typename ArrayHandleType1,
typename ArrayHandleType2,
typename ArrayHandleType3,
typename ArrayHandleType4>
VTKM_CONT ArrayHandleCompositeVector(const ArrayHandleType1& array1,
vtkm::IdComponent sourceComponent1,
const ArrayHandleType2& array2,
vtkm::IdComponent sourceComponent2,
const ArrayHandleType3& array3,
vtkm::IdComponent sourceComponent3,
const ArrayHandleType4& array4,
vtkm::IdComponent sourceComponent4)
: Superclass(StorageType(
vtkm::internal::make_FunctionInterface<ValueType>(array1, array2, array3, array4),
ComponentMapType(sourceComponent1, sourceComponent2, sourceComponent3, sourceComponent4)))
{
}
};
/// \brief Get the type for an ArrayHandleCompositeVector
///
/// The ArrayHandleCompositeVector has a difficult template specification.
/// Use this helper template to covert a list of array handle types to a
/// composite vector of these array handles. Here is a simple example.
///
/// \code{.cpp}
/// typedef vtkm::cont::ArrayHandleCompositeVector<
/// vtkm::cont::ArrayHandle<vtkm::FloatDefault>,
/// vtkm::cont::ArrayHandle<vtkm::FloatDefault> >::type OutArrayType;
/// OutArrayType outArray = vtkm::cont::make_ArrayHandleCompositeVector(a1,a2);
/// \endcode
///
template <typename ArrayHandleType1,
typename ArrayHandleType2 = void,
typename ArrayHandleType3 = void,
typename ArrayHandleType4 = void>
struct ArrayHandleCompositeVectorType
{
VTKM_IS_ARRAY_HANDLE(ArrayHandleType1);
VTKM_IS_ARRAY_HANDLE(ArrayHandleType2);
VTKM_IS_ARRAY_HANDLE(ArrayHandleType3);
VTKM_IS_ARRAY_HANDLE(ArrayHandleType4);
private:
using ComponentType =
typename vtkm::VecTraits<typename ArrayHandleType1::ValueType>::ComponentType;
typedef vtkm::Vec<ComponentType, 4> Signature(ArrayHandleType1,
ArrayHandleType2,
ArrayHandleType3,
ArrayHandleType4);
public:
using type = vtkm::cont::ArrayHandleCompositeVector<Signature>;
};
template <typename ArrayHandleType1, typename ArrayHandleType2, typename ArrayHandleType3>
struct ArrayHandleCompositeVectorType<ArrayHandleType1, ArrayHandleType2, ArrayHandleType3>
{
VTKM_IS_ARRAY_HANDLE(ArrayHandleType1);
VTKM_IS_ARRAY_HANDLE(ArrayHandleType2);
VTKM_IS_ARRAY_HANDLE(ArrayHandleType3);
private:
using ComponentType =
typename vtkm::VecTraits<typename ArrayHandleType1::ValueType>::ComponentType;
typedef vtkm::Vec<ComponentType, 3> Signature(ArrayHandleType1,
ArrayHandleType2,
ArrayHandleType3);
public:
using type = vtkm::cont::ArrayHandleCompositeVector<Signature>;
};
template <typename ArrayHandleType1, typename ArrayHandleType2>
struct ArrayHandleCompositeVectorType<ArrayHandleType1, ArrayHandleType2>
{
VTKM_IS_ARRAY_HANDLE(ArrayHandleType1);
VTKM_IS_ARRAY_HANDLE(ArrayHandleType2);
private:
using ComponentType =
typename vtkm::VecTraits<typename ArrayHandleType1::ValueType>::ComponentType;
typedef vtkm::Vec<ComponentType, 2> Signature(ArrayHandleType1, ArrayHandleType2);
public:
using type = vtkm::cont::ArrayHandleCompositeVector<Signature>;
};
template <typename ArrayHandleType1>
struct ArrayHandleCompositeVectorType<ArrayHandleType1>
{
VTKM_IS_ARRAY_HANDLE(ArrayHandleType1);
private:
using ComponentType =
typename vtkm::VecTraits<typename ArrayHandleType1::ValueType>::ComponentType;
typedef ComponentType Signature(ArrayHandleType1);
public:
using type = vtkm::cont::ArrayHandleCompositeVector<Signature>;
};
// clang-format off
/// Create a composite vector array from other arrays.
///
template <typename ValueType1, typename Storage1>
VTKM_CONT
typename ArrayHandleCompositeVectorType<vtkm::cont::ArrayHandle<ValueType1, Storage1>>::type
make_ArrayHandleCompositeVector(const vtkm::cont::ArrayHandle<ValueType1, Storage1>& array1,
vtkm::IdComponent sourceComponent1)
{
return
typename ArrayHandleCompositeVectorType<vtkm::cont::ArrayHandle<ValueType1, Storage1>>::type(
array1, sourceComponent1);
}
// clang-format on
template <typename ArrayHandleType1>
VTKM_CONT typename ArrayHandleCompositeVectorType<ArrayHandleType1>::type
make_ArrayHandleCompositeVector(const ArrayHandleType1& array1, vtkm::IdComponent sourceComponent1)
{
VTKM_IS_ARRAY_HANDLE(ArrayHandleType1);
return typename ArrayHandleCompositeVectorType<ArrayHandleType1>::type(array1, sourceComponent1);
}
template <typename ArrayHandleType1, typename ArrayHandleType2>
VTKM_CONT typename ArrayHandleCompositeVectorType<ArrayHandleType1, ArrayHandleType2>::type
make_ArrayHandleCompositeVector(const ArrayHandleType1& array1,
vtkm::IdComponent sourceComponent1,
const ArrayHandleType2& array2,
vtkm::IdComponent sourceComponent2)
{
VTKM_IS_ARRAY_HANDLE(ArrayHandleType1);
VTKM_IS_ARRAY_HANDLE(ArrayHandleType2);
return typename ArrayHandleCompositeVectorType<ArrayHandleType1, ArrayHandleType2>::type(
array1, sourceComponent1, array2, sourceComponent2);
}
template <typename ArrayHandleType1, typename ArrayHandleType2, typename ArrayHandleType3>
VTKM_CONT typename ArrayHandleCompositeVectorType<ArrayHandleType1,
ArrayHandleType2,
ArrayHandleType3>::type
make_ArrayHandleCompositeVector(const ArrayHandleType1& array1,
vtkm::IdComponent sourceComponent1,
const ArrayHandleType2& array2,
vtkm::IdComponent sourceComponent2,
const ArrayHandleType3& array3,
vtkm::IdComponent sourceComponent3)
{
VTKM_IS_ARRAY_HANDLE(ArrayHandleType1);
VTKM_IS_ARRAY_HANDLE(ArrayHandleType2);
VTKM_IS_ARRAY_HANDLE(ArrayHandleType3);
return
typename ArrayHandleCompositeVectorType<ArrayHandleType1, ArrayHandleType2, ArrayHandleType3>::
type(array1, sourceComponent1, array2, sourceComponent2, array3, sourceComponent3);
}
template <typename ArrayHandleType1,
typename ArrayHandleType2,
typename ArrayHandleType3,
typename ArrayHandleType4>
VTKM_CONT typename ArrayHandleCompositeVectorType<ArrayHandleType1,
ArrayHandleType2,
ArrayHandleType3,
ArrayHandleType4>::type
make_ArrayHandleCompositeVector(const ArrayHandleType1& array1,
vtkm::IdComponent sourceComponent1,
const ArrayHandleType2& array2,
vtkm::IdComponent sourceComponent2,
const ArrayHandleType3& array3,
vtkm::IdComponent sourceComponent3,
const ArrayHandleType4& array4,
vtkm::IdComponent sourceComponent4)
{
VTKM_IS_ARRAY_HANDLE(ArrayHandleType1);
VTKM_IS_ARRAY_HANDLE(ArrayHandleType2);
VTKM_IS_ARRAY_HANDLE(ArrayHandleType3);
VTKM_IS_ARRAY_HANDLE(ArrayHandleType4);
return typename ArrayHandleCompositeVectorType<ArrayHandleType1,
ArrayHandleType2,
ArrayHandleType3,
ArrayHandleType4>::type(array1,
sourceComponent1,
array2,
sourceComponent2,
array3,
sourceComponent3,
array4,
sourceComponent4);
}
}
} // namespace vtkm::cont
#endif //vtk_m_ArrayHandleCompositeVector_h