Skip to content

Commit c4b718f

Browse files
committed
syntax: implement fast push in-place.
1 parent 371f790 commit c4b718f

File tree

1 file changed

+34
-4
lines changed

1 file changed

+34
-4
lines changed

regex-syntax/src/hir/interval.rs

+34-4
Original file line numberDiff line numberDiff line change
@@ -81,14 +81,44 @@ impl<I: Interval> IntervalSet<I> {
8181

8282
/// Add a new interval to this set.
8383
pub fn push(&mut self, interval: I) {
84-
// TODO: This could be faster. e.g., Push the interval such that
85-
// it preserves canonicalization.
86-
self.ranges.push(interval);
87-
self.canonicalize();
8884
// We don't know whether the new interval added here is considered
8985
// case folded, so we conservatively assume that the entire set is
9086
// no longer case folded if it was previously.
9187
self.folded = false;
88+
89+
if self.ranges.is_empty() {
90+
self.ranges.push(interval);
91+
return;
92+
}
93+
94+
// Find the first range that is not greater than the new interval.
95+
// This is the first range that could possibly be unioned with the
96+
// new interval.
97+
let mut drain_end = self.ranges.len();
98+
while drain_end > 0
99+
&& self.ranges[drain_end - 1].lower() > interval.upper()
100+
{
101+
drain_end -= 1;
102+
}
103+
104+
// Try to union the new interval with old intervals backwards.
105+
if drain_end > 0 && self.ranges[drain_end - 1].is_contiguous(&interval)
106+
{
107+
self.ranges[drain_end - 1] =
108+
self.ranges[drain_end - 1].union(&interval).unwrap();
109+
for i in 0..drain_end - 1 {
110+
if let Some(union) =
111+
self.ranges[drain_end - 1].union(&self.ranges[i])
112+
{
113+
self.ranges[drain_end - 1] = union;
114+
} else {
115+
self.ranges.drain(i + 1..drain_end - 1);
116+
break;
117+
}
118+
}
119+
} else {
120+
self.ranges.insert(drain_end, interval);
121+
}
92122
}
93123

94124
/// Return an iterator over all intervals in this set.

0 commit comments

Comments
 (0)