PieceTable: keep the line index across consolidation; reset moved-from

Consolidation rewrites pieces without changing content or offsets but
invalidated the line index, so once a buffer passed the piece limit
every edit paid a full rescan again. A moved-from table kept the index
of the text it gave away, and Insert now updates that index in place,
producing ranges past the end of its buffer.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015rcVQiiWyTzoNrsvLSaAfB
This commit is contained in:
Claude
2026-09-24 09:16:04 -07:00
committed by Kyle Isom
parent 7b8ccbb8db
commit 0075c7aa86
2 changed files with 39 additions and 4 deletions
+5 -2
View File
@@ -74,6 +74,7 @@ PieceTable::PieceTable(PieceTable &&other) noexcept
{
other.dirty_ = true;
other.total_size_ = 0;
other.InvalidateLineIndex(); // its index described the moved-away text
version_ = other.version_;
range_cache_ = {};
find_cache_ = {};
@@ -93,6 +94,7 @@ PieceTable::operator=(PieceTable &&other) noexcept
total_size_ = other.total_size_;
other.dirty_ = true;
other.total_size_ = 0;
other.InvalidateLineIndex(); // its index described the moved-away text
version_ = other.version_;
range_cache_ = {};
find_cache_ = {};
@@ -603,9 +605,10 @@ PieceTable::consolidateRange(std::size_t start_idx, std::size_t end_idx)
pieces_.begin() + static_cast<std::ptrdiff_t>(end_idx));
pieces_.insert(pieces_.begin() + static_cast<std::ptrdiff_t>(start_idx), consolidated);
// total_size_ unchanged
// total_size_ unchanged. Content and byte offsets are unchanged too, so
// the line index stays valid (invalidating it here forced a full rescan
// on every edit once a buffer had many pieces).
dirty_ = true;
InvalidateLineIndex();
coalesceNeighbors(start_idx);
// Layout changed; invalidate caches/version
version_++;