diff --git a/src/hotspot/share/utilities/bitMap.hpp b/src/hotspot/share/utilities/bitMap.hpp index 8a55d410c3e..b0c293d29dd 100644 --- a/src/hotspot/share/utilities/bitMap.hpp +++ b/src/hotspot/share/utilities/bitMap.hpp @@ -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 @@ -296,6 +296,22 @@ class BitMap { return iterate(cl, 0, size()); } + template + bool reverse_iterate(Function function, idx_t beg, idx_t end) const; + + template + bool reverse_iterate(BitMapClosureType* cl, idx_t beg, idx_t end) const; + + template + bool reverse_iterate(Function function) const { + return reverse_iterate(function, 0, size()); + } + + template + 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. diff --git a/src/hotspot/share/utilities/bitMap.inline.hpp b/src/hotspot/share/utilities/bitMap.inline.hpp index 41b6cc0c0e6..200feb5f7b8 100644 --- a/src/hotspot/share/utilities/bitMap.inline.hpp +++ b/src/hotspot/share/utilities/bitMap.inline.hpp @@ -351,6 +351,25 @@ inline bool BitMap::iterate(BitMapClosureType* cl, idx_t beg, idx_t end) const { return iterate(function, beg, end); } +template +inline bool BitMap::reverse_iterate(Function function, idx_t beg, idx_t end) const { + auto invoke = IterateInvoker(); + 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 +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 diff --git a/test/hotspot/gtest/utilities/test_bitMap_iterate.cpp b/test/hotspot/gtest/utilities/test_bitMap_iterate.cpp index f2e3d4bd630..ec2528073a0 100644 --- a/test/hotspot/gtest/utilities/test_bitMap_iterate.cpp +++ b/test/hotspot/gtest/utilities/test_bitMap_iterate.cpp @@ -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) {