Speed up get_case_fold() 5x

Using `c.is_uppercase()` instead of getting the iterator and checking if the
first (and only) lowercase letter of the sequence is the same as the original
input is 5-8x faster (measured via criterion against `/usr/share/dict/words`).

(Additional benefit of forcibly inlining the now iterator-based comparison not
taken into account; this necessitated changing from a closure to a local
function as the inline attribute on closures is not yet supported with the
stable compiler toolchain.)
This commit is contained in:
Mahmoud Al-Qudsi 2024-11-22 15:33:13 -06:00
parent b949497bc1
commit 8c8da78cf8

View File

@ -175,14 +175,14 @@ impl StringFuzzyMatch {
) -> Option<StringFuzzyMatch> { ) -> Option<StringFuzzyMatch> {
// Helper to lazily compute if case insensitive matches should use icase or smartcase. // Helper to lazily compute if case insensitive matches should use icase or smartcase.
// Use icase if the input contains any uppercase characters, smartcase otherwise. // Use icase if the input contains any uppercase characters, smartcase otherwise.
let get_case_fold = || { #[inline(always)]
for c in string.chars() { fn get_case_fold(s: &widestring::Utf32Str) -> CaseSensitivity {
if c.to_lowercase().next().unwrap() != c { if s.chars().any(|c| c.is_uppercase()) {
return CaseSensitivity::Insensitive; CaseSensitivity::Insensitive
} } else {
CaseSensitivity::Smart
} }
CaseSensitivity::Smart }
};
// A string cannot fuzzy match against a shorter string. // A string cannot fuzzy match against a shorter string.
if string.len() > match_against.len() { if string.len() > match_against.len() {
@ -207,12 +207,18 @@ impl StringFuzzyMatch {
// exact icase // exact icase
if wcscasecmp(string, match_against).is_eq() { if wcscasecmp(string, match_against).is_eq() {
return Some(StringFuzzyMatch::new(ContainType::Exact, get_case_fold())); return Some(StringFuzzyMatch::new(
ContainType::Exact,
get_case_fold(string),
));
} }
// prefix icase // prefix icase
if string_prefixes_string_case_insensitive(string, match_against) { if string_prefixes_string_case_insensitive(string, match_against) {
return Some(StringFuzzyMatch::new(ContainType::Prefix, get_case_fold())); return Some(StringFuzzyMatch::new(
ContainType::Prefix,
get_case_fold(string),
));
} }
// If anchor_start is set, this is as far as we go. // If anchor_start is set, this is as far as we go.
@ -234,7 +240,10 @@ impl StringFuzzyMatch {
// substr icase // substr icase
if ifind(match_against, string, true /* fuzzy */).is_some() { if ifind(match_against, string, true /* fuzzy */).is_some() {
return Some(StringFuzzyMatch::new(ContainType::Substr, get_case_fold())); return Some(StringFuzzyMatch::new(
ContainType::Substr,
get_case_fold(string),
));
} }
// subseq samecase // subseq samecase