diff options
author | Neil <nyamatongwe@gmail.com> | 2021-05-07 22:39:01 +1000 |
---|---|---|
committer | Neil <nyamatongwe@gmail.com> | 2021-05-07 22:39:01 +1000 |
commit | cdf89374e4bbf0d4a02100968b38b263dee239e1 (patch) | |
tree | c64ad5ad174f6462d0a62ad7ca5ef9888d236503 | |
parent | da718f8909b937bd839fc8e09d0b81727644c5fd (diff) | |
download | scintilla-mirror-cdf89374e4bbf0d4a02100968b38b263dee239e1.tar.gz |
When resizing for Cache::page, move cached entries to correct positions.
Hoist position calculation into EntryForLine method.
-rw-r--r-- | src/PositionCache.cxx | 77 | ||||
-rw-r--r-- | src/PositionCache.h | 2 |
2 files changed, 58 insertions, 21 deletions
diff --git a/src/PositionCache.cxx b/src/PositionCache.cxx index bf7c4623a..18971dc99 100644 --- a/src/PositionCache.cxx +++ b/src/PositionCache.cxx @@ -364,17 +364,22 @@ XYPOSITION ScreenLine::TabPositionAfter(XYPOSITION xPosition) const { LineLayoutCache::LineLayoutCache() : level(Cache::none), allInvalidated(false), styleClock(-1), useCount(0) { - Allocate(0); } -LineLayoutCache::~LineLayoutCache() { - Deallocate(); -} +LineLayoutCache::~LineLayoutCache() = default; -void LineLayoutCache::Allocate(size_t length_) { - PLATFORM_ASSERT(cache.empty()); - allInvalidated = false; - cache.resize(length_); +size_t LineLayoutCache::EntryForLine(Sci::Line line) const noexcept { + switch (level) { + case Cache::none: + return 0; + case Cache::caret: + return 0; + case Cache::page: + return 1 + (line % (cache.size() - 1)); + case Cache::document: + return line; + } + return 0; } void LineLayoutCache::AllocateForLevel(Sci::Line linesOnScreen, Sci::Line linesInDoc) { @@ -387,16 +392,47 @@ void LineLayoutCache::AllocateForLevel(Sci::Line linesOnScreen, Sci::Line linesI } else if (level == Cache::document) { lengthForLevel = linesInDoc; } - if (lengthForLevel > cache.size()) { - Deallocate(); - Allocate(lengthForLevel); - } else { - if (lengthForLevel < cache.size()) { - for (size_t i = lengthForLevel; i < cache.size(); i++) { - cache[i].reset(); + + if (lengthForLevel != cache.size()) { + PLATFORM_ASSERT(useCount == 0); + allInvalidated = false; + cache.resize(lengthForLevel); + // Cache::none -> no entries + // Cache::caret -> 1 entry can take any line + // Cache::document -> entry per line so each line in correct entry after resize + if (level == Cache::page) { + // Cache::page -> locates lines in particular entries which may be incorrect after + // a resize so move them to correct entries. + for (size_t i = 1; i < cache.size();) { + size_t increment = 1; + if (cache[i]) { + const size_t posForLine = EntryForLine(cache[i]->LineNumber()); + if (posForLine != i) { + if (cache[posForLine]) { + if (EntryForLine(cache[posForLine]->LineNumber()) == posForLine) { + // [posForLine] already holds line that is in correct place + cache[i].reset(); // This line has nowhere to go so reset it. + } else { + std::swap(cache[i], cache[posForLine]); + increment = 0; + // Don't increment as newly swapped in value may have to move + } + } else { + cache[posForLine] = std::move(cache[i]); + } + } + } + i += increment; } + +#ifdef CHECK_LLC + for (size_t i = 1; i < cache.size(); i++) { + if (cache[i]) { + PLATFORM_ASSERT(EntryForLine(cache[i]->LineNumber()) == i); + } + } +#endif } - cache.resize(lengthForLevel); } PLATFORM_ASSERT(cache.size() == lengthForLevel); } @@ -423,7 +459,8 @@ void LineLayoutCache::SetLevel(Cache level_) noexcept { allInvalidated = false; if ((static_cast<int>(level_) != -1) && (level != level_)) { level = level_; - Deallocate(); + allInvalidated = false; + cache.clear(); } } @@ -440,13 +477,13 @@ LineLayout *LineLayoutCache::Retrieve(Sci::Line lineNumber, Sci::Line lineCaret, if (level == Cache::page) { // If first entry is this line then just reuse it. if (!(cache[0] && (cache[0]->lineNumber == lineNumber))) { - const size_t posForLine = 1 + (lineNumber % (cache.size() - 1)); + const size_t posForLine = EntryForLine(lineNumber); if (lineNumber == lineCaret) { // Use position 0 for caret line. if (cache[0]) { // Another line is currently in [0] so move it out to its normal position. // Since it was recently the caret line its likely to be needed soon. - const size_t posNewForEntry0 = 1 + (cache[0]->lineNumber % (cache.size() - 1)); + const size_t posNewForEntry0 = EntryForLine(cache[0]->lineNumber); if (posForLine == posNewForEntry0) { std::swap(cache[0], cache[posNewForEntry0]); } else { @@ -473,7 +510,7 @@ LineLayout *LineLayoutCache::Retrieve(Sci::Line lineNumber, Sci::Line lineCaret, cache[pos] = std::make_unique<LineLayout>(lineNumber, maxChars); } cache[pos]->inCache = true; -#ifndef CHECK_LLC_UNIQUE +#ifdef CHECK_LLC // Expensive check that there is only one entry for any line number std::vector<bool> linesInCache(linesInDoc); for (const auto &entry : cache) { diff --git a/src/PositionCache.h b/src/PositionCache.h index 479476eb9..41da53bcf 100644 --- a/src/PositionCache.h +++ b/src/PositionCache.h @@ -164,7 +164,7 @@ private: bool allInvalidated; int styleClock; int useCount; - void Allocate(size_t length_); + size_t EntryForLine(Sci::Line line) const noexcept; void AllocateForLevel(Sci::Line linesOnScreen, Sci::Line linesInDoc); public: LineLayoutCache(); |