8298725: Add BitMap support for reverse iteration
Reviewed-by: stefank, aboldtch, tschatzl
This commit is contained in:
parent
97649489d0
commit
501b606816
@ -264,7 +264,7 @@ class BitMap {
|
||||
void verify_range(idx_t beg, idx_t end) const NOT_DEBUG_RETURN;
|
||||
|
||||
// Applies an operation to the index of each set bit in [beg, end), in
|
||||
// increasing order.
|
||||
// increasing (decreasing for reverse iteration) order.
|
||||
//
|
||||
// If i is an index of the bitmap, the operation is either
|
||||
// - function(i)
|
||||
@ -276,8 +276,8 @@ class BitMap {
|
||||
// an operation returning false.
|
||||
//
|
||||
// If an operation modifies the bitmap, modifications to bits at indices
|
||||
// greater than the current index will affect which further indices the
|
||||
// operation will be applied to.
|
||||
// greater than (less than for reverse iteration) the current index will
|
||||
// affect which further indices the operation will be applied to.
|
||||
//
|
||||
// precondition: beg and end form a valid range for the bitmap.
|
||||
template<typename Function>
|
||||
@ -296,6 +296,22 @@ class BitMap {
|
||||
return iterate(cl, 0, size());
|
||||
}
|
||||
|
||||
template<typename Function>
|
||||
bool reverse_iterate(Function function, idx_t beg, idx_t end) const;
|
||||
|
||||
template<typename BitMapClosureType>
|
||||
bool reverse_iterate(BitMapClosureType* cl, idx_t beg, idx_t end) const;
|
||||
|
||||
template<typename Function>
|
||||
bool reverse_iterate(Function function) const {
|
||||
return reverse_iterate(function, 0, size());
|
||||
}
|
||||
|
||||
template<typename BitMapClosureType>
|
||||
bool reverse_iterate(BitMapClosureType* cl) const {
|
||||
return reverse_iterate(cl, 0, size());
|
||||
}
|
||||
|
||||
// Return the index of the first set (or clear) bit in the range [beg, end),
|
||||
// or end if none found.
|
||||
// precondition: beg and end form a valid range for the bitmap.
|
||||
|
@ -351,6 +351,25 @@ inline bool BitMap::iterate(BitMapClosureType* cl, idx_t beg, idx_t end) const {
|
||||
return iterate(function, beg, end);
|
||||
}
|
||||
|
||||
template <typename Function>
|
||||
inline bool BitMap::reverse_iterate(Function function, idx_t beg, idx_t end) const {
|
||||
auto invoke = IterateInvoker<decltype(function(beg))>();
|
||||
for (idx_t index; true; end = index) {
|
||||
index = find_last_set_bit(beg, end);
|
||||
if (index >= end) {
|
||||
return true;
|
||||
} else if (!invoke(function, index)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <typename BitMapClosureType>
|
||||
inline bool BitMap::reverse_iterate(BitMapClosureType* cl, idx_t beg, idx_t end) const {
|
||||
auto function = [&](idx_t index) { return cl->do_bit(index); };
|
||||
return reverse_iterate(function, beg, end);
|
||||
}
|
||||
|
||||
// Returns a bit mask for a range of bits [beg, end) within a single word. Each
|
||||
// bit in the mask is 0 if the bit is in the range, 1 if not in the range. The
|
||||
// returned mask can be used directly to clear the range, or inverted to set the
|
||||
|
@ -59,31 +59,81 @@ static void test_iterate_lambda(const BitMap& map,
|
||||
ASSERT_EQ(positions_index, positions_size);
|
||||
}
|
||||
|
||||
static void test_reverse_iterate_lambda(const BitMap& map,
|
||||
const idx_t* positions,
|
||||
size_t positions_size) {
|
||||
SCOPED_TRACE("reverse iterate with lambda");
|
||||
size_t positions_index = positions_size;
|
||||
auto f = [&](idx_t i) {
|
||||
test_iterate_step(map, i, positions, --positions_index, positions_size);
|
||||
};
|
||||
ASSERT_TRUE(map.reverse_iterate(f));
|
||||
ASSERT_EQ(positions_index, 0u);
|
||||
}
|
||||
|
||||
|
||||
struct TestBitMapIterationData {
|
||||
const BitMap& _map;
|
||||
const idx_t* _positions;
|
||||
size_t _positions_index;
|
||||
size_t _positions_size;
|
||||
|
||||
TestBitMapIterationData(const BitMap& map,
|
||||
const idx_t* positions,
|
||||
size_t positions_index,
|
||||
size_t positions_size)
|
||||
: _map(map),
|
||||
_positions(positions),
|
||||
_positions_index(positions_index),
|
||||
_positions_size(positions_size)
|
||||
{}
|
||||
|
||||
void test(idx_t index) const {
|
||||
test_iterate_step(_map, index, _positions, _positions_index, _positions_size);
|
||||
}
|
||||
};
|
||||
|
||||
// Test closure returning bool. Also tests lambda returning bool.
|
||||
static void test_iterate_closure(const BitMap& map,
|
||||
const idx_t* positions,
|
||||
size_t positions_size) {
|
||||
SCOPED_TRACE("iterate with BitMapClosure");
|
||||
struct Closure : public BitMapClosure {
|
||||
const BitMap& _map;
|
||||
const idx_t* _positions;
|
||||
size_t _positions_index;
|
||||
size_t _positions_size;
|
||||
TestBitMapIterationData _data;
|
||||
|
||||
Closure(const BitMap& map, const idx_t* positions, size_t positions_size)
|
||||
: _map(map),
|
||||
_positions(positions),
|
||||
_positions_index(0),
|
||||
_positions_size(positions_size)
|
||||
: _data(map, positions, 0, positions_size)
|
||||
{}
|
||||
|
||||
bool do_bit(idx_t i) override {
|
||||
test_iterate_step(_map, i, _positions, _positions_index++, _positions_size);
|
||||
_data.test(i);
|
||||
_data._positions_index += 1;
|
||||
return true;
|
||||
}
|
||||
} closure{map, positions, positions_size};
|
||||
ASSERT_TRUE(map.iterate(&closure));
|
||||
ASSERT_EQ(closure._positions_index, positions_size);
|
||||
ASSERT_EQ(closure._data._positions_index, positions_size);
|
||||
}
|
||||
|
||||
static void test_reverse_iterate_closure(const BitMap& map,
|
||||
const idx_t* positions,
|
||||
size_t positions_size) {
|
||||
SCOPED_TRACE("reverse iterate with BitMapClosure");
|
||||
struct Closure : public BitMapClosure {
|
||||
TestBitMapIterationData _data;
|
||||
|
||||
Closure(const BitMap& map, const idx_t* positions, size_t positions_size)
|
||||
: _data(map, positions, positions_size, positions_size)
|
||||
{}
|
||||
|
||||
bool do_bit(idx_t i) override {
|
||||
_data._positions_index -= 1;
|
||||
_data.test(i);
|
||||
return true;
|
||||
}
|
||||
} closure{map, positions, positions_size};
|
||||
ASSERT_TRUE(map.reverse_iterate(&closure));
|
||||
ASSERT_EQ(closure._data._positions_index, 0u);
|
||||
}
|
||||
|
||||
// Test closure returning void. Also tests lambda returning bool.
|
||||
@ -92,24 +142,37 @@ static void test_iterate_non_closure(const BitMap& map,
|
||||
size_t positions_size) {
|
||||
SCOPED_TRACE("iterate with non-BitMapClosure");
|
||||
struct Closure {
|
||||
const BitMap& _map;
|
||||
const idx_t* _positions;
|
||||
size_t _positions_index;
|
||||
size_t _positions_size;
|
||||
|
||||
TestBitMapIterationData _data;
|
||||
Closure(const BitMap& map, const idx_t* positions, size_t positions_size)
|
||||
: _map(map),
|
||||
_positions(positions),
|
||||
_positions_index(0),
|
||||
_positions_size(positions_size)
|
||||
: _data(map, positions, 0, positions_size)
|
||||
{}
|
||||
|
||||
void do_bit(idx_t i) {
|
||||
test_iterate_step(_map, i, _positions, _positions_index++, _positions_size);
|
||||
_data.test(i);
|
||||
_data._positions_index += 1;
|
||||
}
|
||||
} closure{map, positions, positions_size};
|
||||
ASSERT_TRUE(map.iterate(&closure));
|
||||
ASSERT_EQ(closure._positions_index, positions_size);
|
||||
ASSERT_EQ(closure._data._positions_index, positions_size);
|
||||
}
|
||||
|
||||
static void test_reverse_iterate_non_closure(const BitMap& map,
|
||||
const idx_t* positions,
|
||||
size_t positions_size) {
|
||||
SCOPED_TRACE("reverse iterate with non-BitMapClosure");
|
||||
struct Closure {
|
||||
TestBitMapIterationData _data;
|
||||
Closure(const BitMap& map, const idx_t* positions, size_t positions_size)
|
||||
: _data(map, positions, positions_size, positions_size)
|
||||
{}
|
||||
|
||||
void do_bit(idx_t i) {
|
||||
_data._positions_index -= 1;
|
||||
_data.test(i);
|
||||
}
|
||||
} closure{map, positions, positions_size};
|
||||
ASSERT_TRUE(map.reverse_iterate(&closure));
|
||||
ASSERT_EQ(closure._data._positions_index, 0u);
|
||||
}
|
||||
|
||||
static void fill_iterate_map(BitMap& map,
|
||||
@ -125,9 +188,14 @@ static void test_iterate(BitMap& map,
|
||||
const idx_t* positions,
|
||||
size_t positions_size) {
|
||||
fill_iterate_map(map, positions, positions_size);
|
||||
|
||||
test_iterate_lambda(map, positions, positions_size);
|
||||
test_iterate_closure(map, positions, positions_size);
|
||||
test_iterate_non_closure(map, positions, positions_size);
|
||||
|
||||
test_reverse_iterate_lambda(map, positions, positions_size);
|
||||
test_reverse_iterate_closure(map, positions, positions_size);
|
||||
test_reverse_iterate_non_closure(map, positions, positions_size);
|
||||
}
|
||||
|
||||
TEST(BitMap, iterate_empty) {
|
||||
|
Loading…
Reference in New Issue
Block a user