optimize insert_range
method of IntervalSet
This commit is contained in:
parent
4799baa70d
commit
eead168dd7
@ -70,7 +70,7 @@ pub fn insert(&mut self, point: I) -> bool {
|
|||||||
/// Returns true if we increased the number of elements present.
|
/// Returns true if we increased the number of elements present.
|
||||||
pub fn insert_range(&mut self, range: impl RangeBounds<I> + Clone) -> bool {
|
pub fn insert_range(&mut self, range: impl RangeBounds<I> + Clone) -> bool {
|
||||||
let start = inclusive_start(range.clone());
|
let start = inclusive_start(range.clone());
|
||||||
let Some(mut end) = inclusive_end(self.domain, range) else {
|
let Some(end) = inclusive_end(self.domain, range) else {
|
||||||
// empty range
|
// empty range
|
||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
@ -78,59 +78,56 @@ pub fn insert_range(&mut self, range: impl RangeBounds<I> + Clone) -> bool {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
loop {
|
// This condition looks a bit weird, but actually makes sense.
|
||||||
// This condition looks a bit weird, but actually makes sense.
|
//
|
||||||
//
|
// if r.0 == end + 1, then we're actually adjacent, so we want to
|
||||||
// if r.0 == end + 1, then we're actually adjacent, so we want to
|
// continue to the next range. We're looking here for the first
|
||||||
// continue to the next range. We're looking here for the first
|
// range which starts *non-adjacently* to our end.
|
||||||
// range which starts *non-adjacently* to our end.
|
let next = self.map.partition_point(|r| r.0 <= end + 1);
|
||||||
let next = self.map.partition_point(|r| r.0 <= end + 1);
|
if let Some(right) = next.checked_sub(1) {
|
||||||
if let Some(last) = next.checked_sub(1) {
|
let (prev_start, prev_end) = self.map[right];
|
||||||
let (prev_start, prev_end) = &mut self.map[last];
|
if prev_end + 1 >= start {
|
||||||
if *prev_end + 1 >= start {
|
// If the start for the inserted range is adjacent to the
|
||||||
// If the start for the inserted range is adjacent to the
|
// end of the previous, we can extend the previous range.
|
||||||
// end of the previous, we can extend the previous range.
|
if start < prev_start {
|
||||||
if start < *prev_start {
|
// The first range which ends *non-adjacently* to our start.
|
||||||
// Our range starts before the one we found. We'll need
|
// And we can ensure that left <= right.
|
||||||
// to *remove* it, and then try again.
|
let left = self.map.partition_point(|l| l.1 + 1 < start);
|
||||||
//
|
let min = std::cmp::min(self.map[left].0, start);
|
||||||
// FIXME: This is not so efficient; we may need to
|
let max = std::cmp::max(prev_end, end);
|
||||||
// recurse a bunch of times here. Instead, it's probably
|
self.map[right] = (min, max);
|
||||||
// better to do something like drain_filter(...) on the
|
if left != right {
|
||||||
// map to be able to delete or modify all the ranges in
|
self.map.drain(left..right);
|
||||||
// start..=end and then potentially re-insert a new
|
|
||||||
// range.
|
|
||||||
end = std::cmp::max(end, *prev_end);
|
|
||||||
self.map.remove(last);
|
|
||||||
} else {
|
|
||||||
// We overlap with the previous range, increase it to
|
|
||||||
// include us.
|
|
||||||
//
|
|
||||||
// Make sure we're actually going to *increase* it though --
|
|
||||||
// it may be that end is just inside the previously existing
|
|
||||||
// set.
|
|
||||||
return if end > *prev_end {
|
|
||||||
*prev_end = end;
|
|
||||||
true
|
|
||||||
} else {
|
|
||||||
false
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
// Otherwise, we don't overlap, so just insert
|
|
||||||
self.map.insert(last + 1, (start, end));
|
|
||||||
return true;
|
return true;
|
||||||
|
} else {
|
||||||
|
// We overlap with the previous range, increase it to
|
||||||
|
// include us.
|
||||||
|
//
|
||||||
|
// Make sure we're actually going to *increase* it though --
|
||||||
|
// it may be that end is just inside the previously existing
|
||||||
|
// set.
|
||||||
|
return if end > prev_end {
|
||||||
|
self.map[right].1 = end;
|
||||||
|
true
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
};
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if self.map.is_empty() {
|
// Otherwise, we don't overlap, so just insert
|
||||||
// Quite common in practice, and expensive to call memcpy
|
self.map.insert(right + 1, (start, end));
|
||||||
// with length zero.
|
|
||||||
self.map.push((start, end));
|
|
||||||
} else {
|
|
||||||
self.map.insert(next, (start, end));
|
|
||||||
}
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
if self.map.is_empty() {
|
||||||
|
// Quite common in practice, and expensive to call memcpy
|
||||||
|
// with length zero.
|
||||||
|
self.map.push((start, end));
|
||||||
|
} else {
|
||||||
|
self.map.insert(next, (start, end));
|
||||||
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user