-
Notifications
You must be signed in to change notification settings - Fork 0
⚡ Bolt: [performance improvement] Hoist ASCII bounds in terminal search #404
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,4 @@ | ||
|
|
||
| ## 2024-05-18 - Hoist ASCII bounds in case-insensitive search loop | ||
| **Learning:** Function calls in the innermost hot loops (even with small fast-paths) are costly. Hoisting the lower/upper checks out of the loop using a fast path condition gives an enormous boost (3x) for non-matching occurrences. | ||
| **Action:** Precalculate ASCII bounds before the main search loop to avoid function overhead when rejecting mismatched characters. | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -76,24 +76,54 @@ fn for_each_char_match_start( | |
| } | ||
| let first_needle = needle[0]; | ||
| let mut index = 0; | ||
| while index + needle.len() <= haystack.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; | ||
|
|
||
| // Fast-path: short-circuit the full substring check if the first character | ||
| // doesn't match, avoiding iterator and function call overhead in the common case. | ||
| if first_needle.is_ascii() { | ||
| let first_lower = first_needle.to_ascii_lowercase(); | ||
| let first_upper = first_needle.to_ascii_uppercase(); | ||
|
|
||
| while index + needle.len() <= haystack.len() { | ||
| let h = haystack[index]; | ||
| if h != first_lower && h != first_upper { | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
When an ASCII query starts with a character that has a non-ASCII lowercase equivalent—for example, query Useful? React with 👍 / 👎. |
||
| index += 1; | ||
| continue; | ||
| } | ||
|
|
||
| let matched = haystack[index + 1..index + needle.len()] | ||
| .iter() | ||
| .zip(&needle[1..]) | ||
| .all(|(a, b)| chars_eq_ignore_case(*a, *b)); | ||
|
|
||
| if matched { | ||
| if !visit(index) { | ||
| return; | ||
| } | ||
| index += needle.len(); | ||
| } else { | ||
| index += 1; | ||
| } | ||
| } | ||
| let matched = haystack[index + 1..index + needle.len()] | ||
| .iter() | ||
| .zip(&needle[1..]) | ||
| .all(|(a, b)| chars_eq_ignore_case(*a, *b)); | ||
| if matched { | ||
| if !visit(index) { | ||
| return; | ||
| } else { | ||
| while index + needle.len() <= haystack.len() { | ||
| if !chars_eq_ignore_case(haystack[index], first_needle) { | ||
| index += 1; | ||
| continue; | ||
| } | ||
|
|
||
| let matched = haystack[index + 1..index + needle.len()] | ||
| .iter() | ||
| .zip(&needle[1..]) | ||
| .all(|(a, b)| chars_eq_ignore_case(*a, *b)); | ||
|
|
||
| if matched { | ||
| if !visit(index) { | ||
| return; | ||
| } | ||
| index += needle.len(); | ||
| } else { | ||
| index += 1; | ||
| } | ||
| index += needle.len(); | ||
| } else { | ||
| index += 1; | ||
| } | ||
| } | ||
| } | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a user-visible terminal-search performance change—the added note claims a 3x improvement—but it is recorded only in a Jules-specific file, leaving it absent from release notes. Add an entry under
CHANGELOG.md'sUnreleasedsection as required for every user-visible change.AGENTS.md reference: AGENTS.md:L183-L183
Useful? React with 👍 / 👎.