[llvm] [NFC] Use unique_ptr in SparseSet (PR #116617)

Akshat Oke via llvm-commits llvm-commits at lists.llvm.org
Fri Nov 22 03:22:16 PST 2024


https://github.com/optimisan updated https://github.com/llvm/llvm-project/pull/116617

>From 367e6fbb6c5ba45723cd9afe3dbaeaced84d0c6b Mon Sep 17 00:00:00 2001
From: Akshat Oke <Akshat.Oke at amd.com>
Date: Mon, 18 Nov 2024 10:15:19 +0000
Subject: [PATCH 1/2] [NFC] Use unique_ptr in SparseSet

This allows implementing the move constructor.
---
 llvm/include/llvm/ADT/SparseSet.h | 18 +++++++++++-------
 1 file changed, 11 insertions(+), 7 deletions(-)

diff --git a/llvm/include/llvm/ADT/SparseSet.h b/llvm/include/llvm/ADT/SparseSet.h
index c7793117ff5408..1adae0d4595ac4 100644
--- a/llvm/include/llvm/ADT/SparseSet.h
+++ b/llvm/include/llvm/ADT/SparseSet.h
@@ -129,7 +129,12 @@ class SparseSet {
   using DenseT = SmallVector<ValueT, 8>;
   using size_type = unsigned;
   DenseT Dense;
-  SparseT *Sparse = nullptr;
+
+  struct Deleter {
+    void operator()(SparseT *S) { free(S); }
+  };
+  std::unique_ptr<SparseT, Deleter> Sparse;
+
   unsigned Universe = 0;
   KeyFunctorT KeyIndexOf;
   SparseSetValFunctor<KeyT, ValueT, KeyFunctorT> ValIndexOf;
@@ -144,7 +149,7 @@ class SparseSet {
   SparseSet() = default;
   SparseSet(const SparseSet &) = delete;
   SparseSet &operator=(const SparseSet &) = delete;
-  ~SparseSet() { free(Sparse); }
+  SparseSet(SparseSet &&) = default;
 
   /// setUniverse - Set the universe size which determines the largest key the
   /// set can hold.  The universe must be sized before any elements can be
@@ -159,11 +164,10 @@ class SparseSet {
     // Hysteresis prevents needless reallocations.
     if (U >= Universe/4 && U <= Universe)
       return;
-    free(Sparse);
     // The Sparse array doesn't actually need to be initialized, so malloc
     // would be enough here, but that will cause tools like valgrind to
     // complain about branching on uninitialized data.
-    Sparse = static_cast<SparseT*>(safe_calloc(U, sizeof(SparseT)));
+    Sparse.reset(static_cast<SparseT *>(safe_calloc(U, sizeof(SparseT))));
     Universe = U;
   }
 
@@ -205,7 +209,7 @@ class SparseSet {
     assert(Idx < Universe && "Key out of range");
     assert(Sparse != nullptr && "Invalid sparse type");
     const unsigned Stride = std::numeric_limits<SparseT>::max() + 1u;
-    for (unsigned i = Sparse[Idx], e = size(); i < e; i += Stride) {
+    for (unsigned i = Sparse.get()[Idx], e = size(); i < e; i += Stride) {
       const unsigned FoundIdx = ValIndexOf(Dense[i]);
       assert(FoundIdx < Universe && "Invalid key in set. Did object mutate?");
       if (Idx == FoundIdx)
@@ -255,7 +259,7 @@ class SparseSet {
     iterator I = findIndex(Idx);
     if (I != end())
       return std::make_pair(I, false);
-    Sparse[Idx] = size();
+    Sparse.get()[Idx] = size();
     Dense.push_back(Val);
     return std::make_pair(end() - 1, true);
   }
@@ -292,7 +296,7 @@ class SparseSet {
       *I = Dense.back();
       unsigned BackIdx = ValIndexOf(Dense.back());
       assert(BackIdx < Universe && "Invalid key in set. Did object mutate?");
-      Sparse[BackIdx] = I - begin();
+      Sparse.get()[BackIdx] = I - begin();
     }
     // This depends on SmallVector::pop_back() not invalidating iterators.
     // std::vector::pop_back() doesn't give that guarantee.

>From 175470ec484e1fdff8b2c2eda7b6b84c6787b05a Mon Sep 17 00:00:00 2001
From: Akshat Oke <Akshat.Oke at amd.com>
Date: Tue, 19 Nov 2024 08:40:06 +0000
Subject: [PATCH 2/2] Use SparseT[] and add test

---
 llvm/include/llvm/ADT/SparseSet.h    |  8 ++++----
 llvm/unittests/ADT/SparseSetTest.cpp | 12 ++++++++++++
 2 files changed, 16 insertions(+), 4 deletions(-)

diff --git a/llvm/include/llvm/ADT/SparseSet.h b/llvm/include/llvm/ADT/SparseSet.h
index 1adae0d4595ac4..d9ded9875d3779 100644
--- a/llvm/include/llvm/ADT/SparseSet.h
+++ b/llvm/include/llvm/ADT/SparseSet.h
@@ -133,7 +133,7 @@ class SparseSet {
   struct Deleter {
     void operator()(SparseT *S) { free(S); }
   };
-  std::unique_ptr<SparseT, Deleter> Sparse;
+  std::unique_ptr<SparseT[], Deleter> Sparse;
 
   unsigned Universe = 0;
   KeyFunctorT KeyIndexOf;
@@ -209,7 +209,7 @@ class SparseSet {
     assert(Idx < Universe && "Key out of range");
     assert(Sparse != nullptr && "Invalid sparse type");
     const unsigned Stride = std::numeric_limits<SparseT>::max() + 1u;
-    for (unsigned i = Sparse.get()[Idx], e = size(); i < e; i += Stride) {
+    for (unsigned i = Sparse[Idx], e = size(); i < e; i += Stride) {
       const unsigned FoundIdx = ValIndexOf(Dense[i]);
       assert(FoundIdx < Universe && "Invalid key in set. Did object mutate?");
       if (Idx == FoundIdx)
@@ -259,7 +259,7 @@ class SparseSet {
     iterator I = findIndex(Idx);
     if (I != end())
       return std::make_pair(I, false);
-    Sparse.get()[Idx] = size();
+    Sparse[Idx] = size();
     Dense.push_back(Val);
     return std::make_pair(end() - 1, true);
   }
@@ -296,7 +296,7 @@ class SparseSet {
       *I = Dense.back();
       unsigned BackIdx = ValIndexOf(Dense.back());
       assert(BackIdx < Universe && "Invalid key in set. Did object mutate?");
-      Sparse.get()[BackIdx] = I - begin();
+      Sparse[BackIdx] = I - begin();
     }
     // This depends on SmallVector::pop_back() not invalidating iterators.
     // std::vector::pop_back() doesn't give that guarantee.
diff --git a/llvm/unittests/ADT/SparseSetTest.cpp b/llvm/unittests/ADT/SparseSetTest.cpp
index 3eea4bde8c07cc..4fbf1caa247b79 100644
--- a/llvm/unittests/ADT/SparseSetTest.cpp
+++ b/llvm/unittests/ADT/SparseSetTest.cpp
@@ -204,4 +204,16 @@ TEST(SparseSetTest, PopBack) {
   for (unsigned i = 0; i < UpperBound; ++i)
     ASSERT_TRUE(Set.insert(i).second);
 }
+
+TEST(SparseSetTest, MoveConstructor) {
+  USet Set;
+  Set.setUniverse(2);
+  Set.insert(1);
+  EXPECT_FALSE(Set.empty());
+  // Move and check original is empty.
+  USet OtherSet(std::move(Set));
+  EXPECT_TRUE(Set.empty());
+  EXPECT_TRUE(OtherSet.contains(1));
+}
+
 } // namespace



More information about the llvm-commits mailing list