Commit 1d5e8683 authored by Luis Javier Merino's avatar Luis Javier Merino Committed by Tomaz Canabrava
Browse files

[CompactHistory] store biased starts of lines

Using line lengths, moving up in scroll history would require traversing
line lengths adding them until getting the start of the required line.
Using line starts, removing lines as they scroll past history would
require traversing the whole vector and updating the line starts.  A
better option is storing biased line starts, which doesn't require any
traversing of the vector for common operations (hopefully reflowing is
not a common operation).
parent 86db4e0c
Pipeline #128546 passed with stage
in 2 minutes and 3 seconds
......@@ -21,12 +21,11 @@ CompactHistoryScroll::CompactHistoryScroll(const unsigned int maxLineCount)
void CompactHistoryScroll::removeLinesFromTop(size_t lines)
{
if (_lineDatas.size() > 1) {
const int removing = std::accumulate(_lineDatas.begin(), _lineDatas.begin() + lines, 0, [](int total, LineData ld) {
return total + ld.length;
});
const unsigned int removing = _lineDatas.at(lines - 1).index;
_lineDatas.erase(_lineDatas.begin(), _lineDatas.begin() + lines);
_cells.erase(_cells.begin(), _cells.begin() + removing);
_cells.erase(_cells.begin(), _cells.begin() + (removing - _indexBias));
_indexBias = removing;
} else {
_lineDatas.clear();
_cells.clear();
......@@ -37,9 +36,9 @@ void CompactHistoryScroll::addCells(const Character a[], const int count)
{
_cells.insert(_cells.end(), a, a + count);
// store the length of line + default flag
// store the (biased) start of next line + default flag
// the flag is later updated when addLine is called
_lineDatas.push_back({count, LINE_DEFAULT});
_lineDatas.push_back({static_cast<unsigned int>(_cells.size() + _indexBias), LINE_DEFAULT});
if (_lineDatas.size() > _maxLineCount + 5) {
removeLinesFromTop(5);
......@@ -135,33 +134,28 @@ int CompactHistoryScroll::reflowLines(const int columns)
auto reflowLineLen = [](int start, int end) {
return end - start;
};
auto setNewLine = [](std::vector<LineData> &change, int length, LineProperty flag) {
change.push_back({length, flag});
auto setNewLine = [](std::vector<LineData> &change, unsigned int index, LineProperty flag) {
change.push_back({index, flag});
};
int currentPos = 0;
while (currentPos < getLines()) {
int lineStart = startOfLine(currentPos);
// next line will be startLine + length of startLine
// i.e., start of next line
int endLine = lineStart + lineLen(currentPos);
int startLine = startOfLine(currentPos);
int endLine = startOfLine(currentPos + 1);
LineProperty lineProperty = getLineProperty(currentPos);
// Join the lines if they are wrapped
while (currentPos < getLines() - 1 && isWrappedLine(currentPos)) {
currentPos++;
endLine += lineLen(currentPos);
endLine = startOfLine(currentPos + 1);
}
// Now reflow the lines
int last = lineStart;
while (reflowLineLen(lineStart, endLine) > columns && !(lineProperty & (LINE_DOUBLEHEIGHT_BOTTOM | LINE_DOUBLEHEIGHT_TOP))) {
lineStart += columns;
// new length = newLineStart - prevLineStart
setNewLine(newLineData, lineStart - last, lineProperty | LINE_WRAPPED);
last = lineStart;
while (reflowLineLen(startLine, endLine) > columns && !(lineProperty & (LINE_DOUBLEHEIGHT_BOTTOM | LINE_DOUBLEHEIGHT_TOP))) {
startLine += columns;
setNewLine(newLineData, startLine + _indexBias, lineProperty | LINE_WRAPPED);
}
setNewLine(newLineData, endLine - last, lineProperty & ~LINE_WRAPPED);
setNewLine(newLineData, endLine + _indexBias, lineProperty & ~LINE_WRAPPED);
currentPos++;
}
_lineDatas = std::move(newLineData);
......
......@@ -44,8 +44,24 @@ private:
*/
std::deque<Character> _cells;
/**
* Each entry contains the start of the next line and the current line's
* properties. The start of lines is biased by _indexBias, i.e. an index
* value of _indexBias corresponds to _cells' zero index.
*
* The use of a biased line start means we don't need to traverse the
* vector recalculating line starts when removing lines from the top, and
* also we don't need to traverse the vector to compute the start of a line
* as we would have to do if we stored line lengths.
*
* unsigned int means we're limited in common architectures to 4 million
* characters, but CompactHistoryScroll is limited by the UI to 1_000_000
* lines (see historyLineSpinner in src/widgets/HistorySizeWidget.ui), so
* enough for 1_000_000 lines of an average ~4295 length (and each
* Character takes 16 bytes, so that's 64Gb!).
*/
struct LineData {
int length;
unsigned int index;
LineProperty flag;
};
/**
......@@ -53,6 +69,7 @@ private:
* The size of this buffer is the number of lines we have.
*/
std::vector<LineData> _lineDatas;
unsigned int _indexBias;
/**
* Max number of lines we can hold
......@@ -66,21 +83,17 @@ private:
inline int lineLen(const int line) const
{
return _lineDatas.at(line).length;
return line == 0 ? _lineDatas.at(0).index - _indexBias : _lineDatas.at(line).index - _lineDatas.at(line - 1).index;
}
/**
* Get the start of @p line in _cells buffer
*
* Since _index contains lengths of lines, we need
* to add up till we reach @p line. That will be the starting point
* of @p line.
* index actually contains the start of the next line.
*/
inline int startOfLine(const int line) const
{
return std::accumulate(_lineDatas.begin(), _lineDatas.begin() + line, 0, [](int total, LineData ld) {
return total + ld.length;
});
return line == 0 ? 0 : _lineDatas.at(line - 1).index - _indexBias;
}
};
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment