Improve codegen of line_offset_of_character_at_offset

This function is a hotspot, but it has inefficient codegen:

1. For whatever reason, the chars() iterator of wstr is slower
   than that of a slice. Use the slice.

2. Unnecessary overflow checks were preventing vectorization.

Switch to a more optimized implementation.

This improves aliases benchmark time by about 9%.
This commit is contained in:
ridiculousfish
2024-01-13 17:06:35 -08:00
parent e8ebeedfca
commit 4ea222cd34
2 changed files with 28 additions and 9 deletions

View File

@@ -8,6 +8,20 @@
use crate::wchar::{decode_byte_from_char, prelude::*};
use crate::wutil::encoding::{wcrtomb, zero_mbstate, AT_LEAST_MB_LEN_MAX};
/// Return the number of newlines in a string.
pub fn count_newlines(s: &wstr) -> usize {
// This is a performance-sensitive function.
// The native filter().count() produces sub-optimal codegen because of overflow checks,
// which we currently enable in release mode. Implement it more efficiently.
let mut count: usize = 0;
for c in s.as_char_slice() {
if *c == '\n' {
count = count.wrapping_add(1);
}
}
count
}
/// Test if a string prefixes another without regard to case. Returns true if a is a prefix of b.
pub fn string_prefixes_string_case_insensitive(proposed_prefix: &wstr, value: &wstr) -> bool {
let prefix_size = proposed_prefix.len();
@@ -643,3 +657,13 @@ fn test_line_iterator() {
]
);
}
#[test]
fn test_count_newlines() {
assert_eq!(count_newlines(L!("")), 0);
assert_eq!(count_newlines(L!("foo")), 0);
assert_eq!(count_newlines(L!("foo\nbar")), 1);
assert_eq!(count_newlines(L!("foo\nbar\nbaz")), 2);
assert_eq!(count_newlines(L!("\n")), 1);
assert_eq!(count_newlines(L!("\n\n")), 2);
}