editor: Optimize selection overlap checking with binary search (#39773)
Xiaobo Liu
created 3 weeks ago
Replace O(n²) linear search with O(log n) binary search for checking
selection overlaps when finding next selection range. Pre-sort selection
ranges and use binary search to significantly improve performance when
working with many selections.
Release Notes:
- N/A
---------
Signed-off-by: Xiaobo Liu <cppcoffee@gmail.com>
Change summary
crates/editor/src/editor.rs | 23 ++++++++++++++++++-----
1 file changed, 18 insertions(+), 5 deletions(-)
Detailed changes
@@ -14448,6 +14448,10 @@ impl Editor {
let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
let mut next_selected_range = None;
+ // Collect and sort selection ranges for efficient overlap checking
+ let mut selection_ranges: Vec<_> = selections.iter().map(|s| s.range()).collect();
+ selection_ranges.sort_by_key(|r| r.start);
+
let bytes_after_last_selection =
buffer.bytes_in_range(last_selection.end..buffer.len());
let bytes_before_first_selection = buffer.bytes_in_range(0..first_selection.start);
@@ -14469,11 +14473,20 @@ impl Editor {
|| (!buffer.is_inside_word(offset_range.start, None)
&& !buffer.is_inside_word(offset_range.end, None))
{
- // TODO: This is n^2, because we might check all the selections
- if !selections
- .iter()
- .any(|selection| selection.range().overlaps(&offset_range))
- {
+ // Use binary search to check for overlap (O(log n))
+ let overlaps = selection_ranges
+ .binary_search_by(|range| {
+ if range.end <= offset_range.start {
+ std::cmp::Ordering::Less
+ } else if range.start >= offset_range.end {
+ std::cmp::Ordering::Greater
+ } else {
+ std::cmp::Ordering::Equal
+ }
+ })
+ .is_ok();
+
+ if !overlaps {
next_selected_range = Some(offset_range);
break;
}