Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve bitmap::_calculateArea performance #6572

Merged
2 commits merged into from
Jun 19, 2020
Merged
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
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);
miniksa marked this conversation as resolved.
Show resolved Hide resolved
// 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;
miniksa marked this conversation as resolved.
Show resolved Hide resolved
_run = til::rectangle{};
}
}
Expand Down