https://github.com/vhscampos updated https://github.com/llvm/llvm-project/pull/108590
>From a2438ce9a61d8e80aa32fa58ca5368a64deacd52 Mon Sep 17 00:00:00 2001 From: Victor Campos <victor.cam...@arm.com> Date: Fri, 9 Aug 2024 13:56:31 +0100 Subject: [PATCH 1/4] [ADT] Use range-based helper functions in SmallSet Replace code that relies on iterators by LLVM helper functions that take ranges. This makes the code simpler and more readable. --- llvm/include/llvm/ADT/SmallSet.h | 36 +++++++++----------------------- 1 file changed, 10 insertions(+), 26 deletions(-) diff --git a/llvm/include/llvm/ADT/SmallSet.h b/llvm/include/llvm/ADT/SmallSet.h index 630c98504261aa..d5f64e4f20f854 100644 --- a/llvm/include/llvm/ADT/SmallSet.h +++ b/llvm/include/llvm/ADT/SmallSet.h @@ -139,10 +139,6 @@ class SmallSet { SmallVector<T, N> Vector; std::set<T, C> Set; - using VIterator = typename SmallVector<T, N>::const_iterator; - using SIterator = typename std::set<T, C>::const_iterator; - using mutable_iterator = typename SmallVector<T, N>::iterator; - // In small mode SmallPtrSet uses linear search for the elements, so it is // not a good idea to choose this value too high. You may consider using a // DenseSet<> instead if you expect many elements in the set. @@ -163,13 +159,7 @@ class SmallSet { } /// count - Return 1 if the element is in the set, 0 otherwise. - size_type count(const T &V) const { - if (isSmall()) { - // Since the collection is small, just do a linear search. - return vfind(V) == Vector.end() ? 0 : 1; - } - return Set.count(V); - } + size_type count(const T &V) const { return contains(V) ? 1 : 0; } /// insert - Insert an element into the set if it isn't already there. /// Returns a pair. The first value of it is an iterator to the inserted @@ -181,7 +171,7 @@ class SmallSet { return std::make_pair(const_iterator(I), Inserted); } - VIterator I = vfind(V); + auto I = llvm::find(Vector, V); if (I != Vector.end()) // Don't reinsert if it already exists. return std::make_pair(const_iterator(I), false); if (Vector.size() < N) { @@ -206,11 +196,12 @@ class SmallSet { bool erase(const T &V) { if (!isSmall()) return Set.erase(V); - for (mutable_iterator I = Vector.begin(), E = Vector.end(); I != E; ++I) - if (*I == V) { - Vector.erase(I); - return true; - } + + auto It = llvm::find(Vector, V); + if (It != Vector.end()) { + Vector.erase(It); + return true; + } return false; } @@ -234,19 +225,12 @@ class SmallSet { /// Check if the SmallSet contains the given element. bool contains(const T &V) const { if (isSmall()) - return vfind(V) != Vector.end(); - return Set.find(V) != Set.end(); + return llvm::is_contained(Vector, V); + return llvm::is_contained(Set, V); } private: bool isSmall() const { return Set.empty(); } - - VIterator vfind(const T &V) const { - for (VIterator I = Vector.begin(), E = Vector.end(); I != E; ++I) - if (*I == V) - return I; - return Vector.end(); - } }; /// If this set is of pointer values, transparently switch over to using >From e0295a14694c5bba65a873914eb700b201e94b6a Mon Sep 17 00:00:00 2001 From: Victor Campos <victor.cam...@arm.com> Date: Fri, 9 Aug 2024 13:57:42 +0100 Subject: [PATCH 2/4] [ADT] Use perfect forwarding in SmallSet::insert() Previously this method took arguments by const-ref. This patch changes the implementation to take perfectly forwarded arguments in the form of a universal reference. Now, the insertion method will take advantage of arguments passed as rvalue, potentially leading to performance improvements. --- llvm/include/llvm/ADT/SmallSet.h | 47 +++++++++++++++++++------------- 1 file changed, 28 insertions(+), 19 deletions(-) diff --git a/llvm/include/llvm/ADT/SmallSet.h b/llvm/include/llvm/ADT/SmallSet.h index d5f64e4f20f854..c8641111eda8f8 100644 --- a/llvm/include/llvm/ADT/SmallSet.h +++ b/llvm/include/llvm/ADT/SmallSet.h @@ -165,26 +165,10 @@ class SmallSet { /// Returns a pair. The first value of it is an iterator to the inserted /// element or the existing element in the set. The second value is true /// if the element is inserted (it was not in the set before). - std::pair<const_iterator, bool> insert(const T &V) { - if (!isSmall()) { - auto [I, Inserted] = Set.insert(V); - return std::make_pair(const_iterator(I), Inserted); - } + std::pair<const_iterator, bool> insert(const T &V) { return insertImpl(V); } - auto I = llvm::find(Vector, V); - if (I != Vector.end()) // Don't reinsert if it already exists. - return std::make_pair(const_iterator(I), false); - if (Vector.size() < N) { - Vector.push_back(V); - return std::make_pair(const_iterator(std::prev(Vector.end())), true); - } - - // Otherwise, grow from vector to set. - while (!Vector.empty()) { - Set.insert(Vector.back()); - Vector.pop_back(); - } - return std::make_pair(const_iterator(Set.insert(V).first), true); + std::pair<const_iterator, bool> insert(T &&V) { + return insertImpl(std::move(V)); } template <typename IterT> @@ -231,6 +215,31 @@ class SmallSet { private: bool isSmall() const { return Set.empty(); } + + template <typename ArgType> + std::pair<const_iterator, bool> insertImpl(ArgType &&V) { + static_assert(std::is_convertible_v<ArgType, T>, + "ArgType must be convertible to T!"); + if (!isSmall()) { + auto [I, Inserted] = Set.insert(std::forward<ArgType>(V)); + return std::make_pair(const_iterator(I), Inserted); + } + + auto I = llvm::find(Vector, V); + if (I != Vector.end()) // Don't reinsert if it already exists. + return std::make_pair(const_iterator(I), false); + if (Vector.size() < N) { + Vector.push_back(std::forward<ArgType>(V)); + return std::make_pair(const_iterator(std::prev(Vector.end())), true); + } + + // Otherwise, grow from vector to set. + Set.insert(std::make_move_iterator(Vector.begin()), + std::make_move_iterator(Vector.end())); + Vector.clear(); + return std::make_pair( + const_iterator(Set.insert(std::forward<ArgType>(V)).first), true); + } }; /// If this set is of pointer values, transparently switch over to using >From 47c7444d4391d3bcbead2bb86a09ae051e0c4802 Mon Sep 17 00:00:00 2001 From: Victor Campos <victor.cam...@arm.com> Date: Tue, 17 Sep 2024 13:11:00 +0100 Subject: [PATCH 3/4] Add test for SmallSet::insert perfect forwarding --- llvm/unittests/ADT/SmallSetTest.cpp | 34 +++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/llvm/unittests/ADT/SmallSetTest.cpp b/llvm/unittests/ADT/SmallSetTest.cpp index b50b368ae66361..0fb20b19df9254 100644 --- a/llvm/unittests/ADT/SmallSetTest.cpp +++ b/llvm/unittests/ADT/SmallSetTest.cpp @@ -41,6 +41,40 @@ TEST(SmallSetTest, Insert) { EXPECT_EQ(0u, s1.count(4)); } +TEST(SmallSetTest, InsertPerfectFwd) { + struct Value { + int Key; + bool Moved; + + Value(int Key) : Key(Key), Moved(false) {} + Value(const Value &) = default; + Value(Value &&Other) : Key(Other.Key), Moved(false) { Other.Moved = true; } + bool operator==(const Value &Other) const { return Key == Other.Key; } + bool operator<(const Value &Other) const { return Key < Other.Key; } + }; + + { + SmallSet<Value, 4> S; + Value V1(1), V2(2); + + S.insert(V1); + EXPECT_EQ(V1.Moved, false); + + S.insert(std::move(V2)); + EXPECT_EQ(V2.Moved, true); + } + { + SmallSet<Value, 1> S; + Value V1(1), V2(2); + + S.insert(V1); + EXPECT_EQ(V1.Moved, false); + + S.insert(std::move(V2)); + EXPECT_EQ(V2.Moved, true); + } +} + TEST(SmallSetTest, Grow) { SmallSet<int, 4> s1; >From a2eb49509529eb0a04346e50f64aa071b91e8c93 Mon Sep 17 00:00:00 2001 From: Victor Campos <victor.cam...@arm.com> Date: Tue, 17 Sep 2024 13:16:24 +0100 Subject: [PATCH 4/4] Style changes --- llvm/include/llvm/ADT/SmallSet.h | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/llvm/include/llvm/ADT/SmallSet.h b/llvm/include/llvm/ADT/SmallSet.h index c8641111eda8f8..2beaf2b92c028b 100644 --- a/llvm/include/llvm/ADT/SmallSet.h +++ b/llvm/include/llvm/ADT/SmallSet.h @@ -222,23 +222,22 @@ class SmallSet { "ArgType must be convertible to T!"); if (!isSmall()) { auto [I, Inserted] = Set.insert(std::forward<ArgType>(V)); - return std::make_pair(const_iterator(I), Inserted); + return {const_iterator(I), Inserted}; } - auto I = llvm::find(Vector, V); - if (I != Vector.end()) // Don't reinsert if it already exists. - return std::make_pair(const_iterator(I), false); + if (auto I = llvm::find(Vector, V); + I != Vector.end()) // Don't reinsert if it already exists. + return {const_iterator(I), false}; if (Vector.size() < N) { Vector.push_back(std::forward<ArgType>(V)); - return std::make_pair(const_iterator(std::prev(Vector.end())), true); + return {const_iterator(std::prev(Vector.end())), true}; } // Otherwise, grow from vector to set. Set.insert(std::make_move_iterator(Vector.begin()), std::make_move_iterator(Vector.end())); Vector.clear(); - return std::make_pair( - const_iterator(Set.insert(std::forward<ArgType>(V)).first), true); + return {const_iterator(Set.insert(std::forward<ArgType>(V)).first), true}; } }; _______________________________________________ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits