Skip to content

Commit d8a2965

Browse files
[ADT] Adding bidirectional iterator functionality + unit tests (#160726)
This feature is needed for #160415 , kuhar suggested that I split that PR into 2 so that the ADT work is checking in first. --------- Co-authored-by: Jakub Kuderski <[email protected]>
1 parent 078a4e9 commit d8a2965

File tree

2 files changed

+117
-5
lines changed

2 files changed

+117
-5
lines changed

llvm/include/llvm/ADT/BitVector.h

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -40,12 +40,20 @@ template <typename BitVectorT> class const_set_bits_iterator_impl {
4040
Current = Parent.find_next(Current);
4141
}
4242

43+
void retreat() {
44+
if (Current == -1) {
45+
Current = Parent.find_last();
46+
} else {
47+
Current = Parent.find_prev(Current);
48+
}
49+
}
50+
4351
public:
44-
using iterator_category = std::forward_iterator_tag;
45-
using difference_type = std::ptrdiff_t;
46-
using value_type = int;
47-
using pointer = value_type*;
48-
using reference = value_type&;
52+
using iterator_category = std::bidirectional_iterator_tag;
53+
using difference_type = std::ptrdiff_t;
54+
using value_type = unsigned;
55+
using pointer = const value_type *;
56+
using reference = value_type;
4957

5058
const_set_bits_iterator_impl(const BitVectorT &Parent, int Current)
5159
: Parent(Parent), Current(Current) {}
@@ -64,6 +72,17 @@ template <typename BitVectorT> class const_set_bits_iterator_impl {
6472
return *this;
6573
}
6674

75+
const_set_bits_iterator_impl operator--(int) {
76+
auto Prev = *this;
77+
retreat();
78+
return Prev;
79+
}
80+
81+
const_set_bits_iterator_impl &operator--() {
82+
retreat();
83+
return *this;
84+
}
85+
6786
unsigned operator*() const { return Current; }
6887

6988
bool operator==(const const_set_bits_iterator_impl &Other) const {

llvm/unittests/ADT/BitVectorTest.cpp

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
#include "llvm/ADT/BitVector.h"
1010
#include "llvm/ADT/DenseSet.h"
11+
#include "llvm/ADT/STLExtras.h"
1112
#include "llvm/ADT/SmallBitVector.h"
1213
#include "gtest/gtest.h"
1314

@@ -1177,6 +1178,98 @@ TYPED_TEST(BitVectorTest, Iterators) {
11771178
EXPECT_EQ(List[i++], Bit);
11781179
}
11791180

1181+
TYPED_TEST(BitVectorTest, BidirectionalIterator) {
1182+
// Test decrement operators.
1183+
TypeParam Vec(100, false);
1184+
Vec.set(10);
1185+
Vec.set(20);
1186+
Vec.set(30);
1187+
Vec.set(40);
1188+
1189+
// Test that we can decrement from end().
1190+
auto EndIt = Vec.set_bits_end();
1191+
auto LastIt = EndIt;
1192+
--LastIt;
1193+
EXPECT_EQ(*LastIt, 40U);
1194+
1195+
// Test post-decrement.
1196+
auto It = Vec.set_bits_end();
1197+
auto PrevIt = It--;
1198+
EXPECT_EQ(PrevIt, Vec.set_bits_end());
1199+
EXPECT_EQ(*It, 40U);
1200+
1201+
// Test pre-decrement.
1202+
--It;
1203+
EXPECT_EQ(*It, 30U);
1204+
1205+
// Test full backward iteration.
1206+
std::vector<unsigned> BackwardBits;
1207+
for (auto RIt = Vec.set_bits_end(); RIt != Vec.set_bits_begin();) {
1208+
--RIt;
1209+
BackwardBits.push_back(*RIt);
1210+
}
1211+
EXPECT_EQ(BackwardBits.size(), 4U);
1212+
EXPECT_EQ(BackwardBits[0], 40U);
1213+
EXPECT_EQ(BackwardBits[1], 30U);
1214+
EXPECT_EQ(BackwardBits[2], 20U);
1215+
EXPECT_EQ(BackwardBits[3], 10U);
1216+
}
1217+
1218+
TYPED_TEST(BitVectorTest, ReverseIteration) {
1219+
// Test using llvm::reverse.
1220+
TypeParam Vec(100, false);
1221+
Vec.set(5);
1222+
Vec.set(15);
1223+
Vec.set(25);
1224+
Vec.set(35);
1225+
Vec.set(45);
1226+
1227+
std::vector<unsigned> ReversedBits;
1228+
for (unsigned Bit : llvm::reverse(Vec.set_bits())) {
1229+
ReversedBits.push_back(Bit);
1230+
}
1231+
1232+
EXPECT_EQ(ReversedBits.size(), 5U);
1233+
EXPECT_EQ(ReversedBits[0], 45U);
1234+
EXPECT_EQ(ReversedBits[1], 35U);
1235+
EXPECT_EQ(ReversedBits[2], 25U);
1236+
EXPECT_EQ(ReversedBits[3], 15U);
1237+
EXPECT_EQ(ReversedBits[4], 5U);
1238+
}
1239+
1240+
TYPED_TEST(BitVectorTest, BidirectionalIteratorEdgeCases) {
1241+
// Test empty BitVector.
1242+
TypeParam Empty;
1243+
EXPECT_EQ(Empty.set_bits_begin(), Empty.set_bits_end());
1244+
1245+
// Decrementing end() on empty should give -1 (no bits set).
1246+
auto EmptyEndIt = Empty.set_bits_end();
1247+
--EmptyEndIt;
1248+
// After decrement on empty, iterator should still be at "no bit" position.
1249+
EXPECT_EQ(*EmptyEndIt, static_cast<unsigned>(-1));
1250+
1251+
// Test single bit.
1252+
TypeParam Single(10, false);
1253+
Single.set(5);
1254+
1255+
auto SingleIt = Single.set_bits_end();
1256+
--SingleIt;
1257+
EXPECT_EQ(*SingleIt, 5U);
1258+
// After decrementing past the first element, the iterator is in an
1259+
// undefined state (before begin), so we don't test this case.
1260+
1261+
// Test all bits set.
1262+
TypeParam AllSet(10, true);
1263+
std::vector<unsigned> AllBitsReverse;
1264+
for (unsigned Bit : llvm::reverse(AllSet.set_bits())) {
1265+
AllBitsReverse.push_back(Bit);
1266+
}
1267+
EXPECT_EQ(AllBitsReverse.size(), 10U);
1268+
for (unsigned i = 0; i < 10; ++i) {
1269+
EXPECT_EQ(AllBitsReverse[i], 9 - i);
1270+
}
1271+
}
1272+
11801273
TYPED_TEST(BitVectorTest, PushBack) {
11811274
TypeParam Vec(10, false);
11821275
EXPECT_EQ(-1, Vec.find_first());

0 commit comments

Comments
 (0)