diff options
author | Neil <nyamatongwe@gmail.com> | 2021-05-07 17:04:06 +1000 |
---|---|---|
committer | Neil <nyamatongwe@gmail.com> | 2021-05-07 17:04:06 +1000 |
commit | ed07e1aa1c0c5ae0168add6ed9964c6aefc19578 (patch) | |
tree | 8e0b7f714636d0d7856607f73af028b101a47fd8 /src/PositionCache.cxx | |
parent | 67695f7fd5725f534dc3664c4ce76c542940a4a7 (diff) | |
download | scintilla-mirror-ed07e1aa1c0c5ae0168add6ed9964c6aefc19578.tar.gz |
Ensure a line is only ever in one line layout cache entry. Preserve calculated
data where possible when overwriting a cache entry.
Diffstat (limited to 'src/PositionCache.cxx')
-rw-r--r-- | src/PositionCache.cxx | 78 |
1 files changed, 49 insertions, 29 deletions
diff --git a/src/PositionCache.cxx b/src/PositionCache.cxx index a3e8e74f8..87fa544cd 100644 --- a/src/PositionCache.cxx +++ b/src/PositionCache.cxx @@ -421,49 +421,69 @@ void LineLayoutCache::SetLevel(Cache level_) noexcept { LineLayout *LineLayoutCache::Retrieve(Sci::Line lineNumber, Sci::Line lineCaret, int maxChars, int styleClock_, Sci::Line linesOnScreen, Sci::Line linesInDoc) { + PLATFORM_ASSERT(useCount == 0); AllocateForLevel(linesOnScreen, linesInDoc); if (styleClock != styleClock_) { Invalidate(LineLayout::ValidLevel::checkTextAndStyle); styleClock = styleClock_; } allInvalidated = false; - Sci::Position pos = -1; - LineLayout *ret = nullptr; - if (level == Cache::caret) { - pos = 0; - } else if (level == Cache::page) { - if (lineNumber == lineCaret) { - pos = 0; - } else if (cache.size() > 1) { - pos = 1 + (lineNumber % (cache.size() - 1)); + size_t pos = 0; + 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)); + 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)); + if (posForLine == posNewForEntry0) { + std::swap(cache[0], cache[posNewForEntry0]); + } else { + cache[posNewForEntry0] = std::move(cache[0]); + } + } + if (cache[posForLine] && (cache[posForLine]->lineNumber == lineNumber)) { + // Caret line is currently somewhere else so move it to [0]. + cache[0] = std::move(cache[posForLine]); + } + } else { + pos = posForLine; + } } } else if (level == Cache::document) { pos = lineNumber; } - if (pos >= 0) { - PLATFORM_ASSERT(useCount == 0); - if (!cache.empty() && (pos < static_cast<int>(cache.size()))) { - if (cache[pos]) { - if ((cache[pos]->lineNumber != lineNumber) || - (cache[pos]->maxLineLength < maxChars)) { - cache[pos].reset(); - } - } - if (!cache[pos]) { - cache[pos] = std::make_unique<LineLayout>(maxChars); + + if (pos < cache.size()) { + if (cache[pos] && + ((cache[pos]->lineNumber != lineNumber) || (cache[pos]->maxLineLength < maxChars))) { + cache[pos].reset(); + } + if (!cache[pos]) { + cache[pos] = std::make_unique<LineLayout>(maxChars); + } + cache[pos]->lineNumber = lineNumber; + cache[pos]->inCache = true; +#ifdef CHECK_LLC_UNIQUE + // Expensive check that there is only one entry for any line number + std::vector<bool> linesInCache(linesInDoc); + for (const auto &entry : cache) { + if (entry) { + PLATFORM_ASSERT(!linesInCache[entry->lineNumber]); + linesInCache[entry->lineNumber] = true; } - cache[pos]->lineNumber = lineNumber; - cache[pos]->inCache = true; - ret = cache[pos].get(); - useCount++; } +#endif + useCount++; + return cache[pos].get(); } - if (!ret) { - ret = new LineLayout(maxChars); - ret->lineNumber = lineNumber; - } - + // Only reach here for level == Cache::none + LineLayout *ret = new LineLayout(maxChars); + ret->lineNumber = lineNumber; return ret; } |