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
+34 -2
View File
@@ -511,10 +511,10 @@ TEST(Audit_B6_HorizontalScroll_CountsCells)
// P2: the line index is updated in place by Insert/Delete. Query it after
// every edit (so it is never dirty) and compare with a plain string model.
TEST(Audit_P2_IncrementalLineIndex_MatchesModel)
static void
check_incremental_line_index(PieceTable &t)
{
std::mt19937 rng(20260923u);
PieceTable t;
std::string model;
const char alphabet[] = "ab\nc\n\nd";
for (int step = 0; step < 3000; ++step) {
@@ -546,3 +546,35 @@ TEST(Audit_P2_IncrementalLineIndex_MatchesModel)
}
}
}
TEST(Audit_P2_IncrementalLineIndex_MatchesModel)
{
PieceTable t;
check_incremental_line_index(t);
}
// Consolidation (forced here by a tiny piece limit) rewrites pieces without
// changing content; the incrementally maintained index must stay correct.
TEST(Audit_P2_IncrementalLineIndex_WithConsolidation)
{
PieceTable t(0, 8, 64, 1 << 20);
check_incremental_line_index(t);
}
// A moved-from table must not keep (and incrementally update) the index of
// the text it gave away.
TEST(Audit_PieceTable_MovedFrom_LineIndexReset)
{
const std::string text = "l1\nl2\nl3\n";
PieceTable a;
a.Append(text.data(), text.size());
ASSERT_EQ(a.LineCount(), (std::size_t) 4);
PieceTable b(std::move(a));
a.Insert(0, "x", 1);
ASSERT_EQ(a.Size(), (std::size_t) 1);
ASSERT_EQ(a.LineCount(), (std::size_t) 1);
ASSERT_EQ(b.LineCount(), (std::size_t) 4);
}