[llvm] [ADT] Adding bidirectional iterator functionality + unit tests (PR #160726)
Francisco Geiman Thiesen via llvm-commits
llvm-commits at lists.llvm.org
Thu Sep 25 09:57:50 PDT 2025
https://github.com/FranciscoThiesen updated https://github.com/llvm/llvm-project/pull/160726
>From 6205ff8c59a7684ff578037f3fcafcf25295b05c Mon Sep 17 00:00:00 2001
From: Francisco Geiman Thiesen <franciscogthiesen at gmail.com>
Date: Thu, 25 Sep 2025 08:28:09 -0700
Subject: [PATCH 1/2] Adding bidirectional iterator functionality + unit tests.
---
llvm/include/llvm/ADT/BitVector.h | 27 ++++++--
llvm/unittests/ADT/BitVectorTest.cpp | 93 ++++++++++++++++++++++++++++
2 files changed, 116 insertions(+), 4 deletions(-)
diff --git a/llvm/include/llvm/ADT/BitVector.h b/llvm/include/llvm/ADT/BitVector.h
index 72da2343fae13..ef619aef208f3 100644
--- a/llvm/include/llvm/ADT/BitVector.h
+++ b/llvm/include/llvm/ADT/BitVector.h
@@ -40,12 +40,20 @@ template <typename BitVectorT> class const_set_bits_iterator_impl {
Current = Parent.find_next(Current);
}
+ void retreat() {
+ if (Current == -1) {
+ Current = Parent.find_last();
+ } else {
+ Current = Parent.find_prev(Current);
+ }
+ }
+
public:
- using iterator_category = std::forward_iterator_tag;
+ using iterator_category = std::bidirectional_iterator_tag;
using difference_type = std::ptrdiff_t;
- using value_type = int;
- using pointer = value_type*;
- using reference = value_type&;
+ using value_type = unsigned;
+ using pointer = const value_type*;
+ using reference = value_type;
const_set_bits_iterator_impl(const BitVectorT &Parent, int Current)
: Parent(Parent), Current(Current) {}
@@ -64,6 +72,17 @@ template <typename BitVectorT> class const_set_bits_iterator_impl {
return *this;
}
+ const_set_bits_iterator_impl operator--(int) {
+ auto Prev = *this;
+ retreat();
+ return Prev;
+ }
+
+ const_set_bits_iterator_impl &operator--() {
+ retreat();
+ return *this;
+ }
+
unsigned operator*() const { return Current; }
bool operator==(const const_set_bits_iterator_impl &Other) const {
diff --git a/llvm/unittests/ADT/BitVectorTest.cpp b/llvm/unittests/ADT/BitVectorTest.cpp
index 6a4780c143e54..216e9a0c579f4 100644
--- a/llvm/unittests/ADT/BitVectorTest.cpp
+++ b/llvm/unittests/ADT/BitVectorTest.cpp
@@ -9,6 +9,7 @@
#include "llvm/ADT/BitVector.h"
#include "llvm/ADT/DenseSet.h"
#include "llvm/ADT/SmallBitVector.h"
+#include "llvm/ADT/STLExtras.h"
#include "gtest/gtest.h"
using namespace llvm;
@@ -1177,6 +1178,98 @@ TYPED_TEST(BitVectorTest, Iterators) {
EXPECT_EQ(List[i++], Bit);
}
+TYPED_TEST(BitVectorTest, BidirectionalIterator) {
+ // Test decrement operators
+ TypeParam Vec(100, false);
+ Vec.set(10);
+ Vec.set(20);
+ Vec.set(30);
+ Vec.set(40);
+
+ // Test that we can decrement from end()
+ auto EndIt = Vec.set_bits_end();
+ auto LastIt = EndIt;
+ --LastIt;
+ EXPECT_EQ(*LastIt, 40U);
+
+ // Test post-decrement
+ auto It = Vec.set_bits_end();
+ auto PrevIt = It--;
+ EXPECT_EQ(PrevIt, Vec.set_bits_end());
+ EXPECT_EQ(*It, 40U);
+
+ // Test pre-decrement
+ --It;
+ EXPECT_EQ(*It, 30U);
+
+ // Test full backward iteration
+ std::vector<unsigned> BackwardBits;
+ for (auto RIt = Vec.set_bits_end(); RIt != Vec.set_bits_begin(); ) {
+ --RIt;
+ BackwardBits.push_back(*RIt);
+ }
+ EXPECT_EQ(BackwardBits.size(), 4U);
+ EXPECT_EQ(BackwardBits[0], 40U);
+ EXPECT_EQ(BackwardBits[1], 30U);
+ EXPECT_EQ(BackwardBits[2], 20U);
+ EXPECT_EQ(BackwardBits[3], 10U);
+}
+
+TYPED_TEST(BitVectorTest, ReverseIteration) {
+ // Test using llvm::reverse
+ TypeParam Vec(100, false);
+ Vec.set(5);
+ Vec.set(15);
+ Vec.set(25);
+ Vec.set(35);
+ Vec.set(45);
+
+ std::vector<unsigned> ReversedBits;
+ for (unsigned Bit : llvm::reverse(Vec.set_bits())) {
+ ReversedBits.push_back(Bit);
+ }
+
+ EXPECT_EQ(ReversedBits.size(), 5U);
+ EXPECT_EQ(ReversedBits[0], 45U);
+ EXPECT_EQ(ReversedBits[1], 35U);
+ EXPECT_EQ(ReversedBits[2], 25U);
+ EXPECT_EQ(ReversedBits[3], 15U);
+ EXPECT_EQ(ReversedBits[4], 5U);
+}
+
+TYPED_TEST(BitVectorTest, BidirectionalIteratorEdgeCases) {
+ // Test empty BitVector
+ TypeParam Empty;
+ EXPECT_EQ(Empty.set_bits_begin(), Empty.set_bits_end());
+
+ // Decrementing end() on empty should give -1 (no bits set)
+ auto EmptyEndIt = Empty.set_bits_end();
+ --EmptyEndIt;
+ // After decrement on empty, iterator should still be at "no bit" position
+ EXPECT_EQ(*EmptyEndIt, static_cast<unsigned>(-1));
+
+ // Test single bit
+ TypeParam Single(10, false);
+ Single.set(5);
+
+ auto SingleIt = Single.set_bits_end();
+ --SingleIt;
+ EXPECT_EQ(*SingleIt, 5U);
+ // After decrementing past the first element, the iterator is in an
+ // undefined state (before begin), so we don't test this case
+
+ // Test all bits set
+ TypeParam AllSet(10, true);
+ std::vector<unsigned> AllBitsReverse;
+ for (unsigned Bit : llvm::reverse(AllSet.set_bits())) {
+ AllBitsReverse.push_back(Bit);
+ }
+ EXPECT_EQ(AllBitsReverse.size(), 10U);
+ for (unsigned i = 0; i < 10; ++i) {
+ EXPECT_EQ(AllBitsReverse[i], 9 - i);
+ }
+}
+
TYPED_TEST(BitVectorTest, PushBack) {
TypeParam Vec(10, false);
EXPECT_EQ(-1, Vec.find_first());
>From 2b1a7eb5d3bd5f4016621bd464898f31350e7524 Mon Sep 17 00:00:00 2001
From: Francisco Geiman Thiesen <franciscogthiesen at gmail.com>
Date: Thu, 25 Sep 2025 09:57:38 -0700
Subject: [PATCH 2/2] Clang-formatting + adding dots to the end of comment
lines
---
llvm/unittests/ADT/BitVectorTest.cpp | 62 +++++++++++++---------------
1 file changed, 29 insertions(+), 33 deletions(-)
diff --git a/llvm/unittests/ADT/BitVectorTest.cpp b/llvm/unittests/ADT/BitVectorTest.cpp
index 216e9a0c579f4..ef599a6940bd1 100644
--- a/llvm/unittests/ADT/BitVectorTest.cpp
+++ b/llvm/unittests/ADT/BitVectorTest.cpp
@@ -8,8 +8,8 @@
#include "llvm/ADT/BitVector.h"
#include "llvm/ADT/DenseSet.h"
-#include "llvm/ADT/SmallBitVector.h"
#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/SmallBitVector.h"
#include "gtest/gtest.h"
using namespace llvm;
@@ -17,8 +17,7 @@ using namespace llvm;
namespace {
// Test fixture
-template <typename T>
-class BitVectorTest : public ::testing::Test { };
+template <typename T> class BitVectorTest : public ::testing::Test {};
// Test both BitVector and SmallBitVector with the same suite of tests.
typedef ::testing::Types<BitVector, SmallBitVector> BitVectorTestTypes;
@@ -780,10 +779,9 @@ TYPED_TEST(BitVectorTest, ProxyIndex) {
EXPECT_TRUE(Vec.none());
}
-
TYPED_TEST(BitVectorTest, PortableBitMask) {
TypeParam A;
- const uint32_t Mask1[] = { 0x80000000, 6, 5 };
+ const uint32_t Mask1[] = {0x80000000, 6, 5};
A.resize(10);
A.setBitsInMask(Mask1, 1);
@@ -811,7 +809,7 @@ TYPED_TEST(BitVectorTest, PortableBitMask) {
EXPECT_EQ(4u, A.count());
A.setBitsNotInMask(Mask1, 1);
- EXPECT_EQ(32u+3u, A.count());
+ EXPECT_EQ(32u + 3u, A.count());
A.setBitsNotInMask(Mask1, 3);
EXPECT_EQ(65u, A.count());
@@ -822,10 +820,10 @@ TYPED_TEST(BitVectorTest, PortableBitMask) {
A.clear();
A.resize(128);
A.setBitsNotInMask(Mask1, 3);
- EXPECT_EQ(96u-5u, A.count());
+ EXPECT_EQ(96u - 5u, A.count());
A.clearBitsNotInMask(Mask1, 1);
- EXPECT_EQ(64-4u, A.count());
+ EXPECT_EQ(64 - 4u, A.count());
}
TYPED_TEST(BitVectorTest, BinOps) {
@@ -986,9 +984,9 @@ TYPED_TEST(BitVectorTest, RangeOps) {
A.set(1, 255);
EXPECT_FALSE(A.test(0));
- EXPECT_TRUE( A.test(1));
- EXPECT_TRUE( A.test(23));
- EXPECT_TRUE( A.test(254));
+ EXPECT_TRUE(A.test(1));
+ EXPECT_TRUE(A.test(23));
+ EXPECT_TRUE(A.test(254));
EXPECT_FALSE(A.test(255));
TypeParam B;
@@ -996,11 +994,11 @@ TYPED_TEST(BitVectorTest, RangeOps) {
B.set();
B.reset(1, 255);
- EXPECT_TRUE( B.test(0));
+ EXPECT_TRUE(B.test(0));
EXPECT_FALSE(B.test(1));
EXPECT_FALSE(B.test(23));
EXPECT_FALSE(B.test(254));
- EXPECT_TRUE( B.test(255));
+ EXPECT_TRUE(B.test(255));
TypeParam C;
C.resize(3);
@@ -1008,8 +1006,8 @@ TYPED_TEST(BitVectorTest, RangeOps) {
C.set(0, 1);
EXPECT_TRUE(C.test(0));
- EXPECT_FALSE( C.test(1));
- EXPECT_FALSE( C.test(2));
+ EXPECT_FALSE(C.test(1));
+ EXPECT_FALSE(C.test(2));
TypeParam D;
D.resize(3);
@@ -1017,8 +1015,8 @@ TYPED_TEST(BitVectorTest, RangeOps) {
D.reset(0, 1);
EXPECT_FALSE(D.test(0));
- EXPECT_TRUE( D.test(1));
- EXPECT_TRUE( D.test(2));
+ EXPECT_TRUE(D.test(1));
+ EXPECT_TRUE(D.test(2));
TypeParam E;
E.resize(128);
@@ -1026,8 +1024,8 @@ TYPED_TEST(BitVectorTest, RangeOps) {
E.set(1, 33);
EXPECT_FALSE(E.test(0));
- EXPECT_TRUE( E.test(1));
- EXPECT_TRUE( E.test(32));
+ EXPECT_TRUE(E.test(1));
+ EXPECT_TRUE(E.test(32));
EXPECT_FALSE(E.test(33));
TypeParam BufferOverrun;
@@ -1098,8 +1096,7 @@ TYPED_TEST(BitVectorTest, MoveAssignment) {
EXPECT_EQ(C, B);
}
-template<class TypeParam>
-static void testEmpty(const TypeParam &A) {
+template <class TypeParam> static void testEmpty(const TypeParam &A) {
EXPECT_TRUE(A.empty());
EXPECT_EQ((size_t)0, A.size());
EXPECT_EQ((size_t)0, A.count());
@@ -1192,19 +1189,19 @@ TYPED_TEST(BitVectorTest, BidirectionalIterator) {
--LastIt;
EXPECT_EQ(*LastIt, 40U);
- // Test post-decrement
+ // Test post-decrement.
auto It = Vec.set_bits_end();
auto PrevIt = It--;
EXPECT_EQ(PrevIt, Vec.set_bits_end());
EXPECT_EQ(*It, 40U);
- // Test pre-decrement
+ // Test pre-decrement.
--It;
EXPECT_EQ(*It, 30U);
- // Test full backward iteration
+ // Test full backward iteration.
std::vector<unsigned> BackwardBits;
- for (auto RIt = Vec.set_bits_end(); RIt != Vec.set_bits_begin(); ) {
+ for (auto RIt = Vec.set_bits_end(); RIt != Vec.set_bits_begin();) {
--RIt;
BackwardBits.push_back(*RIt);
}
@@ -1216,7 +1213,7 @@ TYPED_TEST(BitVectorTest, BidirectionalIterator) {
}
TYPED_TEST(BitVectorTest, ReverseIteration) {
- // Test using llvm::reverse
+ // Test using llvm::reverse.
TypeParam Vec(100, false);
Vec.set(5);
Vec.set(15);
@@ -1238,17 +1235,17 @@ TYPED_TEST(BitVectorTest, ReverseIteration) {
}
TYPED_TEST(BitVectorTest, BidirectionalIteratorEdgeCases) {
- // Test empty BitVector
+ // Test empty BitVector.
TypeParam Empty;
EXPECT_EQ(Empty.set_bits_begin(), Empty.set_bits_end());
- // Decrementing end() on empty should give -1 (no bits set)
+ // Decrementing end() on empty should give -1 (no bits set).
auto EmptyEndIt = Empty.set_bits_end();
--EmptyEndIt;
- // After decrement on empty, iterator should still be at "no bit" position
+ // After decrement on empty, iterator should still be at "no bit" position.
EXPECT_EQ(*EmptyEndIt, static_cast<unsigned>(-1));
- // Test single bit
+ // Test single bit.
TypeParam Single(10, false);
Single.set(5);
@@ -1256,9 +1253,9 @@ TYPED_TEST(BitVectorTest, BidirectionalIteratorEdgeCases) {
--SingleIt;
EXPECT_EQ(*SingleIt, 5U);
// After decrementing past the first element, the iterator is in an
- // undefined state (before begin), so we don't test this case
+ // undefined state (before begin), so we don't test this case.
- // Test all bits set
+ // Test all bits set.
TypeParam AllSet(10, true);
std::vector<unsigned> AllBitsReverse;
for (unsigned Bit : llvm::reverse(AllSet.set_bits())) {
@@ -1427,5 +1424,4 @@ TEST(BitVectoryTest, Apply) {
}
}
-
} // namespace
More information about the llvm-commits
mailing list