Skip to content

Commit 0f202d2

Browse files
committed
Auto merge of rust-lang#96895 - SparrowLii:interval, r=Mark-Simulacrum
optimize `insert_range` method of `IntervalSet` This PR fixes the FIXME in the `insert_range` method that avoids recurse calculations when overlaping
2 parents a170f2b + eead168 commit 0f202d2

File tree

1 file changed

+45
-48
lines changed

1 file changed

+45
-48
lines changed

compiler/rustc_index/src/interval.rs

+45-48
Original file line numberDiff line numberDiff line change
@@ -70,67 +70,64 @@ impl<I: Idx> IntervalSet<I> {
7070
/// Returns true if we increased the number of elements present.
7171
pub fn insert_range(&mut self, range: impl RangeBounds<I> + Clone) -> bool {
7272
let start = inclusive_start(range.clone());
73-
let Some(mut end) = inclusive_end(self.domain, range) else {
73+
let Some(end) = inclusive_end(self.domain, range) else {
7474
// empty range
7575
return false;
7676
};
7777
if start > end {
7878
return false;
7979
}
8080

81-
loop {
82-
// This condition looks a bit weird, but actually makes sense.
83-
//
84-
// if r.0 == end + 1, then we're actually adjacent, so we want to
85-
// continue to the next range. We're looking here for the first
86-
// range which starts *non-adjacently* to our end.
87-
let next = self.map.partition_point(|r| r.0 <= end + 1);
88-
if let Some(last) = next.checked_sub(1) {
89-
let (prev_start, prev_end) = &mut self.map[last];
90-
if *prev_end + 1 >= start {
91-
// If the start for the inserted range is adjacent to the
92-
// end of the previous, we can extend the previous range.
93-
if start < *prev_start {
94-
// Our range starts before the one we found. We'll need
95-
// to *remove* it, and then try again.
96-
//
97-
// FIXME: This is not so efficient; we may need to
98-
// recurse a bunch of times here. Instead, it's probably
99-
// better to do something like drain_filter(...) on the
100-
// map to be able to delete or modify all the ranges in
101-
// start..=end and then potentially re-insert a new
102-
// range.
103-
end = std::cmp::max(end, *prev_end);
104-
self.map.remove(last);
105-
} else {
106-
// We overlap with the previous range, increase it to
107-
// include us.
108-
//
109-
// Make sure we're actually going to *increase* it though --
110-
// it may be that end is just inside the previously existing
111-
// set.
112-
return if end > *prev_end {
113-
*prev_end = end;
114-
true
115-
} else {
116-
false
117-
};
81+
// This condition looks a bit weird, but actually makes sense.
82+
//
83+
// if r.0 == end + 1, then we're actually adjacent, so we want to
84+
// continue to the next range. We're looking here for the first
85+
// range which starts *non-adjacently* to our end.
86+
let next = self.map.partition_point(|r| r.0 <= end + 1);
87+
if let Some(right) = next.checked_sub(1) {
88+
let (prev_start, prev_end) = self.map[right];
89+
if prev_end + 1 >= start {
90+
// If the start for the inserted range is adjacent to the
91+
// end of the previous, we can extend the previous range.
92+
if start < prev_start {
93+
// The first range which ends *non-adjacently* to our start.
94+
// And we can ensure that left <= right.
95+
let left = self.map.partition_point(|l| l.1 + 1 < start);
96+
let min = std::cmp::min(self.map[left].0, start);
97+
let max = std::cmp::max(prev_end, end);
98+
self.map[right] = (min, max);
99+
if left != right {
100+
self.map.drain(left..right);
118101
}
119-
} else {
120-
// Otherwise, we don't overlap, so just insert
121-
self.map.insert(last + 1, (start, end));
122102
return true;
123-
}
124-
} else {
125-
if self.map.is_empty() {
126-
// Quite common in practice, and expensive to call memcpy
127-
// with length zero.
128-
self.map.push((start, end));
129103
} else {
130-
self.map.insert(next, (start, end));
104+
// We overlap with the previous range, increase it to
105+
// include us.
106+
//
107+
// Make sure we're actually going to *increase* it though --
108+
// it may be that end is just inside the previously existing
109+
// set.
110+
return if end > prev_end {
111+
self.map[right].1 = end;
112+
true
113+
} else {
114+
false
115+
};
131116
}
117+
} else {
118+
// Otherwise, we don't overlap, so just insert
119+
self.map.insert(right + 1, (start, end));
132120
return true;
133121
}
122+
} else {
123+
if self.map.is_empty() {
124+
// Quite common in practice, and expensive to call memcpy
125+
// with length zero.
126+
self.map.push((start, end));
127+
} else {
128+
self.map.insert(next, (start, end));
129+
}
130+
return true;
134131
}
135132
}
136133

0 commit comments

Comments
 (0)