From 11e3568d7626ac5bbf8c1c3aa93b1c250d09cc2c Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?St=C3=A9phane=20Del=20Pino?= <stephane.delpino44@gmail.com>
Date: Thu, 10 Mar 2022 14:31:41 +0100
Subject: [PATCH] Add a new constructor for SubItemArrayPerItem using a given
 Table

---
 src/mesh/SubItemArrayPerItem.hpp   |  33 ++++---
 tests/test_SubItemArrayPerItem.cpp | 141 +++++++++++++++++------------
 2 files changed, 102 insertions(+), 72 deletions(-)

diff --git a/src/mesh/SubItemArrayPerItem.hpp b/src/mesh/SubItemArrayPerItem.hpp
index 318063f8a..a98c039e0 100644
--- a/src/mesh/SubItemArrayPerItem.hpp
+++ b/src/mesh/SubItemArrayPerItem.hpp
@@ -83,8 +83,10 @@ class SubItemArrayPerItem
   {
     static_assert(std::is_same_v<IndexType, ItemId>, "first index must be of the correct ItemId type");
     static_assert(std::is_integral_v<SubIndexType>, "second index must be an integral type");
-    Assert(this->isBuilt());
-    Assert(i + m_row_map[size_t{item_id}] < m_row_map[size_t{item_id} + 1]);
+    Assert(this->isBuilt(), "SubItemArrayPerItem is not built");
+    Assert(item_id < this->numberOfItems(), "invalid item_id");
+
+    Assert(i + m_row_map[size_t{item_id}] < m_row_map[size_t{item_id} + 1], "invalid index");
     return m_values[m_row_map[size_t{item_id}] + i];
   }
 
@@ -101,30 +103,30 @@ class SubItemArrayPerItem
   operator[](const ArrayIndexType& i) const noexcept(NO_ASSERT)
   {
     static_assert(std::is_integral_v<ArrayIndexType>, "index must be an integral type");
-    Assert(this->isBuilt());
-    Assert(static_cast<size_t>(i) < m_values.numberOfRows());
+    Assert(this->isBuilt(), "SubItemArrayPerItem is not built");
+    Assert(static_cast<size_t>(i) < m_values.numberOfRows(), "invalid index");
     return m_values[i];
   }
 
   [[nodiscard]] PUGS_INLINE size_t
   numberOfArrays() const noexcept(NO_ASSERT)
   {
-    Assert(this->isBuilt());
+    Assert(this->isBuilt(), "SubItemArrayPerItem is not built");
     return m_values.numberOfRows();
   }
 
   [[nodiscard]] PUGS_INLINE size_t
   numberOfItems() const noexcept(NO_ASSERT)
   {
-    Assert(this->isBuilt());
-    Assert(m_row_map.size() > 0);
+    Assert(this->isBuilt(), "SubItemArrayPerItem is not built");
+    Assert(m_row_map.size() > 0, "invalid row map");
     return m_row_map.size() - 1;
   }
 
   [[nodiscard]] PUGS_INLINE size_t
   sizeOfArrays() const noexcept(NO_ASSERT)
   {
-    Assert(this->isBuilt());
+    Assert(this->isBuilt(), "SubItemArrayPerItem is not built");
     return m_values.numberOfColumns();
   }
 
@@ -133,8 +135,8 @@ class SubItemArrayPerItem
   numberOfSubArrays(IndexType item_id) const noexcept(NO_ASSERT)
   {
     static_assert(std::is_same_v<IndexType, ItemId>, "index must be an ItemId");
-    Assert(this->isBuilt());
-    Assert(item_id < this->numberOfItems());
+    Assert(this->isBuilt(), "SubItemArrayPerItem is not built");
+    Assert(item_id < this->numberOfItems(), "invalid item_id");
     return m_row_map[size_t{item_id} + 1] - m_row_map[size_t{item_id}];
   }
 
@@ -150,8 +152,8 @@ class SubItemArrayPerItem
   itemTable(IndexType item_id) const noexcept(NO_ASSERT)
   {
     static_assert(std::is_same_v<IndexType, ItemId>, "index must be an ItemId");
-    Assert(this->isBuilt());
-    Assert(item_id < this->numberOfItems());
+    Assert(this->isBuilt(), "SubItemArrayPerItem is not built");
+    Assert(item_id < this->numberOfItems(), "invalid item_id");
     const auto& item_begin = m_row_map[size_t{item_id}];
     const auto& item_end   = m_row_map[size_t{item_id} + 1];
     return subTableView(m_values, item_begin, item_end - item_begin, 0, this->sizeOfArrays());
@@ -203,6 +205,13 @@ class SubItemArrayPerItem
     m_values  = Table<std::remove_const_t<DataType>>(connectivity_matrix.numberOfValues(), size_of_arrays);
   }
 
