vtk-m/vtkm/cont/ArrayHandleZip.h

456 lines
14 KiB
C
Raw Normal View History

//============================================================================
// 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_cont_ArrayHandleZip_h
#define vtk_m_cont_ArrayHandleZip_h
#include <vtkm/Pair.h>
2017-05-18 14:51:24 +00:00
#include <vtkm/cont/ArrayHandle.h>
#include <vtkm/internal/ArrayPortalHelpers.h>
2017-05-18 14:29:41 +00:00
namespace vtkm
{
namespace exec
{
namespace internal
{
/// \brief An array portal that zips two portals together into a single value
/// for the execution environment
2017-05-18 14:29:41 +00:00
template <typename ValueType_, typename PortalTypeFirst_, typename PortalTypeSecond_>
class ArrayPortalZip
{
public:
using ValueType = ValueType_;
using T = typename ValueType::FirstType;
using U = typename ValueType::SecondType;
using IteratorType = ValueType_;
using PortalTypeFirst = PortalTypeFirst_;
using PortalTypeSecond = PortalTypeSecond_;
VTKM_SUPPRESS_EXEC_WARNINGS
VTKM_EXEC_CONT
ArrayPortalZip()
2017-05-18 14:29:41 +00:00
: PortalFirst()
, PortalSecond()
{
} //needs to be host and device so that cuda can create lvalue of these
VTKM_CONT
2017-05-18 14:29:41 +00:00
ArrayPortalZip(const PortalTypeFirst& portalfirst, const PortalTypeSecond& portalsecond)
: PortalFirst(portalfirst)
, PortalSecond(portalsecond)
{
}
/// Copy constructor for any other ArrayPortalZip with an iterator
/// type that can be copied to this iterator type. This allows us to do any
/// type casting that the iterators do (like the non-const to const cast).
///
2017-05-18 14:29:41 +00:00
template <class OtherV, class OtherF, class OtherS>
VTKM_CONT ArrayPortalZip(const ArrayPortalZip<OtherV, OtherF, OtherS>& src)
: PortalFirst(src.GetFirstPortal())
, PortalSecond(src.GetSecondPortal())
{
}
VTKM_EXEC_CONT
vtkm::Id GetNumberOfValues() const { return this->PortalFirst.GetNumberOfValues(); }
VTKM_EXEC
2017-05-18 14:29:41 +00:00
ValueType Get(vtkm::Id index) const
{
using call_supported_t1 = typename vtkm::internal::PortalSupportsGets<PortalTypeFirst>::type;
using call_supported_t2 = typename vtkm::internal::PortalSupportsGets<PortalTypeSecond>::type;
return vtkm::make_Pair(this->GetFirst(call_supported_t1(), index),
this->GetSecond(call_supported_t2(), index));
}
VTKM_EXEC
2017-05-18 14:29:41 +00:00
void Set(vtkm::Id index, const ValueType& value) const
{
using call_supported_t1 = typename vtkm::internal::PortalSupportsSets<PortalTypeFirst>::type;
using call_supported_t2 = typename vtkm::internal::PortalSupportsSets<PortalTypeSecond>::type;
this->SetFirst(call_supported_t1(), index, value.first);
this->SetSecond(call_supported_t2(), index, value.second);
}
VTKM_EXEC_CONT
2017-05-18 14:29:41 +00:00
const PortalTypeFirst& GetFirstPortal() const { return this->PortalFirst; }
VTKM_EXEC_CONT
2017-05-18 14:29:41 +00:00
const PortalTypeSecond& GetSecondPortal() const { return this->PortalSecond; }
private:
VTKM_EXEC inline T GetFirst(std::true_type, vtkm::Id index) const noexcept
{
return this->PortalFirst.Get(index);
}
VTKM_EXEC inline T GetFirst(std::false_type, vtkm::Id) const noexcept { return T{}; }
VTKM_EXEC inline U GetSecond(std::true_type, vtkm::Id index) const noexcept
{
return this->PortalSecond.Get(index);
}
VTKM_EXEC inline U GetSecond(std::false_type, vtkm::Id) const noexcept { return U{}; }
VTKM_EXEC inline void SetFirst(std::true_type, vtkm::Id index, const T& value) const noexcept
{
this->PortalFirst.Set(index, value);
}
VTKM_EXEC inline void SetFirst(std::false_type, vtkm::Id, const T&) const noexcept {}
VTKM_EXEC inline void SetSecond(std::true_type, vtkm::Id index, const U& value) const noexcept
{
this->PortalSecond.Set(index, value);
}
VTKM_EXEC inline void SetSecond(std::false_type, vtkm::Id, const U&) const noexcept {}
PortalTypeFirst PortalFirst;
PortalTypeSecond PortalSecond;
};
}
}
} // namespace vtkm::exec::internal
2017-05-18 14:29:41 +00:00
namespace vtkm
{
namespace cont
{
2017-05-18 14:29:41 +00:00
namespace internal
{
2017-05-18 14:29:41 +00:00
template <typename FirstHandleType, typename SecondHandleType>
struct VTKM_ALWAYS_EXPORT StorageTagZip
{
};
/// This helper struct defines the value type for a zip container containing
/// the given two array handles.
///
2017-05-18 14:29:41 +00:00
template <typename FirstHandleType, typename SecondHandleType>
struct ArrayHandleZipTraits
{
/// The ValueType (a pair containing the value types of the two arrays).
///
using ValueType =
vtkm::Pair<typename FirstHandleType::ValueType, typename SecondHandleType::ValueType>;
/// The appropriately templated tag.
///
using Tag = StorageTagZip<FirstHandleType, SecondHandleType>;
/// The superclass for ArrayHandleZip.
///
using Superclass = vtkm::cont::ArrayHandle<ValueType, Tag>;
};
2018-06-08 15:56:40 +00:00
template <typename FirstHandleType, typename SecondHandleType>
class Storage<vtkm::Pair<typename FirstHandleType::ValueType, typename SecondHandleType::ValueType>,
StorageTagZip<FirstHandleType, SecondHandleType>>
{
VTKM_IS_ARRAY_HANDLE(FirstHandleType);
VTKM_IS_ARRAY_HANDLE(SecondHandleType);
public:
2018-06-08 15:56:40 +00:00
using ValueType =
vtkm::Pair<typename FirstHandleType::ValueType, typename SecondHandleType::ValueType>;
using PortalType = vtkm::exec::internal::ArrayPortalZip<ValueType,
typename FirstHandleType::PortalControl,
typename SecondHandleType::PortalControl>;
using PortalConstType =
vtkm::exec::internal::ArrayPortalZip<ValueType,
typename FirstHandleType::PortalConstControl,
typename SecondHandleType::PortalConstControl>;
VTKM_CONT
2017-05-18 14:29:41 +00:00
Storage()
: FirstArray()
, SecondArray()
{
}
VTKM_CONT
2017-05-18 14:29:41 +00:00
Storage(const FirstHandleType& farray, const SecondHandleType& sarray)
: FirstArray(farray)
, SecondArray(sarray)
{
}
VTKM_CONT
2017-05-18 14:29:41 +00:00
PortalType GetPortal()
{
return PortalType(this->FirstArray.GetPortalControl(), this->SecondArray.GetPortalControl());
}
VTKM_CONT
2017-05-18 14:29:41 +00:00
PortalConstType GetPortalConst() const
{
return PortalConstType(this->FirstArray.GetPortalConstControl(),
this->SecondArray.GetPortalConstControl());
}
VTKM_CONT
2017-05-18 14:29:41 +00:00
vtkm::Id GetNumberOfValues() const
{
VTKM_ASSERT(this->FirstArray.GetNumberOfValues() == this->SecondArray.GetNumberOfValues());
return this->FirstArray.GetNumberOfValues();
}
VTKM_CONT
2017-05-18 14:29:41 +00:00
void Allocate(vtkm::Id numberOfValues)
{
this->FirstArray.Allocate(numberOfValues);
this->SecondArray.Allocate(numberOfValues);
}
VTKM_CONT
2017-05-18 14:29:41 +00:00
void Shrink(vtkm::Id numberOfValues)
{
this->FirstArray.Shrink(numberOfValues);
this->SecondArray.Shrink(numberOfValues);
}
VTKM_CONT
2017-05-18 14:29:41 +00:00
void ReleaseResources()
{
// This request is ignored since it is asking to release the resources
// of the two zipped array, which may be used elsewhere.
}
VTKM_CONT
2017-05-18 14:29:41 +00:00
const FirstHandleType& GetFirstArray() const { return this->FirstArray; }
VTKM_CONT
2017-05-18 14:29:41 +00:00
const SecondHandleType& GetSecondArray() const { return this->SecondArray; }
private:
FirstHandleType FirstArray;
SecondHandleType SecondArray;
};
2018-06-08 15:56:40 +00:00
template <typename FirstHandleType, typename SecondHandleType, typename Device>
class ArrayTransfer<
vtkm::Pair<typename FirstHandleType::ValueType, typename SecondHandleType::ValueType>,
StorageTagZip<FirstHandleType, SecondHandleType>,
Device>
{
2018-06-08 15:56:40 +00:00
public:
using ValueType =
vtkm::Pair<typename FirstHandleType::ValueType, typename SecondHandleType::ValueType>;
private:
using StorageTag = StorageTagZip<FirstHandleType, SecondHandleType>;
2018-06-08 15:56:40 +00:00
using StorageType = vtkm::cont::internal::Storage<ValueType, StorageTag>;
public:
using PortalControl = typename StorageType::PortalType;
using PortalConstControl = typename StorageType::PortalConstType;
using PortalExecution = vtkm::exec::internal::ArrayPortalZip<
ValueType,
typename FirstHandleType::template ExecutionTypes<Device>::Portal,
typename SecondHandleType::template ExecutionTypes<Device>::Portal>;
using PortalConstExecution = vtkm::exec::internal::ArrayPortalZip<
ValueType,
typename FirstHandleType::template ExecutionTypes<Device>::PortalConst,
typename SecondHandleType::template ExecutionTypes<Device>::PortalConst>;
VTKM_CONT
2017-05-18 14:29:41 +00:00
ArrayTransfer(StorageType* storage)
: FirstArray(storage->GetFirstArray())
, SecondArray(storage->GetSecondArray())
{
}
VTKM_CONT
vtkm::Id GetNumberOfValues() const
{
2017-05-18 14:29:41 +00:00
VTKM_ASSERT(this->FirstArray.GetNumberOfValues() == this->SecondArray.GetNumberOfValues());
return this->FirstArray.GetNumberOfValues();
}
VTKM_CONT
2017-05-18 14:29:41 +00:00
PortalConstExecution PrepareForInput(bool vtkmNotUsed(updateData))
{
return PortalConstExecution(this->FirstArray.PrepareForInput(Device()),
this->SecondArray.PrepareForInput(Device()));
}
VTKM_CONT
2017-05-18 14:29:41 +00:00
PortalExecution PrepareForInPlace(bool vtkmNotUsed(updateData))
{
return PortalExecution(this->FirstArray.PrepareForInPlace(Device()),
this->SecondArray.PrepareForInPlace(Device()));
}
VTKM_CONT
PortalExecution PrepareForOutput(vtkm::Id numberOfValues)
{
2017-05-18 14:29:41 +00:00
return PortalExecution(this->FirstArray.PrepareForOutput(numberOfValues, Device()),
this->SecondArray.PrepareForOutput(numberOfValues, Device()));
}
VTKM_CONT
2017-05-18 14:29:41 +00:00
void RetrieveOutputData(StorageType* vtkmNotUsed(storage)) const
{
// Implementation of this method should be unnecessary. The internal
// first and second array handles should automatically retrieve the
// output data as necessary.
}
VTKM_CONT
2017-05-18 14:29:41 +00:00
void Shrink(vtkm::Id numberOfValues)
{
this->FirstArray.Shrink(numberOfValues);
this->SecondArray.Shrink(numberOfValues);
}
VTKM_CONT
2017-05-18 14:29:41 +00:00
void ReleaseResources()
{
this->FirstArray.ReleaseResourcesExecution();
this->SecondArray.ReleaseResourcesExecution();
}
private:
FirstHandleType FirstArray;
SecondHandleType SecondArray;
};
} // namespace internal
/// ArrayHandleZip is a specialization of ArrayHandle. It takes two delegate
/// array handle and makes a new handle that access the corresponding entries
/// in these arrays as a pair.
///
2017-05-18 14:29:41 +00:00
template <typename FirstHandleType, typename SecondHandleType>
class ArrayHandleZip
2017-05-18 14:29:41 +00:00
: public internal::ArrayHandleZipTraits<FirstHandleType, SecondHandleType>::Superclass
{
// If the following line gives a compile error, then the FirstHandleType
// template argument is not a valid ArrayHandle type.
VTKM_IS_ARRAY_HANDLE(FirstHandleType);
// If the following line gives a compile error, then the SecondHandleType
// template argument is not a valid ArrayHandle type.
VTKM_IS_ARRAY_HANDLE(SecondHandleType);
public:
VTKM_ARRAY_HANDLE_SUBCLASS(
ArrayHandleZip,
(ArrayHandleZip<FirstHandleType, SecondHandleType>),
2017-05-18 14:29:41 +00:00
(typename internal::ArrayHandleZipTraits<FirstHandleType, SecondHandleType>::Superclass));
private:
using StorageType = vtkm::cont::internal::Storage<ValueType, StorageTag>;
public:
VTKM_CONT
2017-05-18 14:29:41 +00:00
ArrayHandleZip(const FirstHandleType& firstArray, const SecondHandleType& secondArray)
: Superclass(StorageType(firstArray, secondArray))
{
}
};
/// A convenience function for creating an ArrayHandleZip. It takes the two
/// arrays to be zipped together.
///
2017-05-18 14:29:41 +00:00
template <typename FirstHandleType, typename SecondHandleType>
VTKM_CONT vtkm::cont::ArrayHandleZip<FirstHandleType, SecondHandleType> make_ArrayHandleZip(
const FirstHandleType& first,
const SecondHandleType& second)
{
2017-05-18 14:29:41 +00:00
return ArrayHandleZip<FirstHandleType, SecondHandleType>(first, second);
}
}
} // namespace vtkm::cont
2018-06-08 15:56:40 +00:00
//=============================================================================
// Specializations of serialization related classes
namespace vtkm
{
namespace cont
{
template <typename AH1, typename AH2>
struct TypeString<vtkm::cont::ArrayHandleZip<AH1, AH2>>
{
static VTKM_CONT const std::string& Get()
{
static std::string name =
"AH_Zip<" + TypeString<AH1>::Get() + "," + TypeString<AH2>::Get() + ">";
return name;
}
};
template <typename AH1, typename AH2>
struct TypeString<
vtkm::cont::ArrayHandle<vtkm::Pair<typename AH1::ValueType, typename AH2::ValueType>,
vtkm::cont::internal::StorageTagZip<AH1, AH2>>>
: TypeString<vtkm::cont::ArrayHandleZip<AH1, AH2>>
{
};
}
} // namespace vtkm::cont
namespace diy
{
template <typename AH1, typename AH2>
struct Serialization<vtkm::cont::ArrayHandleZip<AH1, AH2>>
{
private:
using Type = typename vtkm::cont::ArrayHandleZip<AH1, AH2>;
using BaseType = vtkm::cont::ArrayHandle<typename Type::ValueType, typename Type::StorageTag>;
public:
static VTKM_CONT void save(BinaryBuffer& bb, const BaseType& obj)
{
auto storage = obj.GetStorage();
diy::save(bb, storage.GetFirstArray());
diy::save(bb, storage.GetSecondArray());
}
static VTKM_CONT void load(BinaryBuffer& bb, BaseType& obj)
{
AH1 a1;
AH2 a2;
diy::load(bb, a1);
diy::load(bb, a2);
obj = vtkm::cont::make_ArrayHandleZip(a1, a2);
}
};
template <typename AH1, typename AH2>
struct Serialization<
vtkm::cont::ArrayHandle<vtkm::Pair<typename AH1::ValueType, typename AH2::ValueType>,
vtkm::cont::internal::StorageTagZip<AH1, AH2>>>
: Serialization<vtkm::cont::ArrayHandleZip<AH1, AH2>>
{
};
} // diy
#endif //vtk_m_cont_ArrayHandleZip_h