sum_tree: Store context on cursor (#34904)

This gets rid of the need to pass context to all cursor functions. In
practice context is always immutable when interacting with cursors.

A nicety of this is in the follow-up PR we will be able to implement
Iterator for all Cursors/filter cursors (hell, we may be able to get rid
of filter cursor altogether, as it is just a custom `filter` impl on
iterator trait).
Release Notes:

- N/A
This commit is contained in:
Piotr Osiewicz 2025-07-22 18:20:48 +02:00 committed by GitHub
parent fa3e1ccc37
commit 64d0fec699
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
23 changed files with 749 additions and 876 deletions

View file

@ -41,9 +41,9 @@ impl Rope {
self.push_chunk(chunk.as_slice());
let mut chunks = rope.chunks.cursor::<()>(&());
chunks.next(&());
chunks.next(&());
self.chunks.append(chunks.suffix(&()), &());
chunks.next();
chunks.next();
self.chunks.append(chunks.suffix(), &());
self.check_invariants();
return;
}
@ -283,7 +283,7 @@ impl Rope {
return self.summary().len_utf16;
}
let mut cursor = self.chunks.cursor::<(usize, OffsetUtf16)>(&());
cursor.seek(&offset, Bias::Left, &());
cursor.seek(&offset, Bias::Left);
let overshoot = offset - cursor.start().0;
cursor.start().1
+ cursor.item().map_or(Default::default(), |chunk| {
@ -296,7 +296,7 @@ impl Rope {
return self.summary().len;
}
let mut cursor = self.chunks.cursor::<(OffsetUtf16, usize)>(&());
cursor.seek(&offset, Bias::Left, &());
cursor.seek(&offset, Bias::Left);
let overshoot = offset - cursor.start().0;
cursor.start().1
+ cursor.item().map_or(Default::default(), |chunk| {
@ -309,7 +309,7 @@ impl Rope {
return self.summary().lines;
}
let mut cursor = self.chunks.cursor::<(usize, Point)>(&());
cursor.seek(&offset, Bias::Left, &());
cursor.seek(&offset, Bias::Left);
let overshoot = offset - cursor.start().0;
cursor.start().1
+ cursor.item().map_or(Point::zero(), |chunk| {
@ -322,7 +322,7 @@ impl Rope {
return self.summary().lines_utf16();
}
let mut cursor = self.chunks.cursor::<(usize, PointUtf16)>(&());
cursor.seek(&offset, Bias::Left, &());
cursor.seek(&offset, Bias::Left);
let overshoot = offset - cursor.start().0;
cursor.start().1
+ cursor.item().map_or(PointUtf16::zero(), |chunk| {
@ -335,7 +335,7 @@ impl Rope {
return self.summary().lines_utf16();
}
let mut cursor = self.chunks.cursor::<(Point, PointUtf16)>(&());
cursor.seek(&point, Bias::Left, &());
cursor.seek(&point, Bias::Left);
let overshoot = point - cursor.start().0;
cursor.start().1
+ cursor.item().map_or(PointUtf16::zero(), |chunk| {
@ -348,7 +348,7 @@ impl Rope {
return self.summary().len;
}
let mut cursor = self.chunks.cursor::<(Point, usize)>(&());
cursor.seek(&point, Bias::Left, &());
cursor.seek(&point, Bias::Left);
let overshoot = point - cursor.start().0;
cursor.start().1
+ cursor
@ -369,7 +369,7 @@ impl Rope {
return self.summary().len;
}
let mut cursor = self.chunks.cursor::<(PointUtf16, usize)>(&());
cursor.seek(&point, Bias::Left, &());
cursor.seek(&point, Bias::Left);
let overshoot = point - cursor.start().0;
cursor.start().1
+ cursor.item().map_or(0, |chunk| {
@ -382,7 +382,7 @@ impl Rope {
return self.summary().lines;
}
let mut cursor = self.chunks.cursor::<(PointUtf16, Point)>(&());
cursor.seek(&point.0, Bias::Left, &());
cursor.seek(&point.0, Bias::Left);
let overshoot = Unclipped(point.0 - cursor.start().0);
cursor.start().1
+ cursor.item().map_or(Point::zero(), |chunk| {
@ -392,7 +392,7 @@ impl Rope {
pub fn clip_offset(&self, mut offset: usize, bias: Bias) -> usize {
let mut cursor = self.chunks.cursor::<usize>(&());
cursor.seek(&offset, Bias::Left, &());
cursor.seek(&offset, Bias::Left);
if let Some(chunk) = cursor.item() {
let mut ix = offset - cursor.start();
while !chunk.text.is_char_boundary(ix) {
@ -415,7 +415,7 @@ impl Rope {
pub fn clip_offset_utf16(&self, offset: OffsetUtf16, bias: Bias) -> OffsetUtf16 {
let mut cursor = self.chunks.cursor::<OffsetUtf16>(&());
cursor.seek(&offset, Bias::Right, &());
cursor.seek(&offset, Bias::Right);
if let Some(chunk) = cursor.item() {
let overshoot = offset - cursor.start();
*cursor.start() + chunk.as_slice().clip_offset_utf16(overshoot, bias)
@ -426,7 +426,7 @@ impl Rope {
pub fn clip_point(&self, point: Point, bias: Bias) -> Point {
let mut cursor = self.chunks.cursor::<Point>(&());
cursor.seek(&point, Bias::Right, &());
cursor.seek(&point, Bias::Right);
if let Some(chunk) = cursor.item() {
let overshoot = point - cursor.start();
*cursor.start() + chunk.as_slice().clip_point(overshoot, bias)
@ -437,7 +437,7 @@ impl Rope {
pub fn clip_point_utf16(&self, point: Unclipped<PointUtf16>, bias: Bias) -> PointUtf16 {
let mut cursor = self.chunks.cursor::<PointUtf16>(&());
cursor.seek(&point.0, Bias::Right, &());
cursor.seek(&point.0, Bias::Right);
if let Some(chunk) = cursor.item() {
let overshoot = Unclipped(point.0 - cursor.start());
*cursor.start() + chunk.as_slice().clip_point_utf16(overshoot, bias)
@ -450,10 +450,6 @@ impl Rope {
self.clip_point(Point::new(row, u32::MAX), Bias::Left)
.column
}
pub fn ptr_eq(&self, other: &Self) -> bool {
self.chunks.ptr_eq(&other.chunks)
}
}
impl<'a> From<&'a str> for Rope {
@ -514,7 +510,7 @@ pub struct Cursor<'a> {
impl<'a> Cursor<'a> {
pub fn new(rope: &'a Rope, offset: usize) -> Self {
let mut chunks = rope.chunks.cursor(&());
chunks.seek(&offset, Bias::Right, &());
chunks.seek(&offset, Bias::Right);
Self {
rope,
chunks,
@ -525,7 +521,7 @@ impl<'a> Cursor<'a> {
pub fn seek_forward(&mut self, end_offset: usize) {
debug_assert!(end_offset >= self.offset);
self.chunks.seek_forward(&end_offset, Bias::Right, &());
self.chunks.seek_forward(&end_offset, Bias::Right);
self.offset = end_offset;
}
@ -540,14 +536,14 @@ impl<'a> Cursor<'a> {
let mut slice = Rope::new();
if let Some(start_chunk) = self.chunks.item() {
let start_ix = self.offset - self.chunks.start();
let end_ix = cmp::min(end_offset, self.chunks.end(&())) - self.chunks.start();
let end_ix = cmp::min(end_offset, self.chunks.end()) - self.chunks.start();
slice.push_chunk(start_chunk.slice(start_ix..end_ix));
}
if end_offset > self.chunks.end(&()) {
self.chunks.next(&());
if end_offset > self.chunks.end() {
self.chunks.next();
slice.append(Rope {
chunks: self.chunks.slice(&end_offset, Bias::Right, &()),
chunks: self.chunks.slice(&end_offset, Bias::Right),
});
if let Some(end_chunk) = self.chunks.item() {
let end_ix = end_offset - self.chunks.start();
@ -565,13 +561,13 @@ impl<'a> Cursor<'a> {
let mut summary = D::zero(&());
if let Some(start_chunk) = self.chunks.item() {
let start_ix = self.offset - self.chunks.start();
let end_ix = cmp::min(end_offset, self.chunks.end(&())) - self.chunks.start();
let end_ix = cmp::min(end_offset, self.chunks.end()) - self.chunks.start();
summary.add_assign(&D::from_chunk(start_chunk.slice(start_ix..end_ix)));
}
if end_offset > self.chunks.end(&()) {
self.chunks.next(&());
summary.add_assign(&self.chunks.summary(&end_offset, Bias::Right, &()));
if end_offset > self.chunks.end() {
self.chunks.next();
summary.add_assign(&self.chunks.summary(&end_offset, Bias::Right));
if let Some(end_chunk) = self.chunks.item() {
let end_ix = end_offset - self.chunks.start();
summary.add_assign(&D::from_chunk(end_chunk.slice(0..end_ix)));
@ -603,10 +599,10 @@ impl<'a> Chunks<'a> {
pub fn new(rope: &'a Rope, range: Range<usize>, reversed: bool) -> Self {
let mut chunks = rope.chunks.cursor(&());
let offset = if reversed {
chunks.seek(&range.end, Bias::Left, &());
chunks.seek(&range.end, Bias::Left);
range.end
} else {
chunks.seek(&range.start, Bias::Right, &());
chunks.seek(&range.start, Bias::Right);
range.start
};
Self {
@ -642,10 +638,10 @@ impl<'a> Chunks<'a> {
Bias::Right
};
if offset >= self.chunks.end(&()) {
self.chunks.seek_forward(&offset, bias, &());
if offset >= self.chunks.end() {
self.chunks.seek_forward(&offset, bias);
} else {
self.chunks.seek(&offset, bias, &());
self.chunks.seek(&offset, bias);
}
self.offset = offset;
@ -674,25 +670,25 @@ impl<'a> Chunks<'a> {
found = self.offset <= self.range.end;
} else {
self.chunks
.search_forward(|summary| summary.text.lines.row > 0, &());
.search_forward(|summary| summary.text.lines.row > 0);
self.offset = *self.chunks.start();
if let Some(newline_ix) = self.peek().and_then(|chunk| chunk.find('\n')) {
self.offset += newline_ix + 1;
found = self.offset <= self.range.end;
} else {
self.offset = self.chunks.end(&());
self.offset = self.chunks.end();
}
}
if self.offset == self.chunks.end(&()) {
if self.offset == self.chunks.end() {
self.next();
}
}
if self.offset > self.range.end {
self.offset = cmp::min(self.offset, self.range.end);
self.chunks.seek(&self.offset, Bias::Right, &());
self.chunks.seek(&self.offset, Bias::Right);
}
found
@ -711,7 +707,7 @@ impl<'a> Chunks<'a> {
let initial_offset = self.offset;
if self.offset == *self.chunks.start() {
self.chunks.prev(&());
self.chunks.prev();
}
if let Some(chunk) = self.chunks.item() {
@ -729,14 +725,14 @@ impl<'a> Chunks<'a> {
}
self.chunks
.search_backward(|summary| summary.text.lines.row > 0, &());
.search_backward(|summary| summary.text.lines.row > 0);
self.offset = *self.chunks.start();
if let Some(chunk) = self.chunks.item() {
if let Some(newline_ix) = chunk.text.rfind('\n') {
self.offset += newline_ix + 1;
if self.offset_is_valid() {
if self.offset == self.chunks.end(&()) {
self.chunks.next(&());
if self.offset == self.chunks.end() {
self.chunks.next();
}
return true;
@ -746,7 +742,7 @@ impl<'a> Chunks<'a> {
if !self.offset_is_valid() || self.chunks.item().is_none() {
self.offset = self.range.start;
self.chunks.seek(&self.offset, Bias::Right, &());
self.chunks.seek(&self.offset, Bias::Right);
}
self.offset < initial_offset && self.offset == 0
@ -765,7 +761,7 @@ impl<'a> Chunks<'a> {
slice_start..slice_end
} else {
let slice_start = self.offset - chunk_start;
let slice_end = cmp::min(self.chunks.end(&()), self.range.end) - chunk_start;
let slice_end = cmp::min(self.chunks.end(), self.range.end) - chunk_start;
slice_start..slice_end
};
@ -825,12 +821,12 @@ impl<'a> Iterator for Chunks<'a> {
if self.reversed {
self.offset -= chunk.len();
if self.offset <= *self.chunks.start() {
self.chunks.prev(&());
self.chunks.prev();
}
} else {
self.offset += chunk.len();
if self.offset >= self.chunks.end(&()) {
self.chunks.next(&());
if self.offset >= self.chunks.end() {
self.chunks.next();
}
}
@ -848,9 +844,9 @@ impl<'a> Bytes<'a> {
pub fn new(rope: &'a Rope, range: Range<usize>, reversed: bool) -> Self {
let mut chunks = rope.chunks.cursor(&());
if reversed {
chunks.seek(&range.end, Bias::Left, &());
chunks.seek(&range.end, Bias::Left);
} else {
chunks.seek(&range.start, Bias::Right, &());
chunks.seek(&range.start, Bias::Right);
}
Self {
chunks,
@ -861,7 +857,7 @@ impl<'a> Bytes<'a> {
pub fn peek(&self) -> Option<&'a [u8]> {
let chunk = self.chunks.item()?;
if self.reversed && self.range.start >= self.chunks.end(&()) {
if self.reversed && self.range.start >= self.chunks.end() {
return None;
}
let chunk_start = *self.chunks.start();
@ -881,9 +877,9 @@ impl<'a> Iterator for Bytes<'a> {
let result = self.peek();
if result.is_some() {
if self.reversed {
self.chunks.prev(&());
self.chunks.prev();
} else {
self.chunks.next(&());
self.chunks.next();
}
}
result
@ -905,9 +901,9 @@ impl io::Read for Bytes<'_> {
if len == chunk.len() {
if self.reversed {
self.chunks.prev(&());
self.chunks.prev();
} else {
self.chunks.next(&());
self.chunks.next();
}
}
Ok(len)