aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorNeil <nyamatongwe@gmail.com>2021-05-07 22:39:01 +1000
committerNeil <nyamatongwe@gmail.com>2021-05-07 22:39:01 +1000
commitcdf89374e4bbf0d4a02100968b38b263dee239e1 (patch)
treec64ad5ad174f6462d0a62ad7ca5ef9888d236503
parentda718f8909b937bd839fc8e09d0b81727644c5fd (diff)
downloadscintilla-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.cxx77
-rw-r--r--src/PositionCache.h2
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();