Skip to content

Commit ddd0d8c

Browse files
committed
Refactor add_interval_unchecked for less allocation.
1 parent 794ac5a commit ddd0d8c

File tree

1 file changed

+81
-14
lines changed

1 file changed

+81
-14
lines changed

src/lib.rs

Lines changed: 81 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -82,26 +82,93 @@ impl Gtid {
8282

8383
/// Add an interval but does not check assume interval is correctly formed
8484
fn add_interval_unchecked(&mut self, interval: &(u64, u64)) {
85-
let mut interval = *interval;
85+
let interval = *interval;
8686

87-
// TODO: Do it in place with a filter.
88-
let mut new: Vec<(u64, u64)> = Vec::with_capacity(self.intervals.len());
89-
for current in self.intervals.iter() {
90-
if interval.0 == current.1 {
91-
interval = (current.0, interval.1);
92-
continue;
87+
// self.intervals was empty
88+
if self.intervals.is_empty() {
89+
self.intervals.push(interval);
90+
return;
91+
}
92+
if let Some(&first) = self.intervals.first() {
93+
// if interval is strictly before intervals
94+
if interval.1 < first.0 {
95+
self.intervals.insert(0, interval);
96+
return;
9397
}
9498

95-
if interval.1 == current.0 {
96-
interval = (interval.0, current.1);
97-
continue;
99+
// if interval merge before interval
100+
if interval.1 == first.0 {
101+
// unwrapping is ok as intervals is not empty
102+
103+
let first = self.intervals.first_mut().unwrap();
104+
*first = (interval.0, first.1);
105+
return;
98106
}
99-
new.push(*current);
100107
}
101108

102-
new.push(interval);
103-
new.sort();
104-
self.intervals = new;
109+
if let Some(&last) = self.intervals.last() {
110+
if interval.0 > last.1 {
111+
self.intervals.push(interval);
112+
return;
113+
}
114+
115+
if interval.0 == last.1 {
116+
// unwrapping is ok as intervals is not empty
117+
118+
let last = self.intervals.last_mut().unwrap();
119+
*last = (last.0, interval.1);
120+
return;
121+
}
122+
}
123+
124+
match self
125+
.intervals
126+
.binary_search_by(|elem| elem.1.cmp(&interval.0))
127+
{
128+
Err(idx) => {
129+
// error case so it won't merge with previous
130+
// it may merge before the item currently at idx
131+
if idx == self.intervals.len() {
132+
// previously treated
133+
unreachable!()
134+
}
135+
// we can unwrap as the case interval is after the last element is treated before
136+
let next = self.intervals.get(idx).unwrap();
137+
// interval merges with next
138+
if next.0 == interval.1 {
139+
*self.intervals.get_mut(idx).unwrap() = (interval.0, next.1);
140+
} else {
141+
// just add interval, nothing to merge
142+
self.intervals.insert(idx, interval);
143+
}
144+
}
145+
Ok(idx) => {
146+
// ok case it will merge with current
147+
// it may merge with next
148+
149+
let before = self.intervals[idx];
150+
let after = self.intervals[idx + 1];
151+
152+
// interval merges with before and after
153+
if interval.0 == before.1 && interval.1 == after.0 {
154+
*self.intervals.get_mut(idx).unwrap() = (before.0, after.1);
155+
self.intervals.remove(idx + 1);
156+
} else if
157+
// interval merges with before
158+
interval.0 == before.1 {
159+
*self.intervals.get_mut(idx).unwrap() = (before.0, interval.1);
160+
} else if
161+
// interval merges with after
162+
interval.1 == after.0 {
163+
unreachable!("should have been treated in the error branch before");
164+
// *self.intervals.get_mut(idx + 1).unwrap() = (interval.0, after.1);
165+
} else {
166+
// interval does not merge
167+
unreachable!("should have been treated in the error branch before");
168+
// self.intervals.insert(idx + 1, interval)
169+
}
170+
}
171+
}
105172
}
106173

107174
/// Add a raw interval into the gtid.

0 commit comments

Comments
 (0)