+  SubItemArrayPerItem(const IConnectivity& connectivity, const Table<DataType>& table) noexcept(NO_ASSERT)
+    : m_connectivity_ptr{connectivity.shared_ptr()}, m_values{table}
+  {
+    Assert(m_values.numberOfRows() == connectivity.getMatrix(item_type, sub_item_type).numberOfValues(),
+           "invalid size of provided table");
+    m_row_map = connectivity.getMatrix(item_type, sub_item_type).rowsMap();
+  }
   ~SubItemArrayPerItem() = default;
 };
 
diff --git a/tests/test_SubItemArrayPerItem.cpp b/tests/test_SubItemArrayPerItem.cpp
index 71a226f01..aa8930269 100644
--- a/tests/test_SubItemArrayPerItem.cpp
+++ b/tests/test_SubItemArrayPerItem.cpp
@@ -1030,40 +1030,57 @@ TEST_CASE("SubItemArrayPerItem", "[mesh]")
     SECTION("checking for build SubItemArrayPerItem")
     {
       CellArrayPerNode<int> cell_array_per_node;
-      REQUIRE_THROWS_AS(cell_array_per_node[0], AssertError);
-      REQUIRE_THROWS_AS(cell_array_per_node.itemTable(NodeId{0}), AssertError);
-      REQUIRE_THROWS_AS(cell_array_per_node(NodeId{0}, 0), AssertError);
-      REQUIRE_THROWS_AS(cell_array_per_node.sizeOfArrays(), AssertError);
-      REQUIRE_THROWS_AS(cell_array_per_node.numberOfArrays(), AssertError);
-      REQUIRE_THROWS_AS(cell_array_per_node.numberOfItems(), AssertError);
-      REQUIRE_THROWS_AS(cell_array_per_node.numberOfSubArrays(NodeId{0}), AssertError);
+      REQUIRE_THROWS_WITH(cell_array_per_node[0], "SubItemArrayPerItem is not built");
+      REQUIRE_THROWS_WITH(cell_array_per_node.itemTable(NodeId{0}), "SubItemArrayPerItem is not built");
+      REQUIRE_THROWS_WITH(cell_array_per_node(NodeId{0}, 0), "SubItemArrayPerItem is not built");
+      REQUIRE_THROWS_WITH(cell_array_per_node.sizeOfArrays(), "SubItemArrayPerItem is not built");
+      REQUIRE_THROWS_WITH(cell_array_per_node.numberOfArrays(), "SubItemArrayPerItem is not built");
+      REQUIRE_THROWS_WITH(cell_array_per_node.numberOfItems(), "SubItemArrayPerItem is not built");
+      REQUIRE_THROWS_WITH(cell_array_per_node.numberOfSubArrays(NodeId{0}), "SubItemArrayPerItem is not built");
 
       FaceArrayPerCell<int> face_array_per_cell;
-      REQUIRE_THROWS_AS(face_array_per_cell[0], AssertError);
-      REQUIRE_THROWS_AS(face_array_per_cell.itemTable(CellId{0}), AssertError);
-      REQUIRE_THROWS_AS(face_array_per_cell(CellId{0}, 0), AssertError);
-      REQUIRE_THROWS_AS(face_array_per_cell.sizeOfArrays(), AssertError);
-      REQUIRE_THROWS_AS(face_array_per_cell.numberOfArrays(), AssertError);
-      REQUIRE_THROWS_AS(face_array_per_cell.numberOfItems(), AssertError);
-      REQUIRE_THROWS_AS(face_array_per_cell.numberOfSubArrays(CellId{0}), AssertError);
+      REQUIRE_THROWS_WITH(face_array_per_cell[0], "SubItemArrayPerItem is not built");
+      REQUIRE_THROWS_WITH(face_array_per_cell.itemTable(CellId{0}), "SubItemArrayPerItem is not built");
+      REQUIRE_THROWS_WITH(face_array_per_cell(CellId{0}, 0), "SubItemArrayPerItem is not built");
+      REQUIRE_THROWS_WITH(face_array_per_cell.sizeOfArrays(), "SubItemArrayPerItem is not built");
+      REQUIRE_THROWS_WITH(face_array_per_cell.numberOfArrays(), "SubItemArrayPerItem is not built");
+      REQUIRE_THROWS_WITH(face_array_per_cell.numberOfItems(), "SubItemArrayPerItem is not built");
+      REQUIRE_THROWS_WITH(face_array_per_cell.numberOfSubArrays(CellId{0}), "SubItemArrayPerItem is not built");
 
       CellArrayPerEdge<int> cell_array_per_edge;
-      REQUIRE_THROWS_AS(cell_array_per_edge[0], AssertError);
-      REQUIRE_THROWS_AS(cell_array_per_edge.itemTable(EdgeId{0}), AssertError);
-      REQUIRE_THROWS_AS(cell_array_per_edge(EdgeId{0}, 0), AssertError);
-      REQUIRE_THROWS_AS(cell_array_per_edge.sizeOfArrays(), AssertError);
-      REQUIRE_THROWS_AS(cell_array_per_edge.numberOfArrays(), AssertError);
-      REQUIRE_THROWS_AS(cell_array_per_edge.numberOfItems(), AssertError);
-      REQUIRE_THROWS_AS(cell_array_per_edge.numberOfSubArrays(EdgeId{0}), AssertError);
+      REQUIRE_THROWS_WITH(cell_array_per_edge[0], "SubItemArrayPerItem is not built");
+      REQUIRE_THROWS_WITH(cell_array_per_edge.itemTable(EdgeId{0}), "SubItemArrayPerItem is not built");
+      REQUIRE_THROWS_WITH(cell_array_per_edge(EdgeId{0}, 0), "SubItemArrayPerItem is not built");
+      REQUIRE_THROWS_WITH(cell_array_per_edge.sizeOfArrays(), "SubItemArrayPerItem is not built");
+      REQUIRE_THROWS_WITH(cell_array_per_edge.numberOfArrays(), "SubItemArrayPerItem is not built");
+      REQUIRE_THROWS_WITH(cell_array_per_edge.numberOfItems(), "SubItemArrayPerItem is not built");
+      REQUIRE_THROWS_WITH(cell_array_per_edge.numberOfSubArrays(EdgeId{0}), "SubItemArrayPerItem is not built");
 
       NodeArrayPerFace<int> node_array_per_face;
-      REQUIRE_THROWS_AS(node_array_per_face[0], AssertError);
-      REQUIRE_THROWS_AS(node_array_per_face.itemTable(FaceId{0}), AssertError);
-      REQUIRE_THROWS_AS(node_array_per_face(FaceId{0}, 0), AssertError);
-      REQUIRE_THROWS_AS(node_array_per_face.sizeOfArrays(), AssertError);
-      REQUIRE_THROWS_AS(node_array_per_face.numberOfArrays(), AssertError);
-      REQUIRE_THROWS_AS(node_array_per_face.numberOfItems(), AssertError);
-      REQUIRE_THROWS_AS(node_array_per_face.numberOfSubArrays(FaceId{0}), AssertError);
+      REQUIRE_THROWS_WITH(node_array_per_face[0], "SubItemArrayPerItem is not built");
+      REQUIRE_THROWS_WITH(node_array_per_face.itemTable(FaceId{0}), "SubItemArrayPerItem is not built");
+      REQUIRE_THROWS_WITH(node_array_per_face(FaceId{0}, 0), "SubItemArrayPerItem is not built");
+      REQUIRE_THROWS_WITH(node_array_per_face.sizeOfArrays(), "SubItemArrayPerItem is not built");
+      REQUIRE_THROWS_WITH(node_array_per_face.numberOfArrays(), "SubItemArrayPerItem is not built");
+      REQUIRE_THROWS_WITH(node_array_per_face.numberOfItems(), "SubItemArrayPerItem is not built");
+      REQUIRE_THROWS_WITH(node_array_per_face.numberOfSubArrays(FaceId{0}), "SubItemArrayPerItem is not built");
+    }
+
+    SECTION("checking invalid table size in constructor")
+    {
+      auto mesh_3d = MeshDataBaseForTests::get().hybrid3DMesh();
+
+      const Connectivity<3>& connectivity = mesh_3d->connectivity();
+
+      {
+        Table<int> table{connectivity.getMatrix(ItemType::node, ItemType::cell).numberOfValues() + 3, 2};
+        REQUIRE_THROWS_WITH(CellArrayPerNode<int>(connectivity, table), "invalid size of provided table");
+      }
+
+      {
+        Table<int> table{connectivity.getMatrix(ItemType::face, ItemType::edge).numberOfValues() + 3, 2};
+        REQUIRE_THROWS_WITH(EdgeArrayPerFace<int>(connectivity, table), "invalid size of provided table");
+      }
     }
 
     SECTION("checking for bounds violation")
