[llvm] 797330e - [ADT][NFCI]: Fix iterator category for graph iterators with external storage (#116403)
via llvm-commits
llvm-commits at lists.llvm.org
Sat Nov 16 11:46:18 PST 2024
Author: Mészáros Gergely
Date: 2024-11-16T20:46:15+01:00
New Revision: 797330e96c5abf0f1c623c1eb5ca69de28b484be
URL: https://github.com/llvm/llvm-project/commit/797330e96c5abf0f1c623c1eb5ca69de28b484be
DIFF: https://github.com/llvm/llvm-project/commit/797330e96c5abf0f1c623c1eb5ca69de28b484be.diff
LOG: [ADT][NFCI]: Fix iterator category for graph iterators with external storage (#116403)
Set the iterator category for graph iterators to input_iterator_tag when
the visited set is stored externally. In that case we can't provide
multi-pass guarantee, so we should not claim to be a forward iterator.
Fixes: #116400
Added:
Modified:
llvm/include/llvm/ADT/DepthFirstIterator.h
llvm/include/llvm/ADT/PostOrderIterator.h
llvm/unittests/ADT/BreadthFirstIteratorTest.cpp
llvm/unittests/ADT/DepthFirstIteratorTest.cpp
llvm/unittests/ADT/PostOrderIteratorTest.cpp
Removed:
################################################################################
diff --git a/llvm/include/llvm/ADT/DepthFirstIterator.h b/llvm/include/llvm/ADT/DepthFirstIterator.h
index 71053c2d0d8a8e..4ced758343806e 100644
--- a/llvm/include/llvm/ADT/DepthFirstIterator.h
+++ b/llvm/include/llvm/ADT/DepthFirstIterator.h
@@ -39,6 +39,7 @@
#include "llvm/ADT/iterator_range.h"
#include <iterator>
#include <optional>
+#include <type_traits>
#include <utility>
#include <vector>
@@ -84,7 +85,10 @@ template <class GraphT,
bool ExtStorage = false, class GT = GraphTraits<GraphT>>
class df_iterator : public df_iterator_storage<SetType, ExtStorage> {
public:
- using iterator_category = std::forward_iterator_tag;
+ // When External storage is used we are not multi-pass safe.
+ using iterator_category =
+ std::conditional_t<ExtStorage, std::input_iterator_tag,
+ std::forward_iterator_tag>;
using value_type = typename GT::NodeRef;
using
diff erence_type = std::ptr
diff _t;
using pointer = value_type *;
diff --git a/llvm/include/llvm/ADT/PostOrderIterator.h b/llvm/include/llvm/ADT/PostOrderIterator.h
index edf0401a751708..1cbd3c170052c7 100644
--- a/llvm/include/llvm/ADT/PostOrderIterator.h
+++ b/llvm/include/llvm/ADT/PostOrderIterator.h
@@ -23,6 +23,7 @@
#include <iterator>
#include <optional>
#include <set>
+#include <type_traits>
#include <utility>
namespace llvm {
@@ -95,7 +96,10 @@ template <class GraphT,
bool ExtStorage = false, class GT = GraphTraits<GraphT>>
class po_iterator : public po_iterator_storage<SetType, ExtStorage> {
public:
- using iterator_category = std::forward_iterator_tag;
+ // When External storage is used we are not multi-pass safe.
+ using iterator_category =
+ std::conditional_t<ExtStorage, std::input_iterator_tag,
+ std::forward_iterator_tag>;
using value_type = typename GT::NodeRef;
using
diff erence_type = std::ptr
diff _t;
using pointer = value_type *;
diff --git a/llvm/unittests/ADT/BreadthFirstIteratorTest.cpp b/llvm/unittests/ADT/BreadthFirstIteratorTest.cpp
index 5428c644d9ab2a..0cd7fd3f706f04 100644
--- a/llvm/unittests/ADT/BreadthFirstIteratorTest.cpp
+++ b/llvm/unittests/ADT/BreadthFirstIteratorTest.cpp
@@ -10,6 +10,12 @@
#include "TestGraph.h"
#include "gtest/gtest.h"
+#include <array>
+#include <iterator>
+#include <type_traits>
+
+#include <cstddef>
+
using namespace llvm;
namespace llvm {
@@ -74,4 +80,29 @@ static_assert(
std::is_convertible_v<decltype(*std::declval<bf_iterator<Graph<3>>>()),
typename bf_iterator<Graph<3>>::reference>);
+// bf_iterator should be (at-least) a forward-iterator
+static_assert(std::is_base_of_v<std::forward_iterator_tag,
+ bf_iterator<Graph<4>>::iterator_category>);
+
+TEST(BreadthFristIteratorTest, MultiPassSafeWithInternalSet) {
+ Graph<4> G;
+ G.AddEdge(0, 1);
+ G.AddEdge(1, 2);
+ G.AddEdge(1, 3);
+
+ std::array<decltype(G)::NodeType *, 4> NodesFirstPass, NodesSecondPass;
+
+ auto B = bf_begin(G), E = bf_end(G);
+
+ std::size_t I = 0;
+ for (auto It = B; It != E; ++It)
+ NodesFirstPass[I++] = *It;
+
+ I = 0;
+ for (auto It = B; It != E; ++It)
+ NodesSecondPass[I++] = *It;
+
+ EXPECT_EQ(NodesFirstPass, NodesSecondPass);
+}
+
} // end namespace llvm
diff --git a/llvm/unittests/ADT/DepthFirstIteratorTest.cpp b/llvm/unittests/ADT/DepthFirstIteratorTest.cpp
index 007b6839f4d05d..95923b81008389 100644
--- a/llvm/unittests/ADT/DepthFirstIteratorTest.cpp
+++ b/llvm/unittests/ADT/DepthFirstIteratorTest.cpp
@@ -10,6 +10,12 @@
#include "TestGraph.h"
#include "gtest/gtest.h"
+#include <array>
+#include <iterator>
+#include <type_traits>
+
+#include <cstddef>
+
using namespace llvm;
namespace llvm {
@@ -55,4 +61,33 @@ static_assert(
std::is_convertible_v<decltype(*std::declval<df_iterator<Graph<3>>>()),
typename df_iterator<Graph<3>>::reference>);
+// df_iterator should be (at-least) a forward-iterator
+static_assert(std::is_base_of_v<std::forward_iterator_tag,
+ df_iterator<Graph<4>>::iterator_category>);
+
+// df_ext_iterator cannot provide multi-pass guarantee, therefore its only
+// an input-iterator
+static_assert(std::is_same_v<df_ext_iterator<Graph<4>>::iterator_category,
+ std::input_iterator_tag>);
+
+TEST(DepthFirstIteratorTest, MultiPassSafeWithInternalSet) {
+ Graph<4> G;
+ G.AddEdge(0, 1);
+ G.AddEdge(1, 2);
+ G.AddEdge(1, 3);
+
+ std::array<decltype(G)::NodeType *, 4> NodesFirstPass, NodesSecondPass;
+
+ auto B = df_begin(G), E = df_end(G);
+
+ std::size_t I = 0;
+ for (auto It = B; It != E; ++It)
+ NodesFirstPass[I++] = *It;
+
+ I = 0;
+ for (auto It = B; It != E; ++It)
+ NodesSecondPass[I++] = *It;
+
+ EXPECT_EQ(NodesFirstPass, NodesSecondPass);
+}
}
diff --git a/llvm/unittests/ADT/PostOrderIteratorTest.cpp b/llvm/unittests/ADT/PostOrderIteratorTest.cpp
index 17c84229cbc4d8..4c2a66e8d5b626 100644
--- a/llvm/unittests/ADT/PostOrderIteratorTest.cpp
+++ b/llvm/unittests/ADT/PostOrderIteratorTest.cpp
@@ -11,6 +11,12 @@
#include "gtest/gtest.h"
#include "TestGraph.h"
+#include <array>
+#include <iterator>
+#include <type_traits>
+
+#include <cstddef>
+
using namespace llvm;
namespace {
@@ -75,4 +81,34 @@ TEST(PostOrderIteratorTest, PostOrderAndReversePostOrderTraverrsal) {
EXPECT_EQ(1, FromIterator[4]);
EXPECT_EQ(4, FromIterator[5]);
}
+
+// po_iterator should be (at-least) a forward-iterator
+static_assert(std::is_base_of_v<std::forward_iterator_tag,
+ po_iterator<Graph<4>>::iterator_category>);
+
+// po_ext_iterator cannot provide multi-pass guarantee, therefore its only
+// an input-iterator
+static_assert(std::is_same_v<po_ext_iterator<Graph<4>>::iterator_category,
+ std::input_iterator_tag>);
+
+TEST(PostOrderIteratorTest, MultiPassSafeWithInternalSet) {
+ Graph<4> G;
+ G.AddEdge(0, 1);
+ G.AddEdge(1, 2);
+ G.AddEdge(1, 3);
+
+ std::array<decltype(G)::NodeType *, 4> NodesFirstPass, NodesSecondPass;
+
+ auto B = po_begin(G), E = po_end(G);
+
+ std::size_t I = 0;
+ for (auto It = B; It != E; ++It)
+ NodesFirstPass[I++] = *It;
+
+ I = 0;
+ for (auto It = B; It != E; ++It)
+ NodesSecondPass[I++] = *It;
+
+ EXPECT_EQ(NodesFirstPass, NodesSecondPass);
+}
}
More information about the llvm-commits
mailing list