Skip to content

Commit 0c5e3e7

Browse files
committed
perf: add size_hint for rope CharIndices
1 parent 739d6a7 commit 0c5e3e7

File tree

1 file changed

+37
-3
lines changed

1 file changed

+37
-3
lines changed

src/rope.rs

Lines changed: 37 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -509,7 +509,7 @@ impl<'a> Rope<'a> {
509509
Lines {
510510
iter: match &self.repr {
511511
Repr::Light(s) => LinesEnum::Light(s),
512-
Repr::Full(data) => LinesEnum::Complex {
512+
Repr::Full(data) => LinesEnum::Full {
513513
iter: data,
514514
in_chunk_byte_idx: 0,
515515
chunk_idx: 0,
@@ -554,7 +554,7 @@ impl Hash for Rope<'_> {
554554

555555
enum LinesEnum<'a, 'b> {
556556
Light(&'b str),
557-
Complex {
557+
Full {
558558
iter: &'a Vec<(&'b str, usize)>,
559559
in_chunk_byte_idx: usize,
560560
chunk_idx: usize,
@@ -605,7 +605,7 @@ impl<'a> Iterator for Lines<'_, 'a> {
605605
}
606606
Lines {
607607
iter:
608-
LinesEnum::Complex {
608+
LinesEnum::Full {
609609
iter: chunks,
610610
ref mut in_chunk_byte_idx,
611611
ref mut chunk_idx,
@@ -777,6 +777,27 @@ impl Iterator for CharIndices<'_, '_> {
777777
}
778778
}
779779
}
780+
781+
#[inline]
782+
fn size_hint(&self) -> (usize, Option<usize>) {
783+
match &self.iter {
784+
CharIndicesEnum::Light { iter } => iter.size_hint(),
785+
CharIndicesEnum::Full {
786+
chunks,
787+
char_indices,
788+
chunk_index,
789+
} => {
790+
let Some(total) = chunks.last().map(|(s, l)| *l + s.len()) else {
791+
return (0, None);
792+
};
793+
794+
let (_, prev) = chunks[*chunk_index];
795+
// SAFETY: The previous length is guaranteed be less than or equal to the latter one.
796+
let remaining = total - prev;
797+
((remaining + 3) / 4 + char_indices.len(), Some(remaining))
798+
}
799+
}
800+
}
780801
}
781802

782803
impl Default for Rope<'_> {
@@ -1226,25 +1247,38 @@ mod tests {
12261247

12271248
#[test]
12281249
fn char_indices() {
1250+
// The algorithm is the same as the one used in `std::str::CharIndices::size_hint`.
1251+
macro_rules! lo {
1252+
($expr:expr) => {
1253+
($expr + 3) / 4
1254+
};
1255+
}
1256+
12291257
let mut a = Rope::new();
12301258
a.add("abc");
12311259
a.add("def");
12321260
assert_eq!(
12331261
a.char_indices().collect::<Vec<_>>(),
12341262
"abcdef".char_indices().collect::<Vec<_>>()
12351263
);
1264+
let len = "abcdef".char_indices().size_hint().1.unwrap();
1265+
assert_eq!(a.char_indices().size_hint(), (lo!(len), Some(len)));
12361266

12371267
let mut a = Rope::new();
12381268
a.add("こんにちは");
12391269
assert_eq!(
12401270
a.char_indices().collect::<Vec<_>>(),
12411271
"こんにちは".char_indices().collect::<Vec<_>>()
12421272
);
1273+
let len = "こんにちは".char_indices().size_hint().1.unwrap();
1274+
assert_eq!(a.char_indices().size_hint(), (lo!(len), Some(len)));
12431275
a.add("世界");
12441276
assert_eq!(
12451277
a.char_indices().collect::<Vec<_>>(),
12461278
"こんにちは世界".char_indices().collect::<Vec<_>>()
12471279
);
1280+
let len = "こんにちは世界".char_indices().size_hint().1.unwrap();
1281+
assert_eq!(a.char_indices().size_hint(), (lo!(len), Some(len)));
12481282
}
12491283

12501284
#[test]

0 commit comments

Comments
 (0)