Improve bitmap::_calculateArea performance (#6572)

`bitmap::_calculateArea` performance can be improved by leveraging the
optimized `find_first`/`find_next` methods instead of iterating through
the bitmap manually.
This commit is contained in:
Leonard Hecker 2020-06-20 00:09:30 +02:00 committed by GitHub
parent b91430b64d
commit 15f2535752
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 18 additions and 9 deletions

View file

@ -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>

View file

@ -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)
@ -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{};
}
}