Skip to content

Commit

Permalink
Improve bitmap::_calculateArea performance (#6572)
Browse files Browse the repository at this point in the history
`bitmap::_calculateArea` performance can be improved by leveraging the
optimized `find_first`/`find_next` methods instead of iterating through
the bitmap manually.
  • Loading branch information
lhecker authored Jun 19, 2020
1 parent b91430b commit 15f2535
Show file tree
Hide file tree
Showing 2 changed files with 18 additions and 9 deletions.
3 changes: 3 additions & 0 deletions src/inc/LibraryIncludes.h
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,10 @@

// Dynamic Bitset (optional dependency on LibPopCnt for perf at bit counting)
// Variable-size compressed-storage header-only bit flag storage library.
#pragma warning(push)
#pragma warning(disable:4702) // unreachable code
#include <dynamic_bitset.hpp>
#pragma warning(pop)

// {fmt}, a C++20-compatible formatting library
#include <fmt/format.h>
Expand Down
24 changes: 15 additions & 9 deletions src/inc/til/bitmap.h
Original file line number Diff line number Diff line change
Expand Up @@ -81,16 +81,20 @@ namespace til // Terminal Implementation Library. Also: "Today I Learned"
const ptrdiff_t _end;
til::rectangle _run;

// Update _run to contain the next rectangle of consecutively set bits within this bitmap.
// _calculateArea may be called repeatedly to yield all those rectangles.
void _calculateArea()
{
// Backup the position as the next one.
_nextPos = _pos;
// The following logic first finds the next set bit in this bitmap and the next unset bit past that.
// The area in between those positions are thus all set bits and will end up being the next _run.

// Seek forward until we find an on bit.
while (_nextPos < _end && !_values[_nextPos])
{
++_nextPos;
}
// dynamic_bitset allows you to quickly find the next set bit using find_next(prev),
// where "prev" is the position _past_ which should be searched (i.e. excluding position "prev").
// If _pos is still 0, we thus need to use the counterpart find_first().
const auto nextPos = _pos == 0 ? _values.find_first() : _values.find_next(_pos - 1);
// If no next set bit can be found, npos is returned, which is SIZE_T_MAX.
// saturated_cast can ensure that this will be converted to PTRDIFF_T_MAX (which is greater than _end).
_nextPos = base::saturated_cast<ptrdiff_t>(nextPos);

// If we haven't reached the end yet...
if (_nextPos < _end)
Expand Down Expand Up @@ -118,8 +122,10 @@ namespace til // Terminal Implementation Library. Also: "Today I Learned"
}
else
{
// If we reached the end, set the pos because the run is empty.
_pos = _nextPos;
// If we reached the end _nextPos may be >= _end (potentially even PTRDIFF_T_MAX).
// ---> Mark the end of the iterator by updating the state with _end.
_pos = _end;
_nextPos = _end;
_run = til::rectangle{};
}
}
Expand Down

0 comments on commit 15f2535

Please sign in to comment.