Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions src/hotspot/share/utilities/bitMap.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -654,6 +654,12 @@ void BitMap::write_to(bm_word_t* buffer, size_t buffer_size_in_bytes) const {
memcpy(buffer, _map, size_in_bytes());
}

#ifdef ASSERT
void BitMap::IteratorImpl::assert_not_empty() const {
assert(!is_empty(), "empty iterator");
}
#endif

#ifndef PRODUCT

void BitMap::print_on(outputStream* st) const {
Expand Down
170 changes: 170 additions & 0 deletions src/hotspot/share/utilities/bitMap.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,8 @@ class BitMap {

template<typename ReturnType> struct IterateInvoker;

struct IteratorImpl;

// Threshold for performing small range operation, even when large range
// operation was requested. Measured in words.
static const size_t small_range_words = 32;
Expand Down Expand Up @@ -279,6 +281,8 @@ class BitMap {
// greater than (less than for reverse iteration) the current index will
// affect which further indices the operation will be applied to.
//
// See also the Iterator and ReverseIterator classes.
//
// precondition: beg and end form a valid range for the bitmap.
template<typename Function>
bool iterate(Function function, idx_t beg, idx_t end) const;
Expand Down Expand Up @@ -312,6 +316,11 @@ class BitMap {
return reverse_iterate(cl, 0, size());
}

class Iterator;
class ReverseIterator;
class RBFIterator;
class ReverseRBFIterator;

// 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.
Expand Down Expand Up @@ -385,6 +394,167 @@ class BitMap {
#endif
};

// Implementation support for bitmap iteration. While it could be used to
// support bi-directional iteration, it is only intended to be used for
// uni-directional iteration. The directionality is determined by the using
// class.
struct BitMap::IteratorImpl {
const BitMap* _map;
idx_t _cur_beg;
idx_t _cur_end;

void assert_not_empty() const NOT_DEBUG_RETURN;

// Constructs an empty iterator.
IteratorImpl();

// Constructs an iterator for map, over the range [beg, end).
// May be constructed for one of forward or reverse iteration.
// precondition: beg and end form a valid range for map.
// precondition: either beg == end or
// (1) if for forward iteration, then beg must designate a set bit,
// (2) if for reverse iteration, then end-1 must designate a set bit.
IteratorImpl(const BitMap* map, idx_t beg, idx_t end);

// Returns true if the remaining iteration range is empty.
bool is_empty() const;

// Returns the index of the first set bit in the remaining iteration range.
// precondition: !is_empty()
// precondition: constructed for forward iteration.
idx_t first() const;

// Returns the index of the last set bit in the remaining iteration range.
// precondition: !is_empty()
// precondition: constructed for reverse iteration.
idx_t last() const;
Copy link
Member

@xmas92 xmas92 Mar 29, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comments for first() and last() are a little misleading. The invariant that the first()/last() is a set bit is only true for first() in the forward iterator and for last() in the reverse iterator.

It seems more like a contract that if you use first() then you must have created IteratorImpl(const BitMap* map, idx_t beg, idx_t end) with beg being a set bit. And if you use last() then you must have created it with end-1 being a set bit.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Or beg == end, that is an is_empty() Iterator

Copy link
Author

@kimbarrett kimbarrett Mar 29, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, you are correct. Some of the comments for IteratorImpl didn't get properly updated. I'll clean that up.


// Updates first() to the position of the first set bit in the range
// [first() + 1, last()]. The iterator instead becomes empty if there
// aren't any set bits in that range.
// precondition: !is_empty()
// precondition: constructed for forward iteration.
void step_first();

// Updates last() to the position of the last set bit in the range
// [first(), last()). The iterator instead becomes empty if there aren't
// any set bits in that range.
// precondition: !is_empty()
// precondition: constructed for reverse iteration.
void step_last();
};

// Provides iteration over the indices of the set bits in a range of a bitmap,
// in increasing order. This is an alternative to the iterate() function.
class BitMap::Iterator {
IteratorImpl _impl;

public:
// Constructs an empty iterator.
Iterator();

// Constructs an iterator for map, over the range [0, map.size()).
explicit Iterator(const BitMap& map);

// Constructs an iterator for map, over the range [beg, end).
// If there are no set bits in that range, the resulting iterator is empty.
// Otherwise, index() is initially the position of the first set bit in
// that range.
// precondition: beg and end form a valid range for map.
Iterator(const BitMap& map, idx_t beg, idx_t end);

// Returns true if the remaining iteration range is empty.
bool is_empty() const;

// Returns the index of the first set bit in the remaining iteration range.
// precondition: !is_empty()
idx_t index() const;

// Updates index() to the position of the first set bit in the range
// [index(), end), where end was the corresponding constructor argument.
// The iterator instead becomes empty if there aren't any set bits in
// that range.
// precondition: !is_empty()
void step();

// Range-based for loop support.
RBFIterator begin() const;
RBFIterator end() const;
};

// Provides iteration over the indices of the set bits in a range of a bitmap,
// in decreasing order. This is an alternative to the reverse_iterate() function.
class BitMap::ReverseIterator {
IteratorImpl _impl;

static idx_t initial_end(const BitMap& map, idx_t beg, idx_t end);

public:
// Constructs an empty iterator.
ReverseIterator();

// Constructs a reverse iterator for map, over the range [0, map.size()).
explicit ReverseIterator(const BitMap& map);

// Constructs a reverse iterator for map, over the range [beg, end).
// If there are no set bits in that range, the resulting iterator is empty.
// Otherwise, index() is initially the position of the last set bit in
// that range.
// precondition: beg and end form a valid range for map.
ReverseIterator(const BitMap& map, idx_t beg, idx_t end);

// Returns true if the remaining iteration range is empty.
bool is_empty() const;

// Returns the index of the last set bit in the remaining iteration range.
// precondition: !is_empty()
idx_t index() const;

// Updates index() to the position of the last set bit in the range
// [beg, index()), where beg was the corresponding constructor argument.
// The iterator instead becomes empty if there aren't any set bits in
// that range.
// precondition: !is_empty()
void step();

// Range-based for loop support.
ReverseRBFIterator begin() const;
ReverseRBFIterator end() const;
};

// Provides range-based for loop iteration support. This class is not
// intended for direct use by an application. It provides the functionality
// required by a range-based for loop with an Iterator as the range.
class BitMap::RBFIterator {
friend class Iterator;

IteratorImpl _impl;

RBFIterator(const BitMap* map, idx_t beg, idx_t end);

public:
bool operator!=(const RBFIterator& i) const;
idx_t operator*() const;
RBFIterator& operator++();
};

// Provides range-based for loop reverse iteration support. This class is
// not intended for direct use by an application. It provides the
// functionality required by a range-based for loop with a ReverseIterator
// as the range.
class BitMap::ReverseRBFIterator {
friend class ReverseIterator;

IteratorImpl _impl;

ReverseRBFIterator(const BitMap* map, idx_t beg, idx_t end);

public:
bool operator!=(const ReverseRBFIterator& i) const;
idx_t operator*() const;
ReverseRBFIterator& operator++();
};

// CRTP: BitmapWithAllocator exposes the following Allocator interfaces upward to GrowableBitMap.
//
// bm_word_t* allocate(idx_t size_in_words) const;
Expand Down
155 changes: 155 additions & 0 deletions src/hotspot/share/utilities/bitMap.inline.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -370,6 +370,161 @@ inline bool BitMap::reverse_iterate(BitMapClosureType* cl, idx_t beg, idx_t end)
return reverse_iterate(function, beg, end);
}

/// BitMap::IteratorImpl

inline BitMap::IteratorImpl::IteratorImpl()
: _map(nullptr), _cur_beg(0), _cur_end(0)
{}

inline BitMap::IteratorImpl::IteratorImpl(const BitMap* map, idx_t beg, idx_t end)
: _map(map), _cur_beg(beg), _cur_end(end)
{}

inline bool BitMap::IteratorImpl::is_empty() const {
return _cur_beg == _cur_end;
}

inline BitMap::idx_t BitMap::IteratorImpl::first() const {
assert_not_empty();
return _cur_beg;
}

inline BitMap::idx_t BitMap::IteratorImpl::last() const {
assert_not_empty();
return _cur_end - 1;
}

inline void BitMap::IteratorImpl::step_first() {
assert_not_empty();
_cur_beg = _map->find_first_set_bit(_cur_beg + 1, _cur_end);
}

inline void BitMap::IteratorImpl::step_last() {
assert_not_empty();
idx_t lastpos = last();
idx_t pos = _map->find_last_set_bit(_cur_beg, lastpos);
_cur_end = (pos < lastpos) ? (pos + 1) : _cur_beg;
}

/// BitMap::Iterator

inline BitMap::Iterator::Iterator() : _impl() {}

inline BitMap::Iterator::Iterator(const BitMap& map)
: Iterator(map, 0, map.size())
{}

inline BitMap::Iterator::Iterator(const BitMap& map, idx_t beg, idx_t end)
: _impl(&map, map.find_first_set_bit(beg, end), end)
{}

inline bool BitMap::Iterator::is_empty() const {
return _impl.is_empty();
}

inline BitMap::idx_t BitMap::Iterator::index() const {
return _impl.first();
}

inline void BitMap::Iterator::step() {
_impl.step_first();
}

inline BitMap::RBFIterator BitMap::Iterator::begin() const {
return RBFIterator(_impl._map, _impl._cur_beg, _impl._cur_end);
}

inline BitMap::RBFIterator BitMap::Iterator::end() const {
return RBFIterator(_impl._map, _impl._cur_end, _impl._cur_end);
}

/// BitMap::ReverseIterator

inline BitMap::idx_t BitMap::ReverseIterator::initial_end(const BitMap& map,
idx_t beg,
idx_t end) {
idx_t pos = map.find_last_set_bit(beg, end);
return (pos < end) ? (pos + 1) : beg;
}

inline BitMap::ReverseIterator::ReverseIterator() : _impl() {}

inline BitMap::ReverseIterator::ReverseIterator(const BitMap& map)
: ReverseIterator(map, 0, map.size())
{}

inline BitMap::ReverseIterator::ReverseIterator(const BitMap& map,
idx_t beg,
idx_t end)
: _impl(&map, beg, initial_end(map, beg, end))
{}

inline bool BitMap::ReverseIterator::is_empty() const {
return _impl.is_empty();
}

inline BitMap::idx_t BitMap::ReverseIterator::index() const {
return _impl.last();
}

inline void BitMap::ReverseIterator::step() {
_impl.step_last();
}

inline BitMap::ReverseRBFIterator BitMap::ReverseIterator::begin() const {
return ReverseRBFIterator(_impl._map, _impl._cur_beg, _impl._cur_end);
}

inline BitMap::ReverseRBFIterator BitMap::ReverseIterator::end() const {
return ReverseRBFIterator(_impl._map, _impl._cur_beg, _impl._cur_beg);
}

/// BitMap::RBFIterator

inline BitMap::RBFIterator::RBFIterator(const BitMap* map, idx_t beg, idx_t end)
: _impl(map, beg, end)
{}

inline bool BitMap::RBFIterator::operator!=(const RBFIterator& i) const {
// Shouldn't be comparing RBF iterators from different contexts.
assert(_impl._map == i._impl._map, "mismatched range-based for iterators");
assert(_impl._cur_end == i._impl._cur_end, "mismatched range-based for iterators");
return _impl._cur_beg != i._impl._cur_beg;
}

inline BitMap::idx_t BitMap::RBFIterator::operator*() const {
return _impl.first();
}

inline BitMap::RBFIterator& BitMap::RBFIterator::operator++() {
_impl.step_first();
return *this;
}

/// BitMap::ReverseRBFIterator

inline BitMap::ReverseRBFIterator::ReverseRBFIterator(const BitMap* map,
idx_t beg,
idx_t end)
: _impl(map, beg, end)
{}

inline bool BitMap::ReverseRBFIterator::operator!=(const ReverseRBFIterator& i) const {
// Shouldn't be comparing RBF iterators from different contexts.
assert(_impl._map == i._impl._map, "mismatched range-based for iterators");
assert(_impl._cur_beg == i._impl._cur_beg, "mismatched range-based for iterators");
return _impl._cur_end != i._impl._cur_end;
}

inline BitMap::idx_t BitMap::ReverseRBFIterator::operator*() const {
return _impl.last();
}

inline BitMap::ReverseRBFIterator& BitMap::ReverseRBFIterator::operator++() {
_impl.step_last();
return *this;
}

// 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
Expand Down
Loading