//============================================================================ // 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 National Technology & Engineering Solutions of Sandia, LLC (NTESS). // Copyright 2014 UT-Battelle, LLC. // Copyright 2014 Los Alamos National Security. // // Under the terms of Contract DE-NA0003525 with NTESS, // 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 #include #include #include #include namespace vtkm { namespace cont { namespace internal { namespace compvec { // AllAreArrayHandles: --------------------------------------------------------- // Ensures that all types in ArrayHandlesT... are subclasses of ArrayHandleBase template struct AllAreArrayHandlesImpl; template struct AllAreArrayHandlesImpl { private: using Next = AllAreArrayHandlesImpl; constexpr static bool HeadValid = std::is_base_of::value; public: constexpr static bool Value = HeadValid && Next::Value; }; template struct AllAreArrayHandlesImpl { constexpr static bool Value = std::is_base_of::value; }; template struct AllAreArrayHandles { constexpr static bool Value = AllAreArrayHandlesImpl::Value; }; // ParamsAreArrayHandles: ------------------------------------------------------ // Same as AllAreArrayHandles, but accepts a tuple. template struct ParamsAreArrayHandles { constexpr static bool Value = false; }; template struct ParamsAreArrayHandles> { constexpr static bool Value = AllAreArrayHandlesImpl::Value; }; // GetValueType: --------------------------------------------------------------- // Determines the output ValueType of the objects in TupleType, a vtkmstd::tuple // which can contain ArrayHandles, ArrayPortals...anything with a ValueType // defined, really. For example, if the input TupleType contains 3 types with // Float32 ValueTypes, then the ValueType defined here will be Vec. // This also validates that all members have the same ValueType. template struct GetValueTypeImpl; template struct GetValueTypeImpl> { using Type = typename Head::ValueType; private: using Next = GetValueTypeImpl>; VTKM_STATIC_ASSERT_MSG(VTKM_PASS_COMMAS(std::is_same::value), "ArrayHandleCompositeVector must be built from " "ArrayHandles with the same ValueTypes."); }; template struct GetValueTypeImpl> { using Type = typename Head::ValueType; }; template struct GetValueType { VTKM_STATIC_ASSERT(vtkmstd::tuple_size::value >= 1); static const vtkm::IdComponent COUNT = static_cast(vtkmstd::tuple_size::value); using ComponentType = typename GetValueTypeImpl::Type; using ValueType = vtkm::Vec; }; // TupleTypePrepend: ----------------------------------------------------------- // Prepend a type to a tuple, defining the new tuple in Type. template struct TupleTypePrepend; template struct TupleTypePrepend> { using Type = vtkmstd::tuple; }; // ArrayTupleForEach: ---------------------------------------------------------- // Collection of methods that iterate through the arrays in ArrayTuple to // implement the ArrayHandle API. template struct ArrayTupleForEach { using Next = ArrayTupleForEach; template VTKM_CONT static void GetPortalTupleControl(ArrayTuple& arrays, PortalTuple& portals) { vtkmstd::get(portals) = vtkmstd::get(arrays).GetPortalControl(); Next::GetPortalTupleControl(arrays, portals); } template VTKM_CONT static void GetPortalConstTupleControl(const ArrayTuple& arrays, PortalTuple& portals) { vtkmstd::get(portals) = vtkmstd::get(arrays).GetPortalConstControl(); Next::GetPortalConstTupleControl(arrays, portals); } template VTKM_CONT static void PrepareForInput(const ArrayTuple& arrays, PortalTuple& portals) { vtkmstd::get(portals) = vtkmstd::get(arrays).PrepareForInput(DeviceTag()); Next::template PrepareForInput(arrays, portals); } template VTKM_CONT static void PrepareForInPlace(ArrayTuple& arrays, PortalTuple& portals) { vtkmstd::get(portals) = vtkmstd::get(arrays).PrepareForInPlace(DeviceTag()); Next::template PrepareForInPlace(arrays, portals); } template VTKM_CONT static void PrepareForOutput(ArrayTuple& arrays, PortalTuple& portals, vtkm::Id numValues) { vtkmstd::get(portals) = vtkmstd::get(arrays).PrepareForOutput(numValues, DeviceTag()); Next::template PrepareForOutput(arrays, portals, numValues); } VTKM_CONT static void Allocate(ArrayTuple& arrays, vtkm::Id numValues) { vtkmstd::get(arrays).Allocate(numValues); Next::Allocate(arrays, numValues); } VTKM_CONT static void Shrink(ArrayTuple& arrays, vtkm::Id numValues) { vtkmstd::get(arrays).Shrink(numValues); Next::Shrink(arrays, numValues); } VTKM_CONT static void ReleaseResources(ArrayTuple& arrays) { vtkmstd::get(arrays).ReleaseResources(); Next::ReleaseResources(arrays); } }; template struct ArrayTupleForEach { template VTKM_CONT static void GetPortalTupleControl(ArrayTuple&, PortalTuple&) { } template VTKM_CONT static void GetPortalConstTupleControl(const ArrayTuple&, PortalTuple&) { } template VTKM_CONT static void PrepareForInput(const ArrayTuple&, PortalTuple&) { } template VTKM_CONT static void PrepareForInPlace(ArrayTuple&, PortalTuple&) { } template VTKM_CONT static void PrepareForOutput(ArrayTuple&, PortalTuple&, vtkm::Id) { } VTKM_CONT static void Allocate(ArrayTuple&, vtkm::Id) {} VTKM_CONT static void Shrink(ArrayTuple&, vtkm::Id) {} VTKM_CONT static void ReleaseResources(ArrayTuple&) {} }; // PortalTupleTraits: ---------------------------------------------------------- // Determine types of ArrayHandleCompositeVector portals and construct the // portals from the input arrays. template struct PortalTupleTypeGeneratorImpl; template struct PortalTupleTypeGeneratorImpl> { using Next = PortalTupleTypeGeneratorImpl>; using PortalControlTuple = typename TupleTypePrepend::Type; using PortalConstControlTuple = typename TupleTypePrepend::Type; template struct ExecutionTypes { using PortalTuple = typename TupleTypePrepend< typename Head::template ExecutionTypes::Portal, typename Next::template ExecutionTypes::PortalTuple>::Type; using PortalConstTuple = typename TupleTypePrepend< typename Head::template ExecutionTypes::PortalConst, typename Next::template ExecutionTypes::PortalConstTuple>::Type; }; }; template struct PortalTupleTypeGeneratorImpl> { using PortalControlTuple = vtkmstd::tuple; using PortalConstControlTuple = vtkmstd::tuple; template struct ExecutionTypes { using PortalTuple = vtkmstd::tuple::Portal>; using PortalConstTuple = vtkmstd::tuple::PortalConst>; }; }; template struct PortalTupleTraits { private: using TypeGenerator = PortalTupleTypeGeneratorImpl; using ForEachArray = ArrayTupleForEach<0, vtkmstd::tuple_size::value, ArrayTuple>; public: using PortalTuple = typename TypeGenerator::PortalControlTuple; using PortalConstTuple = typename TypeGenerator::PortalConstControlTuple; VTKM_STATIC_ASSERT(vtkmstd::tuple_size::value == vtkmstd::tuple_size::value); VTKM_STATIC_ASSERT(vtkmstd::tuple_size::value == vtkmstd::tuple_size::value); template struct ExecutionTypes { using PortalTuple = typename TypeGenerator::template ExecutionTypes::PortalTuple; using PortalConstTuple = typename TypeGenerator::template ExecutionTypes::PortalConstTuple; VTKM_STATIC_ASSERT(vtkmstd::tuple_size::value == vtkmstd::tuple_size::value); VTKM_STATIC_ASSERT(vtkmstd::tuple_size::value == vtkmstd::tuple_size::value); }; VTKM_CONT static const PortalTuple GetPortalTupleControl(ArrayTuple& arrays) { PortalTuple portals; ForEachArray::GetPortalTupleControl(arrays, portals); return portals; } VTKM_CONT static const PortalConstTuple GetPortalConstTupleControl(const ArrayTuple& arrays) { PortalConstTuple portals; ForEachArray::GetPortalConstTupleControl(arrays, portals); return portals; } template VTKM_CONT static const typename ExecutionTypes::PortalConstTuple PrepareForInput( const ArrayTuple& arrays) { typename ExecutionTypes::PortalConstTuple portals; ForEachArray::template PrepareForInput(arrays, portals); return portals; } template VTKM_CONT static const typename ExecutionTypes::PortalTuple PrepareForInPlace( ArrayTuple& arrays) { typename ExecutionTypes::PortalTuple portals; ForEachArray::template PrepareForInPlace(arrays, portals); return portals; } template VTKM_CONT static const typename ExecutionTypes::PortalTuple PrepareForOutput( ArrayTuple& arrays, vtkm::Id numValues) { typename ExecutionTypes::PortalTuple portals; ForEachArray::template PrepareForOutput(arrays, portals, numValues); return portals; } }; // ArraySizeValidator: --------------------------------------------------------- // Call Exec(ArrayTuple, NumValues) to ensure that all arrays in the tuple have // the specified number of values. template struct ArraySizeValidatorImpl { using Next = ArraySizeValidatorImpl; VTKM_EXEC_CONT static bool Exec(const TupleType& tuple, vtkm::Id numVals) { return vtkmstd::get(tuple).GetNumberOfValues() == numVals && Next::Exec(tuple, numVals); } }; template struct ArraySizeValidatorImpl { VTKM_EXEC_CONT static bool Exec(const TupleType&, vtkm::Id) { return true; } }; template struct ArraySizeValidator { VTKM_EXEC_CONT static bool Exec(const TupleType& tuple, vtkm::Id numVals) { return ArraySizeValidatorImpl<0, vtkmstd::tuple_size::value, TupleType>::Exec( tuple, numVals); } }; } // end namespace compvec template class VTKM_ALWAYS_EXPORT ArrayPortalCompositeVector { public: using ValueType = typename compvec::GetValueType::ValueType; private: using Traits = vtkm::VecTraits; // Get: ---------------------------------------------------------------------- template struct GetImpl; template struct GetImpl> { using Next = GetImpl>; VTKM_EXEC_CONT static void Exec(const PortalTuple& portals, ValueType& vec, vtkm::Id arrayIndex) { Traits::SetComponent(vec, VectorIndex, vtkmstd::get(portals).Get(arrayIndex)); Next::Exec(portals, vec, arrayIndex); } }; template struct GetImpl> { VTKM_EXEC_CONT static void Exec(const PortalTuple& portals, ValueType& vec, vtkm::Id arrayIndex) { Traits::SetComponent(vec, VectorIndex, vtkmstd::get(portals).Get(arrayIndex)); } }; // Set: ---------------------------------------------------------------------- template struct SetImpl; template struct SetImpl> { using Next = SetImpl>; VTKM_EXEC_CONT static void Exec(const PortalTuple& portals, const ValueType& vec, vtkm::Id arrayIndex) { vtkmstd::get(portals).Set(arrayIndex, Traits::GetComponent(vec, VectorIndex)); Next::Exec(portals, vec, arrayIndex); } }; template struct SetImpl> { VTKM_EXEC_CONT static void Exec(const PortalTuple& portals, const ValueType& vec, vtkm::Id arrayIndex) { vtkmstd::get(portals).Set(arrayIndex, Traits::GetComponent(vec, VectorIndex)); } }; public: VTKM_EXEC_CONT ArrayPortalCompositeVector() {} VTKM_CONT ArrayPortalCompositeVector(const PortalTuple& portals) : Portals(portals) { } VTKM_EXEC_CONT vtkm::Id GetNumberOfValues() const { return vtkmstd::get<0>(this->Portals).GetNumberOfValues(); } VTKM_EXEC_CONT ValueType Get(vtkm::Id index) const { ValueType result; GetImpl<0, PortalTuple>::Exec(this->Portals, result, index); return result; } VTKM_EXEC_CONT void Set(vtkm::Id index, const ValueType& value) const { SetImpl<0, PortalTuple>::Exec(this->Portals, value, index); } private: PortalTuple Portals; }; template struct VTKM_ALWAYS_EXPORT StorageTagCompositeVector { }; template class Storage::ValueType, StorageTagCompositeVector> { using ForEachArray = compvec::ArrayTupleForEach<0, vtkmstd::tuple_size::value, ArrayTuple>; using PortalTypes = compvec::PortalTupleTraits; using PortalTupleType = typename PortalTypes::PortalTuple; using PortalConstTupleType = typename PortalTypes::PortalConstTuple; public: using ValueType = typename compvec::GetValueType::ValueType; using PortalType = ArrayPortalCompositeVector; using PortalConstType = ArrayPortalCompositeVector; VTKM_CONT Storage() : Valid(false) { } VTKM_CONT Storage(const ArrayTuple& arrays) : Arrays(arrays) , Valid(true) { using SizeValidator = compvec::ArraySizeValidator; if (!SizeValidator::Exec(this->Arrays, this->GetNumberOfValues())) { throw ErrorBadValue("All arrays must have the same number of values."); } } VTKM_CONT PortalType GetPortal() { VTKM_ASSERT(this->Valid); return PortalType(PortalTypes::GetPortalTupleControl(this->Arrays)); } VTKM_CONT PortalConstType GetPortalConst() const { VTKM_ASSERT(this->Valid); return PortalConstType(PortalTypes::GetPortalConstTupleControl(this->Arrays)); } VTKM_CONT vtkm::Id GetNumberOfValues() const { VTKM_ASSERT(this->Valid); return vtkmstd::get<0>(this->Arrays).GetNumberOfValues(); } VTKM_CONT void Allocate(vtkm::Id numValues) { VTKM_ASSERT(this->Valid); return ForEachArray::Allocate(this->Arrays, numValues); } VTKM_CONT void Shrink(vtkm::Id numValues) { VTKM_ASSERT(this->Valid); return ForEachArray::Shrink(this->Arrays, numValues); } VTKM_CONT void ReleaseResources() { VTKM_ASSERT(this->Valid); return ForEachArray::ReleaseResources(this->Arrays); } VTKM_CONT const ArrayTuple& GetArrayTuple() const { VTKM_ASSERT(this->Valid); return this->Arrays; } VTKM_CONT ArrayTuple& GetArrayTuple() { VTKM_ASSERT(this->Valid); return this->Arrays; } private: ArrayTuple Arrays; bool Valid; }; template class ArrayTransfer::ValueType, StorageTagCompositeVector, DeviceTag> { VTKM_IS_DEVICE_ADAPTER_TAG(DeviceTag); public: using ValueType = typename compvec::GetValueType::ValueType; private: using ForEachArray = compvec::ArrayTupleForEach<0, vtkmstd::tuple_size::value, ArrayTuple>; using StorageTag = StorageTagCompositeVector; using StorageType = internal::Storage; using ControlTraits = compvec::PortalTupleTraits; using ExecutionTraits = typename ControlTraits::template ExecutionTypes; public: using PortalControl = ArrayPortalCompositeVector; using PortalConstControl = ArrayPortalCompositeVector; using PortalExecution = ArrayPortalCompositeVector; using PortalConstExecution = ArrayPortalCompositeVector; 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( ControlTraits::template PrepareForInput(this->GetArrayTuple())); } VTKM_CONT PortalExecution PrepareForInPlace(bool vtkmNotUsed(updateData)) { return PortalExecution( ControlTraits::template PrepareForInPlace(this->GetArrayTuple())); } VTKM_CONT PortalExecution PrepareForOutput(vtkm::Id numValues) { return PortalExecution( ControlTraits::template PrepareForOutput(this->GetArrayTuple(), numValues)); } VTKM_CONT void RetrieveOutputData(StorageType* vtkmNotUsed(storage)) const { // Implementation of this method should be unnecessary. The internal // array handle should automatically retrieve the output data as // necessary. } VTKM_CONT void Shrink(vtkm::Id numValues) { ForEachArray::Shrink(this->GetArrayTuple(), numValues); } VTKM_CONT void ReleaseResources() { ForEachArray::ReleaseResources(this->GetArrayTuple()); } VTKM_CONT const ArrayTuple& GetArrayTuple() const { return this->Storage->GetArrayTuple(); } ArrayTuple& GetArrayTuple() { return this->Storage->GetArrayTuple(); } private: StorageType* Storage; }; template struct CompositeVectorTraits { // Need to check this here, since this traits struct is used in the // ArrayHandleCompositeVector superclass definition before any other // static_asserts could be used. VTKM_STATIC_ASSERT_MSG(compvec::AllAreArrayHandles::Value, "Template parameters for ArrayHandleCompositeVector " "must be a list of ArrayHandle types."); using ValueType = typename compvec::GetValueType>::ValueType; using StorageTag = StorageTagCompositeVector>; using StorageType = Storage; using Superclass = ArrayHandle; }; } // 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 any number of /// single-component \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. /// /// The \c ArrayHandleExtractComponent class may be helpful when a desired /// component is part of an \c ArrayHandle with a \c vtkm::Vec \c ValueType. /// template class ArrayHandleCompositeVector : public ArrayHandle::ValueType, typename internal::CompositeVectorTraits::StorageTag> { private: using Traits = internal::CompositeVectorTraits; using TupleType = vtkmstd::tuple; using StorageType = typename Traits::StorageType; public: VTKM_ARRAY_HANDLE_SUBCLASS(ArrayHandleCompositeVector, (ArrayHandleCompositeVector), (typename Traits::Superclass)); VTKM_CONT ArrayHandleCompositeVector(const ArrayTs&... arrays) : Superclass(StorageType(vtkmstd::make_tuple(arrays...))) { } }; /// Create a composite vector array from other arrays. /// template VTKM_CONT ArrayHandleCompositeVector make_ArrayHandleCompositeVector( const ArrayTs&... arrays) { VTKM_STATIC_ASSERT_MSG(internal::compvec::AllAreArrayHandles::Value, "Arguments to make_ArrayHandleCompositeVector must be " "of ArrayHandle types."); return ArrayHandleCompositeVector(arrays...); } } } // namespace vtkm::cont //============================================================================= // Specializations of serialization related classes namespace vtkm { namespace cont { template struct TypeString> { static VTKM_CONT const std::string& Get() { static std::string name = "AH_CompositeVector<" + internal::GetVariadicTypeString(AHs{}...) + ">"; return name; } }; template struct TypeString>::ValueType, vtkm::cont::internal::StorageTagCompositeVector>>> : TypeString> { }; } } // vtkm::cont namespace mangled_diy_namespace { namespace internal { template inline void TupleForEachImpl(TupleType&& t, std::integral_constant, Functor&& f, Args&&... args) { f(vtkmstd::get<0>(t), std::forward(args)...); } template inline void TupleForEachImpl(TupleType&& t, std::integral_constant, Functor&& f, Args&&... args) { TupleForEachImpl(std::forward(t), std::integral_constant{}, std::forward(f), std::forward(args)...); f(vtkmstd::get(t), std::forward(args)...); } template inline void TupleForEach(TupleType&& t, Functor&& f, Args&&... args) { constexpr auto size = vtkmstd::tuple_size::type>::value; TupleForEachImpl(std::forward(t), std::integral_constant{}, std::forward(f), std::forward(args)...); } } // internal template struct Serialization> { private: using Type = typename vtkm::cont::ArrayHandleCompositeVector; using BaseType = vtkm::cont::ArrayHandle; struct SaveFunctor { template void operator()(const AH& ah, BinaryBuffer& bb) const { vtkmdiy::save(bb, ah); } }; struct LoadFunctor { template void operator()(AH& ah, BinaryBuffer& bb) const { vtkmdiy::load(bb, ah); } }; public: static VTKM_CONT void save(BinaryBuffer& bb, const BaseType& obj) { internal::TupleForEach(obj.GetStorage().GetArrayTuple(), SaveFunctor{}, bb); } static VTKM_CONT void load(BinaryBuffer& bb, BaseType& obj) { vtkmstd::tuple arrayTuple; internal::TupleForEach(arrayTuple, LoadFunctor{}, bb); obj = BaseType(typename BaseType::StorageType(arrayTuple)); } }; template struct Serialization>::ValueType, vtkm::cont::internal::StorageTagCompositeVector>>> : Serialization> { }; } // diy #endif //vtk_m_ArrayHandleCompositeVector_h