Avoid allocation in LineWrapper::wrap_line

Co-Authored-By: Nathan Sobo <nathan@zed.dev>
This commit is contained in:
Max Brunsfeld
2021-07-30 09:50:28 -07:00
co-authored by Nathan Sobo
parent 59bb6624e2
commit 2dcf04cfb9
+38 -29
View File
@@ -36,37 +36,42 @@ impl LineWrapper {
.wrap_line(line, self.font_id, self.font_size, wrap_width)
}
pub fn wrap_line(&self, line: &str, wrap_width: f32) -> Vec<usize> {
pub fn wrap_line<'a>(
&'a self,
line: &'a str,
wrap_width: f32,
) -> impl Iterator<Item = usize> + 'a {
let mut width = 0.0;
let mut boundaries = Vec::new();
let mut last_boundary_ix = 0;
let mut last_boundary_width = 0.0;
let mut last_candidate_ix = 0;
let mut last_candidate_width = 0.0;
let mut last_wrap_ix = 0;
let mut prev_c = '\0';
for (ix, c) in line.char_indices() {
if c == '\n' {
break;
}
if self.is_boundary(prev_c, c) {
last_boundary_ix = ix;
last_boundary_width = width;
}
let char_width = self.width_for_char(c);
width += char_width;
if width > wrap_width && ix > *boundaries.last().unwrap_or(&0) {
if last_boundary_ix > 0 {
boundaries.push(last_boundary_ix);
width -= last_boundary_width;
last_boundary_ix = 0;
} else {
boundaries.push(ix);
width = char_width;
let char_indices = line.char_indices();
char_indices.filter_map(move |(ix, c)| {
if c != '\n' {
if self.is_boundary(prev_c, c) {
last_candidate_ix = ix;
last_candidate_width = width;
}
let char_width = self.width_for_char(c);
width += char_width;
if width > wrap_width && ix > last_wrap_ix {
if last_candidate_ix > 0 {
last_wrap_ix = last_candidate_ix;
width -= last_candidate_width;
last_candidate_ix = 0;
} else {
last_wrap_ix = ix;
width = char_width;
}
return Some(last_wrap_ix);
}
prev_c = c;
}
prev_c = c;
}
boundaries
None
})
}
fn is_boundary(&self, prev: char, next: char) -> bool {
@@ -132,7 +137,9 @@ mod tests {
&[7, 12, 18],
);
assert_eq!(
wrapper.wrap_line("aa bbb cccc ddddd eeee", 72.0),
wrapper
.wrap_line("aa bbb cccc ddddd eeee", 72.0)
.collect::<Vec<_>>(),
&[7, 12, 18],
);
@@ -141,7 +148,9 @@ mod tests {
&[4, 11, 18],
);
assert_eq!(
wrapper.wrap_line("aaa aaaaaaaaaaaaaaaaaa", 72.0),
wrapper
.wrap_line("aaa aaaaaaaaaaaaaaaaaa", 72.0)
.collect::<Vec<_>>(),
&[4, 11, 18],
);
}