From cb974bf5671c757cbce2e0248787bad616b06bf9 Mon Sep 17 00:00:00 2001 From: Michele Caini Date: Tue, 13 Jun 2023 11:54:29 +0200 Subject: [PATCH] adjacency_matrix: fix in_edges() is off by 1 in some cases (close #1019) --- src/entt/graph/adjacency_matrix.hpp | 4 +- test/entt/graph/adjacency_matrix.cpp | 128 +++++++++++++++++++++++++++ 2 files changed, 130 insertions(+), 2 deletions(-) diff --git a/src/entt/graph/adjacency_matrix.hpp b/src/entt/graph/adjacency_matrix.hpp index b0b0e254ba..8fc0a5a62e 100644 --- a/src/entt/graph/adjacency_matrix.hpp +++ b/src/entt/graph/adjacency_matrix.hpp @@ -258,7 +258,7 @@ class adjacency_matrix { [[nodiscard]] iterable_adaptor out_edges(const vertex_type vertex) const noexcept { const auto it = matrix.cbegin(); const auto from = vertex * vert; - const auto to = vertex * vert + vert; + const auto to = from + vert; return {{it, vert, from, to, 1u}, {it, vert, to, to, 1u}}; } @@ -270,7 +270,7 @@ class adjacency_matrix { [[nodiscard]] iterable_adaptor in_edges(const vertex_type vertex) const noexcept { const auto it = matrix.cbegin(); const auto from = vertex; - const auto to = vert * (vert - 1u) + vertex; + const auto to = vert * vert + from; return {{it, vert, from, to, vert}, {it, vert, to, to, vert}}; } diff --git a/test/entt/graph/adjacency_matrix.cpp b/test/entt/graph/adjacency_matrix.cpp index d2bf4106c1..3ec250bac1 100644 --- a/test/entt/graph/adjacency_matrix.cpp +++ b/test/entt/graph/adjacency_matrix.cpp @@ -295,6 +295,23 @@ TEST(AdjacencyMatrix, EdgesDirected) { ASSERT_EQ(++it, iterable.end()); } +TEST(AdjacencyMatrix, EdgesBackwardOnlyDirected) { + entt::adjacency_matrix adjacency_matrix{2u}; + auto iterable = adjacency_matrix.edges(); + + ASSERT_EQ(iterable.begin(), iterable.end()); + + adjacency_matrix.insert(1u, 0u); + iterable = adjacency_matrix.edges(); + + ASSERT_NE(iterable.begin(), iterable.end()); + + auto it = iterable.begin(); + + ASSERT_EQ(*it++, std::make_pair(std::size_t{1u}, std::size_t{0u})); + ASSERT_EQ(it, iterable.end()); +} + TEST(AdjacencyMatrix, EdgesUndirected) { entt::adjacency_matrix adjacency_matrix{3u}; auto iterable = adjacency_matrix.edges(); @@ -317,6 +334,24 @@ TEST(AdjacencyMatrix, EdgesUndirected) { ASSERT_EQ(++it, iterable.end()); } +TEST(AdjacencyMatrix, EdgesBackwardOnlyUndirected) { + entt::adjacency_matrix adjacency_matrix{2u}; + auto iterable = adjacency_matrix.edges(); + + ASSERT_EQ(iterable.begin(), iterable.end()); + + adjacency_matrix.insert(1u, 0u); + iterable = adjacency_matrix.edges(); + + ASSERT_NE(iterable.begin(), iterable.end()); + + auto it = iterable.begin(); + + ASSERT_EQ(*it++, std::make_pair(std::size_t{0u}, std::size_t{1u})); + ASSERT_EQ(*it++, std::make_pair(std::size_t{1u}, std::size_t{0u})); + ASSERT_EQ(it, iterable.end()); +} + TEST(AdjacencyMatrix, OutEdgesDirected) { entt::adjacency_matrix adjacency_matrix{3u}; auto iterable = adjacency_matrix.out_edges(0u); @@ -340,6 +375,28 @@ TEST(AdjacencyMatrix, OutEdgesDirected) { ASSERT_EQ(it, iterable.cend()); } +TEST(AdjacencyMatrix, OutEdgesBackwardOnlyDirected) { + entt::adjacency_matrix adjacency_matrix{2u}; + auto iterable = adjacency_matrix.out_edges(1u); + + ASSERT_EQ(iterable.begin(), iterable.end()); + + adjacency_matrix.insert(1u, 0u); + iterable = adjacency_matrix.out_edges(1u); + + ASSERT_NE(iterable.begin(), iterable.end()); + + auto it = iterable.begin(); + + ASSERT_EQ(*it++, std::make_pair(std::size_t{1u}, std::size_t{0u})); + ASSERT_EQ(it, iterable.end()); + + iterable = adjacency_matrix.out_edges(0u); + it = iterable.cbegin(); + + ASSERT_EQ(it, iterable.cend()); +} + TEST(AdjacencyMatrix, OutEdgesUndirected) { entt::adjacency_matrix adjacency_matrix{3u}; auto iterable = adjacency_matrix.out_edges(0u); @@ -365,6 +422,30 @@ TEST(AdjacencyMatrix, OutEdgesUndirected) { ASSERT_EQ(it, iterable.cend()); } +TEST(AdjacencyMatrix, OutEdgesBackwardOnlyUndirected) { + entt::adjacency_matrix adjacency_matrix{2u}; + auto iterable = adjacency_matrix.out_edges(1u); + + ASSERT_EQ(iterable.begin(), iterable.end()); + + adjacency_matrix.insert(1u, 0u); + iterable = adjacency_matrix.out_edges(1u); + + ASSERT_NE(iterable.begin(), iterable.end()); + + auto it = iterable.begin(); + + ASSERT_EQ(*it++, std::make_pair(std::size_t{1u}, std::size_t{0u})); + ASSERT_EQ(it, iterable.end()); + + iterable = adjacency_matrix.out_edges(0u); + it = iterable.cbegin(); + + ASSERT_NE(it, iterable.cend()); + ASSERT_EQ(*it++, std::make_pair(std::size_t{0u}, std::size_t{1u})); + ASSERT_EQ(it, iterable.cend()); +} + TEST(AdjacencyMatrix, InEdgesDirected) { entt::adjacency_matrix adjacency_matrix{3u}; auto iterable = adjacency_matrix.in_edges(1u); @@ -388,6 +469,28 @@ TEST(AdjacencyMatrix, InEdgesDirected) { ASSERT_EQ(it, iterable.cend()); } +TEST(AdjacencyMatrix, InEdgesBackwardOnlyDirected) { + entt::adjacency_matrix adjacency_matrix{2u}; + auto iterable = adjacency_matrix.in_edges(0u); + + ASSERT_EQ(iterable.begin(), iterable.end()); + + adjacency_matrix.insert(1u, 0u); + iterable = adjacency_matrix.in_edges(0u); + + ASSERT_NE(iterable.begin(), iterable.end()); + + auto it = iterable.begin(); + + ASSERT_EQ(*it++, std::make_pair(std::size_t{1u}, std::size_t{0u})); + ASSERT_EQ(it, iterable.end()); + + iterable = adjacency_matrix.in_edges(1u); + it = iterable.cbegin(); + + ASSERT_EQ(it, iterable.cend()); +} + TEST(AdjacencyMatrix, InEdgesUndirected) { entt::adjacency_matrix adjacency_matrix{3u}; auto iterable = adjacency_matrix.in_edges(1u); @@ -403,6 +506,7 @@ TEST(AdjacencyMatrix, InEdgesUndirected) { auto it = iterable.begin(); ASSERT_EQ(*it++, std::make_pair(std::size_t{0u}, std::size_t{1u})); + ASSERT_EQ(*it++, std::make_pair(std::size_t{2u}, std::size_t{1u})); ASSERT_EQ(it, iterable.end()); iterable = adjacency_matrix.in_edges(0u); @@ -413,6 +517,30 @@ TEST(AdjacencyMatrix, InEdgesUndirected) { ASSERT_EQ(it, iterable.cend()); } +TEST(AdjacencyMatrix, InEdgesBackwardOnlyUndirected) { + entt::adjacency_matrix adjacency_matrix{2u}; + auto iterable = adjacency_matrix.in_edges(0u); + + ASSERT_EQ(iterable.begin(), iterable.end()); + + adjacency_matrix.insert(1u, 0u); + iterable = adjacency_matrix.in_edges(0u); + + ASSERT_NE(iterable.begin(), iterable.end()); + + auto it = iterable.begin(); + + ASSERT_EQ(*it++, std::make_pair(std::size_t{1u}, std::size_t{0u})); + ASSERT_EQ(it, iterable.end()); + + iterable = adjacency_matrix.in_edges(1u); + it = iterable.cbegin(); + + ASSERT_NE(it, iterable.cend()); + ASSERT_EQ(*it++, std::make_pair(std::size_t{0u}, std::size_t{1u})); + ASSERT_EQ(it, iterable.cend()); +} + TEST(AdjacencyMatrix, ThrowingAllocator) { using allocator = test::throwing_allocator; using exception = typename allocator::exception_type;