ec34cb56c4
Also fix deadlocks that occur when portals are not destroyed in time.
564 lines
17 KiB
C++
564 lines
17 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.
|
|
//============================================================================
|
|
#ifndef vtk_m_cont_ArrayHandleMultiplexer_h
|
|
#define vtk_m_cont_ArrayHandleMultiplexer_h
|
|
|
|
#include <vtkm/TypeTraits.h>
|
|
|
|
#include <vtkm/internal/Variant.h>
|
|
|
|
#include <vtkm/cont/ArrayHandle.h>
|
|
#include <vtkm/cont/ArrayHandleCartesianProduct.h>
|
|
#include <vtkm/cont/ArrayHandleCast.h>
|
|
#include <vtkm/cont/ArrayHandleUniformPointCoordinates.h>
|
|
|
|
namespace vtkm
|
|
{
|
|
|
|
namespace internal
|
|
{
|
|
|
|
namespace detail
|
|
{
|
|
|
|
struct ArrayPortalMultiplexerGetNumberOfValuesFunctor
|
|
{
|
|
template <typename PortalType>
|
|
VTKM_EXEC_CONT vtkm::Id operator()(const PortalType& portal) const noexcept
|
|
{
|
|
return portal.GetNumberOfValues();
|
|
}
|
|
};
|
|
|
|
struct ArrayPortalMultiplexerGetFunctor
|
|
{
|
|
VTKM_SUPPRESS_EXEC_WARNINGS
|
|
template <typename PortalType>
|
|
VTKM_EXEC_CONT typename PortalType::ValueType operator()(const PortalType& portal,
|
|
vtkm::Id index) const noexcept
|
|
{
|
|
return portal.Get(index);
|
|
}
|
|
};
|
|
|
|
struct ArrayPortalMultiplexerSetFunctor
|
|
{
|
|
VTKM_SUPPRESS_EXEC_WARNINGS
|
|
template <typename PortalType>
|
|
VTKM_EXEC_CONT void operator()(const PortalType& portal,
|
|
vtkm::Id index,
|
|
const typename PortalType::ValueType& value) const noexcept
|
|
{
|
|
portal.Set(index, value);
|
|
}
|
|
};
|
|
|
|
} // namespace detail
|
|
|
|
template <typename... PortalTypes>
|
|
struct ArrayPortalMultiplexer
|
|
{
|
|
using PortalVariantType = vtkm::internal::Variant<PortalTypes...>;
|
|
PortalVariantType PortalVariant;
|
|
|
|
using ValueType = typename PortalVariantType::template TypeAt<0>::ValueType;
|
|
|
|
ArrayPortalMultiplexer() = default;
|
|
~ArrayPortalMultiplexer() = default;
|
|
ArrayPortalMultiplexer(ArrayPortalMultiplexer&&) = default;
|
|
ArrayPortalMultiplexer(const ArrayPortalMultiplexer&) = default;
|
|
ArrayPortalMultiplexer& operator=(ArrayPortalMultiplexer&&) = default;
|
|
ArrayPortalMultiplexer& operator=(const ArrayPortalMultiplexer&) = default;
|
|
|
|
template <typename Portal>
|
|
VTKM_EXEC_CONT ArrayPortalMultiplexer(const Portal& src) noexcept : PortalVariant(src)
|
|
{
|
|
}
|
|
|
|
template <typename Portal>
|
|
VTKM_EXEC_CONT ArrayPortalMultiplexer& operator=(const Portal& src) noexcept
|
|
{
|
|
this->PortalVariant = src;
|
|
return *this;
|
|
}
|
|
|
|
VTKM_EXEC_CONT vtkm::Id GetNumberOfValues() const noexcept
|
|
{
|
|
return this->PortalVariant.CastAndCall(
|
|
detail::ArrayPortalMultiplexerGetNumberOfValuesFunctor{});
|
|
}
|
|
|
|
VTKM_EXEC_CONT ValueType Get(vtkm::Id index) const noexcept
|
|
{
|
|
return this->PortalVariant.CastAndCall(detail::ArrayPortalMultiplexerGetFunctor{}, index);
|
|
}
|
|
|
|
VTKM_EXEC_CONT void Set(vtkm::Id index, const ValueType& value) const noexcept
|
|
{
|
|
this->PortalVariant.CastAndCall(detail::ArrayPortalMultiplexerSetFunctor{}, index, value);
|
|
}
|
|
};
|
|
|
|
} // namespace internal
|
|
|
|
namespace cont
|
|
{
|
|
|
|
template <typename... StorageTags>
|
|
struct StorageTagMultiplexer
|
|
{
|
|
};
|
|
|
|
namespace internal
|
|
{
|
|
|
|
namespace detail
|
|
{
|
|
|
|
struct MultiplexerGetNumberOfValuesFunctor
|
|
{
|
|
template <typename ArrayHandleType>
|
|
VTKM_CONT vtkm::Id operator()(ArrayHandleType&& array) const
|
|
{
|
|
return array.GetNumberOfValues();
|
|
}
|
|
};
|
|
|
|
struct MultiplexerAllocateFunctor
|
|
{
|
|
template <typename ArrayHandleType>
|
|
VTKM_CONT void operator()(ArrayHandleType&& array, vtkm::Id numberOfValues) const
|
|
{
|
|
array.Allocate(numberOfValues);
|
|
}
|
|
};
|
|
|
|
struct MultiplexerShrinkFunctor
|
|
{
|
|
template <typename ArrayHandleType>
|
|
VTKM_CONT void operator()(ArrayHandleType&& array, vtkm::Id numberOfValues) const
|
|
{
|
|
array.Shrink(numberOfValues);
|
|
}
|
|
};
|
|
|
|
struct MultiplexerReleaseResourcesFunctor
|
|
{
|
|
template <typename ArrayHandleType>
|
|
VTKM_CONT vtkm::Id operator()(ArrayHandleType&& array) const
|
|
{
|
|
return array.ReleaseResources();
|
|
}
|
|
};
|
|
|
|
struct MultiplexerReleaseResourcesExecutionFunctor
|
|
{
|
|
template <typename ArrayHandleType>
|
|
VTKM_CONT void operator()(ArrayHandleType&& array) const
|
|
{
|
|
array.ReleaseResourcesExecution();
|
|
}
|
|
};
|
|
|
|
} // namespace detail
|
|
|
|
template <typename ValueType_, typename... StorageTags>
|
|
class Storage<ValueType_, StorageTagMultiplexer<StorageTags...>>
|
|
{
|
|
public:
|
|
using ValueType = ValueType_;
|
|
|
|
private:
|
|
template <typename S>
|
|
using StorageToArrayHandle = vtkm::cont::ArrayHandle<ValueType, S>;
|
|
|
|
template <typename S>
|
|
using StorageToPortalControl = typename StorageToArrayHandle<S>::WritePortalType;
|
|
|
|
template <typename S>
|
|
using StorageToPortalConstControl = typename StorageToArrayHandle<S>::ReadPortalType;
|
|
|
|
using ArrayHandleVariantType = vtkm::internal::Variant<StorageToArrayHandle<StorageTags>...>;
|
|
ArrayHandleVariantType ArrayHandleVariant;
|
|
|
|
public:
|
|
using PortalType = vtkm::internal::ArrayPortalMultiplexer<StorageToPortalControl<StorageTags>...>;
|
|
using PortalConstType =
|
|
vtkm::internal::ArrayPortalMultiplexer<StorageToPortalConstControl<StorageTags>...>;
|
|
|
|
Storage() = default;
|
|
Storage(Storage&&) = default;
|
|
Storage(const Storage&) = default;
|
|
Storage& operator=(Storage&&) = default;
|
|
Storage& operator=(const Storage&) = default;
|
|
|
|
template <typename S>
|
|
VTKM_CONT Storage(vtkm::cont::ArrayHandle<ValueType, S>&& rhs)
|
|
: ArrayHandleVariant(std::move(rhs))
|
|
{
|
|
}
|
|
|
|
template <typename S>
|
|
VTKM_CONT Storage(const vtkm::cont::ArrayHandle<ValueType, S>& src)
|
|
: ArrayHandleVariant(src)
|
|
{
|
|
}
|
|
|
|
VTKM_CONT bool IsValid() const { return this->ArrayHandleVariant.IsValid(); }
|
|
|
|
template <typename S>
|
|
VTKM_CONT void SetArray(vtkm::cont::ArrayHandle<ValueType, S>&& rhs)
|
|
{
|
|
this->ArrayHandleVariant = std::move(rhs);
|
|
}
|
|
|
|
template <typename S>
|
|
VTKM_CONT void SetArray(const vtkm::cont::ArrayHandle<ValueType, S>& src)
|
|
{
|
|
this->ArrayHandleVariant = src;
|
|
}
|
|
|
|
private:
|
|
struct GetPortalFunctor
|
|
{
|
|
template <typename ArrayHandleType>
|
|
VTKM_CONT PortalType operator()(ArrayHandleType&& array) const
|
|
{
|
|
return PortalType(array.WritePortal());
|
|
}
|
|
};
|
|
|
|
struct GetPortalConstFunctor
|
|
{
|
|
template <typename ArrayHandleType>
|
|
VTKM_CONT PortalConstType operator()(ArrayHandleType&& array) const
|
|
{
|
|
return PortalConstType(array.ReadPortal());
|
|
}
|
|
};
|
|
|
|
public:
|
|
VTKM_CONT PortalType GetPortal()
|
|
{
|
|
return this->ArrayHandleVariant.CastAndCall(GetPortalFunctor{});
|
|
}
|
|
|
|
VTKM_CONT PortalConstType GetPortalConst() const
|
|
{
|
|
return this->ArrayHandleVariant.CastAndCall(GetPortalConstFunctor{});
|
|
}
|
|
|
|
VTKM_CONT vtkm::Id GetNumberOfValues() const
|
|
{
|
|
if (this->IsValid())
|
|
{
|
|
return this->ArrayHandleVariant.CastAndCall(detail::MultiplexerGetNumberOfValuesFunctor{});
|
|
}
|
|
else
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
VTKM_CONT void Allocate(vtkm::Id numberOfValues)
|
|
{
|
|
if (this->IsValid())
|
|
{
|
|
this->ArrayHandleVariant.CastAndCall(detail::MultiplexerAllocateFunctor{}, numberOfValues);
|
|
}
|
|
else if (numberOfValues > 0)
|
|
{
|
|
throw vtkm::cont::ErrorBadValue(
|
|
"Attempted to allocate an ArrayHandleMultiplexer with no underlying array.");
|
|
}
|
|
else
|
|
{
|
|
// Special case, OK to perform "0" allocation on invalid array.
|
|
}
|
|
}
|
|
|
|
VTKM_CONT void Shrink(vtkm::Id numberOfValues)
|
|
{
|
|
if (this->IsValid())
|
|
{
|
|
this->ArrayHandleVariant.CastAndCall(detail::MultiplexerShrinkFunctor{}, numberOfValues);
|
|
}
|
|
else if (numberOfValues > 0)
|
|
{
|
|
throw vtkm::cont::ErrorBadValue(
|
|
"Attempted to allocate an ArrayHandleMultiplexer with no underlying array.");
|
|
}
|
|
else
|
|
{
|
|
// Special case, OK to perform "0" allocation on invalid array.
|
|
}
|
|
}
|
|
|
|
VTKM_CONT void ReleaseResources()
|
|
{
|
|
if (this->IsValid())
|
|
{
|
|
this->ArrayHandleVariant.CastAndCall(detail::MultiplexerReleaseResourcesFunctor{});
|
|
}
|
|
}
|
|
|
|
VTKM_CONT ArrayHandleVariantType& GetArrayHandleVariant() { return this->ArrayHandleVariant; }
|
|
};
|
|
|
|
|
|
template <typename ValueType_, typename... StorageTags, typename Device>
|
|
class ArrayTransfer<ValueType_, StorageTagMultiplexer<StorageTags...>, Device>
|
|
{
|
|
public:
|
|
using ValueType = ValueType_;
|
|
|
|
private:
|
|
using StorageTag = StorageTagMultiplexer<StorageTags...>;
|
|
using StorageType = vtkm::cont::internal::Storage<ValueType, StorageTag>;
|
|
|
|
template <typename S>
|
|
using StorageToArrayHandle = vtkm::cont::ArrayHandle<ValueType, S>;
|
|
|
|
template <typename S>
|
|
using StorageToPortalExecution =
|
|
typename StorageToArrayHandle<S>::template ExecutionTypes<Device>::Portal;
|
|
|
|
template <typename S>
|
|
using StorageToPortalConstExecution =
|
|
typename StorageToArrayHandle<S>::template ExecutionTypes<Device>::PortalConst;
|
|
|
|
public:
|
|
using PortalControl = typename StorageType::PortalType;
|
|
using PortalConstControl = typename StorageType::PortalConstType;
|
|
|
|
using PortalExecution =
|
|
vtkm::internal::ArrayPortalMultiplexer<StorageToPortalExecution<StorageTags>...>;
|
|
using PortalConstExecution =
|
|
vtkm::internal::ArrayPortalMultiplexer<StorageToPortalConstExecution<StorageTags>...>;
|
|
|
|
private:
|
|
StorageType* StoragePointer;
|
|
|
|
public:
|
|
VTKM_CONT ArrayTransfer(StorageType* storage)
|
|
: StoragePointer(storage)
|
|
{
|
|
}
|
|
|
|
VTKM_CONT vtkm::Id GetNumberOfValues() const { return this->StoragePointer->GetNumberOfValues(); }
|
|
|
|
VTKM_CONT PortalConstExecution PrepareForInput(bool vtkmNotUsed(updateData),
|
|
vtkm::cont::Token& token)
|
|
{
|
|
return this->StoragePointer->GetArrayHandleVariant().CastAndCall(PrepareForInputFunctor{},
|
|
token);
|
|
}
|
|
|
|
VTKM_CONT PortalExecution PrepareForInPlace(bool vtkmNotUsed(updateData),
|
|
vtkm::cont::Token& token)
|
|
{
|
|
return this->StoragePointer->GetArrayHandleVariant().CastAndCall(PrepareForInPlaceFunctor{},
|
|
token);
|
|
}
|
|
|
|
VTKM_CONT PortalExecution PrepareForOutput(vtkm::Id numberOfValues, vtkm::cont::Token& token)
|
|
{
|
|
return this->StoragePointer->GetArrayHandleVariant().CastAndCall(
|
|
PrepareForOutputFunctor{}, numberOfValues, token);
|
|
}
|
|
|
|
VTKM_CONT void RetrieveOutputData(StorageType* vtkmNotUsed(storage)) const
|
|
{
|
|
// Implementation of this method should be unnecessary. The internal
|
|
// array handles should automatically retrieve the output data as
|
|
// necessary.
|
|
}
|
|
|
|
VTKM_CONT void Shrink(vtkm::Id numberOfValues)
|
|
{
|
|
this->StoragePointer->GetArrayHandleVariant().CastAndCall(detail::MultiplexerShrinkFunctor{},
|
|
numberOfValues);
|
|
}
|
|
|
|
VTKM_CONT void ReleaseResources()
|
|
{
|
|
this->StoragePointer->GetArrayHandleVariant().CastAndCall(
|
|
detail::MultiplexerReleaseResourcesExecutionFunctor{});
|
|
}
|
|
|
|
private:
|
|
struct PrepareForInputFunctor
|
|
{
|
|
template <typename ArrayHandleType>
|
|
VTKM_CONT PortalConstExecution operator()(const ArrayHandleType& array,
|
|
vtkm::cont::Token& token)
|
|
{
|
|
return PortalConstExecution(array.PrepareForInput(Device{}, token));
|
|
}
|
|
};
|
|
|
|
struct PrepareForInPlaceFunctor
|
|
{
|
|
template <typename ArrayHandleType>
|
|
VTKM_CONT PortalExecution operator()(ArrayHandleType& array, vtkm::cont::Token& token)
|
|
{
|
|
return PortalExecution(array.PrepareForInPlace(Device{}, token));
|
|
}
|
|
};
|
|
|
|
struct PrepareForOutputFunctor
|
|
{
|
|
template <typename ArrayHandleType>
|
|
VTKM_CONT PortalExecution operator()(ArrayHandleType& array,
|
|
vtkm::Id numberOfValues,
|
|
vtkm::cont::Token& token)
|
|
{
|
|
return PortalExecution(array.PrepareForOutput(numberOfValues, Device{}, token));
|
|
}
|
|
};
|
|
};
|
|
|
|
} // namespace internal
|
|
|
|
namespace detail
|
|
{
|
|
|
|
template <typename... ArrayHandleTypes>
|
|
struct ArrayHandleMultiplexerTraits
|
|
{
|
|
using ArrayHandleType0 =
|
|
brigand::at<brigand::list<ArrayHandleTypes...>, std::integral_constant<vtkm::IdComponent, 0>>;
|
|
VTKM_IS_ARRAY_HANDLE(ArrayHandleType0);
|
|
using ValueType = typename ArrayHandleType0::ValueType;
|
|
|
|
// If there is a compile error in this group of lines, then one of the array types given to
|
|
// ArrayHandleMultiplexer must contain an invalid ArrayHandle. That could mean that it is not an
|
|
// ArrayHandle type or it could mean that the value type does not match the appropriate value
|
|
// type.
|
|
template <typename ArrayHandle>
|
|
struct CheckArrayHandleTransform
|
|
{
|
|
VTKM_IS_ARRAY_HANDLE(ArrayHandle);
|
|
VTKM_STATIC_ASSERT((std::is_same<ValueType, typename ArrayHandle::ValueType>::value));
|
|
};
|
|
using CheckArrayHandle = brigand::list<CheckArrayHandleTransform<ArrayHandleTypes>...>;
|
|
|
|
// Note that this group of code could be simplified as the pair of lines:
|
|
// template <typename ArrayHandle>
|
|
// using ArrayHandleToStorageTag = typename ArrayHandle::StorageTag;
|
|
// However, there are issues with older Visual Studio compilers that is not working
|
|
// correctly with that form.
|
|
template <typename ArrayHandle>
|
|
struct ArrayHandleToStorageTagImpl
|
|
{
|
|
using Type = typename ArrayHandle::StorageTag;
|
|
};
|
|
template <typename ArrayHandle>
|
|
using ArrayHandleToStorageTag = typename ArrayHandleToStorageTagImpl<ArrayHandle>::Type;
|
|
|
|
using StorageTag =
|
|
vtkm::cont::StorageTagMultiplexer<ArrayHandleToStorageTag<ArrayHandleTypes>...>;
|
|
using StorageType = vtkm::cont::internal::Storage<ValueType, StorageTag>;
|
|
};
|
|
}
|
|
|
|
/// \brief An ArrayHandle that can behave like several other handles.
|
|
///
|
|
/// An \c ArrayHandleMultiplexer simply redirects its calls to another \c ArrayHandle. However
|
|
/// the type of that \c ArrayHandle does not need to be (completely) known at runtime. Rather,
|
|
/// \c ArrayHandleMultiplexer is defined over a set of possible \c ArrayHandle types. Any
|
|
/// one of these \c ArrayHandles may be assigned to the \c ArrayHandleMultiplexer.
|
|
///
|
|
/// When a value is retreived from the \c ArrayHandleMultiplexer, the multiplexer checks to
|
|
/// see which type of array is currently stored in it. It then redirects to the \c ArrayHandle
|
|
/// of the appropriate type.
|
|
///
|
|
/// The \c ArrayHandleMultiplexer template parameters are all the ArrayHandle types it
|
|
/// should support.
|
|
///
|
|
/// If only one template parameter is given, it is assumed to be the \c ValueType of the
|
|
/// array. A default list of supported arrays is supported (see
|
|
/// \c vtkm::cont::internal::ArrayHandleMultiplexerDefaultArrays.) If multiple template
|
|
/// parameters are given, they are all considered possible \c ArrayHandle types.
|
|
///
|
|
template <typename... ArrayHandleTypes>
|
|
class ArrayHandleMultiplexer
|
|
: public vtkm::cont::ArrayHandle<
|
|
typename detail::ArrayHandleMultiplexerTraits<ArrayHandleTypes...>::ValueType,
|
|
typename detail::ArrayHandleMultiplexerTraits<ArrayHandleTypes...>::StorageTag>
|
|
{
|
|
using Traits = detail::ArrayHandleMultiplexerTraits<ArrayHandleTypes...>;
|
|
|
|
public:
|
|
VTKM_ARRAY_HANDLE_SUBCLASS(
|
|
ArrayHandleMultiplexer,
|
|
(ArrayHandleMultiplexer<ArrayHandleTypes...>),
|
|
(vtkm::cont::ArrayHandle<typename Traits::ValueType, typename Traits::StorageTag>));
|
|
|
|
private:
|
|
using StorageType = vtkm::cont::internal::Storage<ValueType, StorageTag>;
|
|
|
|
public:
|
|
template <typename RealStorageTag>
|
|
VTKM_CONT ArrayHandleMultiplexer(const vtkm::cont::ArrayHandle<ValueType, RealStorageTag>& src)
|
|
: Superclass(StorageType(src))
|
|
{
|
|
}
|
|
|
|
template <typename RealStorageTag>
|
|
VTKM_CONT ArrayHandleMultiplexer(vtkm::cont::ArrayHandle<ValueType, RealStorageTag>&& rhs)
|
|
: Superclass(StorageType(std::move(rhs)))
|
|
{
|
|
}
|
|
|
|
VTKM_CONT bool IsValid() const { return this->GetStorage().IsValid(); }
|
|
|
|
template <typename S>
|
|
VTKM_CONT void SetArray(vtkm::cont::ArrayHandle<ValueType, S>&& rhs)
|
|
{
|
|
this->GetStorage().SetArray(std::move(rhs));
|
|
}
|
|
|
|
template <typename S>
|
|
VTKM_CONT void SetArray(const vtkm::cont::ArrayHandle<ValueType, S>& src)
|
|
{
|
|
this->GetStorage().SetArray(src);
|
|
}
|
|
};
|
|
|
|
/// \brief Converts a \c vtkm::ListTag to an \c ArrayHandleMultiplexer
|
|
///
|
|
/// The argument of this template must be a vtkm::ListTag and furthermore all the types in
|
|
/// the list tag must be some type of \c ArrayHandle. The templated type gets aliased to
|
|
/// an \c ArrayHandleMultiplexer that can store any of these ArrayHandle types.
|
|
///
|
|
/// Deprecated. Use `ArrayHandleMultiplexerFromList` instead.
|
|
///
|
|
template <typename ListTag>
|
|
using ArrayHandleMultiplexerFromListTag VTKM_DEPRECATED(
|
|
1.6,
|
|
"vtkm::ListTag is no longer supported. Use vtkm::List instead.") =
|
|
vtkm::ListApply<ListTag, ArrayHandleMultiplexer>;
|
|
|
|
/// \brief Converts a`vtkm::List` to an `ArrayHandleMultiplexer`
|
|
///
|
|
/// The argument of this template must be a `vtkm::List` and furthermore all the types in
|
|
/// the list tag must be some type of \c ArrayHandle. The templated type gets aliased to
|
|
/// an \c ArrayHandleMultiplexer that can store any of these ArrayHandle types.
|
|
///
|
|
template <typename List>
|
|
using ArrayHandleMultiplexerFromList = vtkm::ListApply<List, ArrayHandleMultiplexer>;
|
|
|
|
} // namespace cont
|
|
|
|
} // namespace vtkm
|
|
|
|
#endif //vtk_m_cont_ArrayHandleMultiplexer_h
|