#ifndef ITEM_ARRAY_HPP #define ITEM_ARRAY_HPP #include <mesh/IConnectivity.hpp> #include <mesh/ItemId.hpp> #include <mesh/ItemType.hpp> #include <utils/PugsAssert.hpp> #include <utils/Table.hpp> #include <memory> template <typename DataType, ItemType item_type, typename ConnectivityPtr = std::shared_ptr<const IConnectivity>> class ItemArray { public: static constexpr ItemType item_t{item_type}; using data_type = DataType; using ItemId = ItemIdT<item_type>; using index_type = ItemId; private: using ConnectivitySharedPtr = std::shared_ptr<const IConnectivity>; using ConnectivityWeakPtr = std::weak_ptr<const IConnectivity>; static_assert(std::is_same_v<ConnectivityPtr, ConnectivitySharedPtr> or std::is_same_v<ConnectivityPtr, ConnectivityWeakPtr>); ConnectivityPtr m_connectivity_ptr; Table<DataType> m_values; // Allow const std:shared_ptr version to access our data friend ItemArray<std::add_const_t<DataType>, item_type, ConnectivitySharedPtr>; // Allow const std:weak_ptr version to access our data friend ItemArray<std::add_const_t<DataType>, item_type, ConnectivityWeakPtr>; // Allow non-const std:shared_ptr version to access our data friend ItemArray<std::remove_const_t<DataType>, item_type, ConnectivitySharedPtr>; // Allow non-const std:weak_ptr version to access our data friend ItemArray<std::remove_const_t<DataType>, item_type, ConnectivityWeakPtr>; public: // This is not the correct way to look at ItemArray, use with care Table<const DataType> tableView() const { return m_values; } [[nodiscard]] friend PUGS_INLINE ItemArray<std::remove_const_t<DataType>, item_type, ConnectivityPtr> copy(const ItemArray<DataType, item_type, ConnectivityPtr>& source) { ItemArray<std::remove_const_t<DataType>, item_type, ConnectivityPtr> image; image.m_connectivity_ptr = source.m_connectivity_ptr; image.m_values = copy(source.m_values); return image; } template <typename ConnectivityPtr2> friend PUGS_INLINE void copy_to(const ItemArray<std::add_const_t<DataType>, item_type, ConnectivityPtr>& source, const ItemArray<DataType, item_type, ConnectivityPtr2>& destination); template <typename ConnectivityPtr2> friend PUGS_INLINE void copy_to(const ItemArray<DataType, item_type, ConnectivityPtr>& source, const ItemArray<std::remove_const_t<DataType>, item_type, ConnectivityPtr2>& destination) { Assert(destination.connectivity_ptr() == source.connectivity_ptr(), "different connectivities"); Assert(source.sizeOfArrays() == destination.sizeOfArrays(), "incompatible size of arrays") copy_to(source.m_values, destination.m_values); } [[nodiscard]] PUGS_INLINE bool isBuilt() const noexcept { return m_connectivity_ptr.use_count() != 0; } [[nodiscard]] PUGS_INLINE std::shared_ptr<const IConnectivity> connectivity_ptr() const noexcept { if constexpr (std::is_same_v<ConnectivityPtr, ConnectivitySharedPtr>) { return m_connectivity_ptr; } else { return m_connectivity_ptr.lock(); } } PUGS_INLINE void fill(const DataType& data) const noexcept { static_assert(not std::is_const_v<DataType>, "Cannot modify ItemArray of const"); m_values.fill(data); } template <ItemType item_t> [[nodiscard]] PUGS_INLINE typename Table<DataType>::UnsafeRowView operator[](const ItemIdT<item_t>& item_id) const noexcept(NO_ASSERT) { static_assert(item_t == item_type, "invalid ItemId type"); Assert(this->isBuilt(), "ItemArray is not built"); Assert(item_id < this->numberOfItems(), "invalid item_id"); return m_values[item_id]; } [[nodiscard]] PUGS_INLINE size_t numberOfItems() const noexcept(NO_ASSERT) { Assert(this->isBuilt(), "ItemArray is not built"); return m_values.numberOfRows(); } [[nodiscard]] PUGS_INLINE size_t sizeOfArrays() const { Assert(this->isBuilt(), "ItemArray is not built"); return m_values.numberOfColumns(); } template <typename DataType2, typename ConnectivityPtr2> PUGS_INLINE ItemArray& operator=(const ItemArray<DataType2, item_type, ConnectivityPtr2>& array_per_item) noexcept { // ensures that DataType is the same as source DataType2 static_assert(std::is_same_v<std::remove_const_t<DataType>, std::remove_const_t<DataType2>>, "Cannot assign ItemArray of different type"); // ensures that const is not lost through copy static_assert(((std::is_const_v<DataType2> and std::is_const_v<DataType>) or not std::is_const_v<DataType2>), "Cannot assign ItemArray of const to ItemArray of non-const"); m_values = array_per_item.m_values; if constexpr (std::is_same_v<ConnectivityPtr, ConnectivitySharedPtr> and std::is_same_v<ConnectivityPtr2, ConnectivityWeakPtr>) { m_connectivity_ptr = array_per_item.m_connectivity_ptr.lock(); } else { m_connectivity_ptr = array_per_item.m_connectivity_ptr; } return *this; } friend std::ostream& operator<<(std::ostream& os, const ItemArray& item_array) { os << item_array.m_values; return os; } template <typename DataType2, typename ConnectivityPtr2> PUGS_INLINE ItemArray(const ItemArray<DataType2, item_type, ConnectivityPtr2>& array_per_item) noexcept { this->operator=(array_per_item); } PUGS_INLINE ItemArray() = default; PUGS_INLINE ItemArray(const IConnectivity& connectivity, size_t size_of_array) noexcept : m_connectivity_ptr{connectivity.shared_ptr()}, m_values{connectivity.numberOf<item_type>(), size_of_array} { static_assert(not std::is_const_v<DataType>, "Cannot allocate ItemArray of const data: only view is " "supported"); } PUGS_INLINE ItemArray(const IConnectivity& connectivity, const Table<DataType>& table) noexcept(NO_ASSERT) : m_connectivity_ptr{connectivity.shared_ptr()}, m_values{table} { Assert(connectivity.numberOf<item_type>() == table.numberOfRows(), "invalid table, wrong number of rows"); } PUGS_INLINE ~ItemArray() = default; }; template <typename DataType> using NodeArray = ItemArray<DataType, ItemType::node>; template <typename DataType> using EdgeArray = ItemArray<DataType, ItemType::edge>; template <typename DataType> using FaceArray = ItemArray<DataType, ItemType::face>; template <typename DataType> using CellArray = ItemArray<DataType, ItemType::cell>; // Weak versions: should not be used outside of Connectivity template <typename DataType, ItemType item_type> using WeakItemArray = ItemArray<DataType, item_type, std::weak_ptr<const IConnectivity>>; template <typename DataType> using WeakNodeArray = WeakItemArray<DataType, ItemType::node>; template <typename DataType> using WeakEdgeArray = WeakItemArray<DataType, ItemType::edge>; template <typename DataType> using WeakFaceArray = WeakItemArray<DataType, ItemType::face>; template <typename DataType> using WeakCellArray = WeakItemArray<DataType, ItemType::cell>; #endif // ITEM_ARRAY_HPP