diff --git a/.jules/bolt.md b/.jules/bolt.md new file mode 100644 index 00000000..028c373f --- /dev/null +++ b/.jules/bolt.md @@ -0,0 +1,3 @@ +## 2025-02-15 - Fast text search +**Learning:** In terminal_search, for_each_char_match_start was extracting substring arrays which makes string comparison slower. +**Action:** Optimize string matching loops to quickly short circuit on first char difference. diff --git a/crates/forktty-ui-gtk/src/gtk_app/terminal_search.rs b/crates/forktty-ui-gtk/src/gtk_app/terminal_search.rs index aec7f6b1..90694aa2 100644 --- a/crates/forktty-ui-gtk/src/gtk_app/terminal_search.rs +++ b/crates/forktty-ui-gtk/src/gtk_app/terminal_search.rs @@ -74,11 +74,18 @@ fn for_each_char_match_start( if needle.is_empty() { return; } + let first_needle = needle[0]; let mut index = 0; while index + needle.len() <= haystack.len() { - let matched = haystack[index..index + needle.len()] + // Fast-path: short-circuit the full substring check if the first character + // doesn't match, avoiding iterator overhead in the common case. + if !chars_eq_ignore_case(haystack[index], first_needle) { + index += 1; + continue; + } + let matched = haystack[index + 1..index + needle.len()] .iter() - .zip(needle) + .zip(&needle[1..]) .all(|(a, b)| chars_eq_ignore_case(*a, *b)); if matched { if !visit(index) {