@@ -1080,69 +1097,73 @@ TEST_CASE("SubItemArrayPerItem", "[mesh]")
           CellArrayPerFace<int> cell_array_per_face{connectivity, 3};
           {
             FaceId invalid_face_id = connectivity.numberOfFaces();
-            REQUIRE_THROWS_AS(cell_array_per_face(invalid_face_id, 0), AssertError);
+            REQUIRE_THROWS_WITH(cell_array_per_face(invalid_face_id, 0), "invalid item_id");
+            REQUIRE_THROWS_WITH(cell_array_per_face[invalid_face_id], "invalid item_id");
           }
           if (connectivity.numberOfFaces() > 0) {
             FaceId face_id         = 0;
             const auto& face_table = cell_array_per_face.itemTable(face_id);
-            REQUIRE_THROWS_AS(cell_array_per_face(face_id, face_table.numberOfRows()), AssertError);
-            REQUIRE_THROWS_AS(face_table[face_table.numberOfRows()], AssertError);
-            REQUIRE_THROWS_AS(cell_array_per_face.itemTable(face_id)[face_table.numberOfRows()], AssertError);
-            REQUIRE_THROWS_AS(cell_array_per_face.itemTable(face_id)[0][cell_array_per_face.sizeOfArrays()],
-                              AssertError);
-            REQUIRE_THROWS_AS(cell_array_per_face.itemTable(face_id)[0][cell_array_per_face.sizeOfArrays()] = 2,
-                              AssertError);
+            REQUIRE_THROWS_WITH(cell_array_per_face(face_id, face_table.numberOfRows()), "invalid index");
+            REQUIRE_THROWS_WITH(face_table[face_table.numberOfRows()], "invalid index");
+            REQUIRE_THROWS_WITH(cell_array_per_face.itemTable(face_id)[face_table.numberOfRows()], "invalid index");
+            REQUIRE_THROWS_WITH(cell_array_per_face.itemTable(face_id)[0][cell_array_per_face.sizeOfArrays()],
+                                "invalid index");
+            REQUIRE_THROWS_WITH(cell_array_per_face.itemTable(face_id)[0][cell_array_per_face.sizeOfArrays()] = 2,
+                                "invalid index");
           }
 
           FaceArrayPerNode<int> face_array_per_node{connectivity, 5};
           {
             NodeId invalid_node_id = connectivity.numberOfNodes();
-            REQUIRE_THROWS_AS(face_array_per_node(invalid_node_id, 0), AssertError);
+            REQUIRE_THROWS_WITH(face_array_per_node(invalid_node_id, 0), "invalid item_id");
+            REQUIRE_THROWS_WITH(face_array_per_node[invalid_node_id], "invalid item_id");
           }
           if (connectivity.numberOfNodes() > 0) {
             NodeId node_id         = 0;
             const auto& node_table = face_array_per_node.itemTable(node_id);
-            REQUIRE_THROWS_AS(face_array_per_node(node_id, node_table.numberOfRows()), AssertError);
-            REQUIRE_THROWS_AS(node_table[node_table.numberOfRows()], AssertError);
-            REQUIRE_THROWS_AS(face_array_per_node.itemTable(node_id)[node_table.numberOfRows()], AssertError);
-            REQUIRE_THROWS_AS(face_array_per_node.itemTable(node_id)[0][face_array_per_node.sizeOfArrays()],
-                              AssertError);
-            REQUIRE_THROWS_AS(face_array_per_node.itemTable(node_id)[0][face_array_per_node.sizeOfArrays()] = 2,
-                              AssertError);
+            REQUIRE_THROWS_WITH(face_array_per_node(node_id, node_table.numberOfRows()), "invalid index");
+            REQUIRE_THROWS_WITH(node_table[node_table.numberOfRows()], "invalid index");
+            REQUIRE_THROWS_WITH(face_array_per_node.itemTable(node_id)[node_table.numberOfRows()], "invalid index");
+            REQUIRE_THROWS_WITH(face_array_per_node.itemTable(node_id)[0][face_array_per_node.sizeOfArrays()],
+                                "invalid index");
+            REQUIRE_THROWS_WITH(face_array_per_node.itemTable(node_id)[0][face_array_per_node.sizeOfArrays()] = 2,
+                                "invalid index");
           }
 
           EdgeArrayPerCell<int> edge_array_per_cell{connectivity, 3};
           {
             CellId invalid_cell_id = connectivity.numberOfCells();
-            REQUIRE_THROWS_AS(edge_array_per_cell(invalid_cell_id, 0), AssertError);
+            REQUIRE_THROWS_WITH(edge_array_per_cell(invalid_cell_id, 0), "invalid item_id");
+            REQUIRE_THROWS_WITH(edge_array_per_cell[invalid_cell_id], "invalid item_id");
           }
           if (connectivity.numberOfCells() > 0) {
             CellId cell_id         = 0;
             const auto& cell_table = edge_array_per_cell.itemTable(cell_id);
-            REQUIRE_THROWS_AS(edge_array_per_cell(cell_id, cell_table.numberOfRows()), AssertError);
-            REQUIRE_THROWS_AS(cell_table[cell_table.numberOfRows()], AssertError);
-            REQUIRE_THROWS_AS(edge_array_per_cell.itemTable(cell_id)[cell_table.numberOfRows()], AssertError);
-            REQUIRE_THROWS_AS(edge_array_per_cell.itemTable(cell_id)[0][edge_array_per_cell.sizeOfArrays()],
-                              AssertError);
-            REQUIRE_THROWS_AS(edge_array_per_cell.itemTable(cell_id)[0][edge_array_per_cell.sizeOfArrays()] == 2,
-                              AssertError);
+            REQUIRE_THROWS_WITH(edge_array_per_cell(cell_id, cell_table.numberOfRows()), "invalid index");
+            REQUIRE_THROWS_WITH(cell_table[cell_table.numberOfRows()], "invalid index");
+            REQUIRE_THROWS_WITH(edge_array_per_cell.itemTable(cell_id)[cell_table.numberOfRows()], "invalid index");
+            REQUIRE_THROWS_WITH(edge_array_per_cell.itemTable(cell_id)[0][edge_array_per_cell.sizeOfArrays()],
+                                "invalid index");
+            REQUIRE_THROWS_WITH(edge_array_per_cell.itemTable(cell_id)[0][edge_array_per_cell.sizeOfArrays()] == 2,
+                                "invalid index");
           }
 
           NodeArrayPerEdge<int> node_array_per_edge{connectivity, 3};
           {
             EdgeId invalid_edge_id = connectivity.numberOfEdges();
-            REQUIRE_THROWS_AS(node_array_per_edge(invalid_edge_id, 0), AssertError);
+            REQUIRE_THROWS_WITH(node_array_per_edge(invalid_edge_id, 0), "invalid item_id");
+            REQUIRE_THROWS_WITH(node_array_per_edge[invalid_edge_id], "invalid item_id");
           }
           if (connectivity.numberOfEdges() > 0) {
             EdgeId edge_id         = 0;
             const auto& edge_table = node_array_per_edge.itemTable(edge_id);
-            REQUIRE_THROWS_AS(node_array_per_edge(edge_id, edge_table.numberOfRows()), AssertError);
-            REQUIRE_THROWS_AS(edge_table[edge_table.numberOfRows()], AssertError);
-            REQUIRE_THROWS_AS(node_array_per_edge.itemTable(edge_id)[edge_table.numberOfRows()], AssertError);
-            REQUIRE_THROWS_AS(node_array_per_edge.itemTable(edge_id)[0][node_array_per_edge.sizeOfArrays()],
-                              AssertError);
-            REQUIRE_THROWS_AS(node_array_per_edge.itemTable(edge_id)[0][node_array_per_edge.sizeOfArrays()] = 2,
-                              AssertError);
+            REQUIRE_THROWS_WITH(node_array_per_edge(edge_id, edge_table.numberOfRows()), "invalid index");
+            REQUIRE_THROWS_WITH(edge_table[edge_table.numberOfRows()], "invalid index");
+            REQUIRE_THROWS_WITH(node_array_per_edge.itemTable(edge_id)[edge_table.numberOfRows()], "invalid index");
+            REQUIRE_THROWS_WITH(node_array_per_edge.itemTable(edge_id)[0][node_array_per_edge.sizeOfArrays()],
+                                "invalid index");
+            REQUIRE_THROWS_WITH(node_array_per_edge.itemTable(edge_id)[0][node_array_per_edge.sizeOfArrays()] = 2,
+                                "invalid index");
           }
         }
       }
-- 
GitLab