@@ -11,6 +11,10 @@ use smallvec::SmallVec;
11
11
mod tests;
12
12
13
13
/// Stores a set of intervals on the indices.
14
+ ///
15
+ /// The elements in `map` are sorted and non-adjacent, which means
16
+ /// the second value of the previous element is *greater* than the
17
+ /// first value of the following element.
14
18
#[derive(Debug, Clone)]
15
19
pub struct IntervalSet<I> {
16
20
// Start, end
@@ -84,7 +88,7 @@ impl<I: Idx> IntervalSet<I> {
84
88
// continue to the next range. We're looking here for the first
85
89
// range which starts *non-adjacently* to our end.
86
90
let next = self.map.partition_point(|r| r.0 <= end + 1);
87
- if let Some(right) = next.checked_sub(1) {
91
+ let result = if let Some(right) = next.checked_sub(1) {
88
92
let (prev_start, prev_end) = self.map[right];
89
93
if prev_end + 1 >= start {
90
94
// If the start for the inserted range is adjacent to the
@@ -99,25 +103,25 @@ impl<I: Idx> IntervalSet<I> {
99
103
if left != right {
100
104
self.map.drain(left..right);
101
105
}
102
- return true;
106
+ true
103
107
} else {
104
108
// We overlap with the previous range, increase it to
105
109
// include us.
106
110
//
107
111
// Make sure we're actually going to *increase* it though --
108
112
// it may be that end is just inside the previously existing
109
113
// set.
110
- return if end > prev_end {
114
+ if end > prev_end {
111
115
self.map[right].1 = end;
112
116
true
113
117
} else {
114
118
false
115
- };
119
+ }
116
120
}
117
121
} else {
118
122
// Otherwise, we don't overlap, so just insert
119
123
self.map.insert(right + 1, (start, end));
120
- return true;
124
+ true
121
125
}
122
126
} else {
123
127
if self.map.is_empty() {
@@ -127,8 +131,16 @@ impl<I: Idx> IntervalSet<I> {
127
131
} else {
128
132
self.map.insert(next, (start, end));
129
133
}
130
- return true;
131
- }
134
+ true
135
+ };
136
+ debug_assert!(
137
+ self.check_invariants(),
138
+ "wrong intervals after insert {:?}..={:?} to {:?}",
139
+ start,
140
+ end,
141
+ self
142
+ );
143
+ result
132
144
}
133
145
134
146
pub fn contains(&self, needle: I) -> bool {
@@ -192,6 +204,7 @@ impl<I: Idx> IntervalSet<I> {
192
204
pub fn insert_all(&mut self) {
193
205
self.clear();
194
206
self.map.push((0, self.domain.try_into().unwrap()));
207
+ debug_assert!(self.check_invariants());
195
208
}
196
209
197
210
pub fn union(&mut self, other: &IntervalSet<I>) -> bool
@@ -203,8 +216,21 @@ impl<I: Idx> IntervalSet<I> {
203
216
for range in other.iter_intervals() {
204
217
did_insert |= self.insert_range(range);
205
218
}
219
+ debug_assert!(self.check_invariants());
206
220
did_insert
207
221
}
222
+
223
+ // Check the intervals are valid, sorted and non-adjacent
224
+ fn check_invariants(&self) -> bool {
225
+ let mut current: Option<u32> = None;
226
+ for (start, end) in &self.map {
227
+ if start > end || current.map_or(false, |x| x + 1 >= *start) {
228
+ return false;
229
+ }
230
+ current = Some(*end);
231
+ }
232
+ current.map_or(true, |x| x < self.domain as u32)
233
+ }
208
234
}
209
235
210
236
/// This data structure optimizes for cases where the stored bits in each row
0 commit comments