vtk-m/vtkm/cont/UnknownCellSet.h
Kenneth Moreland 3e1339f9a7 Remove deprecated features from VTK-m
With the major revision 2.0 of VTK-m, many items previously marked as
deprecated were removed. If updating to a new version of VTK-m, it is
recommended to first update to VTK-m 1.9, which will include the deprecated
features but provide warnings (with the right compiler) that will point to
the replacement code. Once the deprecations have been fixed, updating to
2.0 should be smoother.
2022-11-17 07:12:31 -06:00

360 lines
12 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_UnknownCellSet_h
#define vtk_m_cont_UnknownCellSet_h
#include <vtkm/cont/CastAndCall.h>
#include <vtkm/cont/CellSet.h>
#include <vtkm/cont/DefaultTypes.h>
#include <vtkm/cont/vtkm_cont_export.h>
#include <memory>
namespace vtkm
{
namespace cont
{
// Forward declaration.
template <typename CellSetList>
class UncertainCellSet;
/// \brief A CellSet of an unknown type.
///
/// `UnknownCellSet` holds a `CellSet` object using runtime polymorphism to manage
/// the dynamic type rather than compile-time templates. This adds a programming
/// convenience that helps avoid a proliferation of templates.
///
/// To interface between the runtime polymorphism and the templated algorithms
/// in VTK-m, `UnknownCellSet` contains a method named `CastAndCallForTypes` that
/// determines the correct type from some known list of types. This mechanism is
/// used internally by VTK-m's worklet invocation mechanism to determine the type
/// when running algorithms.
///
/// If the `UnknownCellSet` is used in a context where the possible cell set types
/// can be whittled down to a finite list, you can specify lists of cell set types
/// using the `ResetCellSetList` method. This will convert this object to an
/// `UncertainCellSet` of the given types. In cases where a finite set of types
/// are needed but there is no subset, `VTKM_DEFAULT_CELL_SET_LIST`
///
class VTKM_CONT_EXPORT UnknownCellSet
{
std::shared_ptr<vtkm::cont::CellSet> Container;
void InitializeKnownOrUnknownCellSet(const UnknownCellSet& cellSet,
std::true_type vtkmNotUsed(isUnknownCellSet))
{
*this = cellSet;
}
template <typename CellSetType>
void InitializeKnownOrUnknownCellSet(const CellSetType& cellSet,
std::false_type vtkmNotUsed(isUnknownCellSet))
{
VTKM_IS_CELL_SET(CellSetType);
this->Container = std::shared_ptr<vtkm::cont::CellSet>(new CellSetType(cellSet));
}
public:
VTKM_CONT UnknownCellSet() = default;
template <typename CellSetType>
VTKM_CONT UnknownCellSet(const CellSetType& cellSet)
{
this->InitializeKnownOrUnknownCellSet(
cellSet, typename std::is_base_of<UnknownCellSet, CellSetType>::type{});
}
/// \brief Returns whether a cell set is stored in this `UnknownCellSet`.
///
/// If the `UnknownCellSet` is constructed without a `CellSet`, it will not
/// have an underlying type, and therefore the operations will be invalid.
///
VTKM_CONT bool IsValid() const { return static_cast<bool>(this->Container); }
/// \brief Returns a pointer to the `CellSet` base class.
///
VTKM_CONT vtkm::cont::CellSet* GetCellSetBase() { return this->Container.get(); }
VTKM_CONT const vtkm::cont::CellSet* GetCellSetBase() const { return this->Container.get(); }
/// \brief Create a new cell set of the same type as this cell set.
///
/// This method creates a new cell set that is the same type as this one
/// and returns a new `UnknownCellSet` for it. This method is convenient
/// when creating output cell sets that should be the same type as the
/// input cell set.
///
VTKM_CONT UnknownCellSet NewInstance() const;
/// \brief Returns the name of the cell set type stored in this class.
///
/// Returns an empty string if no cell set is stored.
///
VTKM_CONT std::string GetCellSetName() const;
/// \brief Returns true if this cell set matches the `CellSetType` template argument.
///
template <typename CellSetType>
VTKM_CONT bool IsType() const
{
return (dynamic_cast<const CellSetType*>(this->Container.get()) != nullptr);
}
VTKM_CONT vtkm::Id GetNumberOfCells() const
{
return this->Container ? this->Container->GetNumberOfCells() : 0;
}
VTKM_CONT vtkm::Id GetNumberOfFaces() const
{
return this->Container ? this->Container->GetNumberOfFaces() : 0;
}
VTKM_CONT vtkm::Id GetNumberOfEdges() const
{
return this->Container ? this->Container->GetNumberOfEdges() : 0;
}
VTKM_CONT vtkm::Id GetNumberOfPoints() const
{
return this->Container ? this->Container->GetNumberOfPoints() : 0;
}
VTKM_CONT vtkm::UInt8 GetCellShape(vtkm::Id id) const
{
return this->GetCellSetBase()->GetCellShape(id);
}
VTKM_CONT vtkm::IdComponent GetNumberOfPointsInCell(vtkm::Id id) const
{
return this->GetCellSetBase()->GetNumberOfPointsInCell(id);
}
VTKM_CONT void GetCellPointIds(vtkm::Id id, vtkm::Id* ptids) const
{
return this->GetCellSetBase()->GetCellPointIds(id, ptids);
}
VTKM_CONT void DeepCopyFrom(const CellSet* src) { this->GetCellSetBase()->DeepCopy(src); }
VTKM_CONT void PrintSummary(std::ostream& os) const;
VTKM_CONT void ReleaseResourcesExecution()
{
if (this->Container)
{
this->Container->ReleaseResourcesExecution();
}
}
/// \brief Returns true if this cell set can be retrieved as the given type.
///
/// This method will return true if calling `AsCellSet` of the given type will
/// succeed. This result is similar to `IsType`, and if `IsType` returns true,
/// then this will return true. However, this method will also return true for
/// other types where automatic conversions are made.
///
template <typename CellSetType>
VTKM_CONT bool CanConvert() const
{
// TODO: Currently, these are the same. But in the future we expect to support
// special CellSet types that can convert back and forth such as multiplexed
// cell sets or a cell set that can hold structured grids of any dimension.
return this->IsType<CellSetType>();
}
///@{
/// \brief Get the cell set as a known type.
///
/// Returns this cell set cast appropriately and stored in the given `CellSet`
/// type. Throws an `ErrorBadType` if the stored cell set cannot be stored in
/// the given cell set type. Use the `CanConvert` method to determine if the
/// cell set can be returned with the given type.
///
template <typename CellSetType>
VTKM_CONT void AsCellSet(CellSetType& cellSet) const
{
VTKM_IS_CELL_SET(CellSetType);
CellSetType* cellSetPointer = dynamic_cast<CellSetType*>(this->Container.get());
if (cellSetPointer == nullptr)
{
VTKM_LOG_CAST_FAIL(*this, CellSetType);
throwFailedDynamicCast(this->GetCellSetName(), vtkm::cont::TypeToString(cellSet));
}
VTKM_LOG_CAST_SUCC(*this, *cellSetPointer);
cellSet = *cellSetPointer;
}
template <typename CellSetType>
VTKM_CONT CellSetType AsCellSet() const
{
CellSetType cellSet;
this->AsCellSet(cellSet);
return cellSet;
}
///@}
/// \brief Assigns potential cell set types.
///
/// Calling this method will return an `UncertainCellSet` with the provided
/// cell set list. The returned object will hold the same `CellSet`, but
/// `CastAndCall`'s on the returned object will be constrained to the given
/// types.
///
// Defined in UncertainCellSet.h
template <typename CellSetList>
VTKM_CONT vtkm::cont::UncertainCellSet<CellSetList> ResetCellSetList(CellSetList) const;
template <typename CellSetList>
VTKM_CONT vtkm::cont::UncertainCellSet<CellSetList> ResetCellSetList() const;
/// \brief Call a functor using the underlying cell set type.
///
/// `CastAndCallForTypes` attemts to cast the held cell set to a specific type
/// and then calls the given functor with the cast cell set. You must specify
/// the `CellSetList` (in a `vtkm::List`) as a template argument.
///
/// After the functor argument, you may add any number of arguments that will
/// be passed to the functor after the converted cell set.
///
template <typename CellSetList, typename Functor, typename... Args>
VTKM_CONT void CastAndCallForTypes(Functor&& functor, Args&&... args) const;
};
//=============================================================================
// Free function casting helpers
// (Not sure if these should be deprecated.)
/// Returns true if `unknownCellSet` matches the type of `CellSetType`.
///
template <typename CellSetType>
VTKM_CONT inline bool IsType(const vtkm::cont::UnknownCellSet& unknownCellSet)
{
return unknownCellSet.IsType<CellSetType>();
}
/// Returns `unknownCellSet` cast to the given `CellSet` type. Throws
/// `ErrorBadType` if the cast does not work. Use `IsType`
/// to check if the cast can happen.
///
template <typename CellSetType>
VTKM_CONT inline CellSetType Cast(const vtkm::cont::UnknownCellSet& unknownCellSet)
{
return unknownCellSet.AsCellSet<CellSetType>();
}
namespace internal
{
VTKM_CONT_EXPORT void ThrowCastAndCallException(const vtkm::cont::UnknownCellSet&,
const std::type_info&);
template <>
struct DynamicTransformTraits<vtkm::cont::UnknownCellSet>
{
using DynamicTag = vtkm::cont::internal::DynamicTransformTagCastAndCall;
};
} // namespace internal
template <typename CellSetList, typename Functor, typename... Args>
VTKM_CONT void UnknownCellSet::CastAndCallForTypes(Functor&& functor, Args&&... args) const
{
VTKM_IS_LIST(CellSetList);
bool called = false;
vtkm::ListForEach(
[&](auto cellSet) {
if (!called && this->CanConvert<decltype(cellSet)>())
{
called = true;
this->AsCellSet(cellSet);
VTKM_LOG_CAST_SUCC(*this, cellSet);
// If you get a compile error here, it means that you have called CastAndCall for a
// vtkm::cont::UnknownCellSet and the arguments of the functor do not match those
// being passed. This is often because it is calling the functor with a CellSet
// type that was not expected. Either add overloads to the functor to accept all
// possible cell set types or constrain the types tried for the CastAndCall.
functor(cellSet, args...);
}
},
CellSetList{});
if (!called)
{
VTKM_LOG_CAST_FAIL(*this, CellSetList);
internal::ThrowCastAndCallException(*this, typeid(CellSetList));
}
}
/// A specialization of `CastAndCall` for `UnknownCellSet`.
/// Since we have no hints on the types, use `VTKM_DEFAULT_CELL_SET_LIST`.
template <typename Functor, typename... Args>
void CastAndCall(const vtkm::cont::UnknownCellSet& cellSet, Functor&& f, Args&&... args)
{
cellSet.CastAndCallForTypes<VTKM_DEFAULT_CELL_SET_LIST>(std::forward<Functor>(f),
std::forward<Args>(args)...);
}
namespace internal
{
/// Checks to see if the given object is an unknown (or uncertain) cell set. It
/// resolves to either `std::true_type` or `std::false_type`.
///
template <typename T>
using UnknownCellSetCheck = typename std::is_base_of<vtkm::cont::UnknownCellSet, T>::type;
#define VTKM_IS_UNKNOWN_CELL_SET(T) \
VTKM_STATIC_ASSERT(::vtkm::cont::internal::UnknownCellSetCheck<T>::value)
#define VTKM_IS_KNOWN_OR_UNKNOWN_CELL_SET(T) \
VTKM_STATIC_ASSERT(::vtkm::cont::internal::CellSetCheck<T>::type::value || \
::vtkm::cont::internal::UnknownCellSetCheck<T>::value)
} // namespace internal
} // namespace vtkm::cont
} // namespace vtkm
//=============================================================================
// Specializations of serialization related classes
/// @cond SERIALIZATION
namespace vtkm
{
namespace cont
{
template <>
struct VTKM_CONT_EXPORT SerializableTypeString<vtkm::cont::UnknownCellSet>
{
static VTKM_CONT std::string Get();
};
}
} // namespace vtkm::cont
namespace mangled_diy_namespace
{
template <>
struct VTKM_CONT_EXPORT Serialization<vtkm::cont::UnknownCellSet>
{
public:
static VTKM_CONT void save(BinaryBuffer& bb, const vtkm::cont::UnknownCellSet& obj);
static VTKM_CONT void load(BinaryBuffer& bb, vtkm::cont::UnknownCellSet& obj);
};
} // namespace mangled_diy_namespace
/// @endcond SERIALIZATION
// Include the implementation of UncertainCellSet. This should be included because there
// are methods in UnknownCellSet that produce objects of this type. It has to be included
// at the end to resolve the circular dependency.
#include <vtkm/cont/UncertainCellSet.h>
#endif //vtk_m_cont_UnknownCellSet_h