1use serde::{Deserialize, Serialize};
11
12#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
18#[serde(from = "Vec<[u64; 2]>", into = "Vec<[u64; 2]>")]
19pub struct SeqSet {
20 runs: Vec<[u64; 2]>,
21}
22
23impl SeqSet {
24 #[must_use]
26 pub fn new() -> Self { Self::default() }
27
28 #[must_use]
30 pub fn range(start: u64, end: u64) -> Self {
31 let mut set = Self::new();
32 set.insert_range(start, end);
33 set
34 }
35
36 pub fn insert(&mut self, seq: u64) -> bool { self.insert_range(seq, seq.saturating_add(1)) > 0 }
40
41 pub fn insert_range(&mut self, start: u64, end: u64) -> u64 {
43 if start >= end {
44 return 0;
45 }
46 let low = self.runs.partition_point(|run| run[1] < start);
50 let high = self.runs.partition_point(|run| run[0] <= end);
51 let overlapping = self.runs.get(low..high).unwrap_or_default();
52 let already: u64 = overlapping
53 .iter()
54 .map(|run| run[1].min(end).saturating_sub(run[0].max(start)))
55 .sum();
56 let merged = match overlapping {
57 [first, .., last] => [first[0].min(start), last[1].max(end)],
58 [only] => [only[0].min(start), only[1].max(end)],
59 [] => [start, end],
60 };
61 self.runs.splice(low..high, [merged]);
62 (end - start) - already
63 }
64
65 pub fn remove(&mut self, seq: u64) -> bool {
67 let index = self.runs.partition_point(|run| run[1] <= seq);
68 let Some(run) = self.runs.get(index).copied() else {
69 return false;
70 };
71 if seq < run[0] {
72 return false;
73 }
74 let pieces = [[run[0], seq], [seq + 1, run[1]]];
75 self.runs.splice(
76 index..=index,
77 pieces.into_iter().filter(|piece| piece[0] < piece[1]),
78 );
79 true
80 }
81
82 #[must_use]
84 pub fn contains(&self, seq: u64) -> bool {
85 let index = self.runs.partition_point(|run| run[1] <= seq);
86 self.runs.get(index).is_some_and(|run| run[0] <= seq)
87 }
88
89 #[must_use]
91 pub fn len(&self) -> u64 { self.runs.iter().map(|run| run[1] - run[0]).sum() }
92
93 #[must_use]
95 pub fn is_empty(&self) -> bool { self.runs.is_empty() }
96
97 #[must_use]
99 pub fn last(&self) -> Option<u64> { self.runs.last().map(|run| run[1] - 1) }
100
101 pub fn iter(&self) -> impl DoubleEndedIterator<Item = u64> + '_ {
104 self.runs.iter().flat_map(|run| run[0]..run[1])
105 }
106
107 #[must_use]
111 pub fn union(&self, other: &Self) -> Self {
112 let mut out = Self::new();
113 let (mut left, mut right) = (self.runs.iter().peekable(), other.runs.iter().peekable());
114 loop {
115 let next = match (left.peek(), right.peek()) {
116 (Some(a), Some(b)) if a[0] <= b[0] => left.next(),
117 (_, Some(_)) => right.next(),
118 (Some(_), None) => left.next(),
119 (None, None) => break,
120 };
121 if let Some(&run) = next {
122 out.push_run(run);
123 }
124 }
125 out
126 }
127
128 #[must_use]
134 pub fn union_all<'a>(sets: impl IntoIterator<Item = &'a Self>) -> Self {
135 sets.into_iter()
136 .flat_map(|set| set.runs.iter().copied())
137 .collect::<Vec<_>>()
138 .into()
139 }
140
141 #[must_use]
145 pub fn difference(&self, other: &Self) -> Self {
146 let mut out = Self::new();
147 let mut first = 0;
153 for &[start, end] in &self.runs {
154 while other.runs.get(first).is_some_and(|cut| cut[1] <= start) {
155 first += 1;
156 }
157 let mut cursor = start;
158 for cut in other.runs.iter().skip(first).take_while(|cut| cut[0] < end) {
159 if cut[0] > cursor {
160 out.push_run([cursor, cut[0]]);
161 }
162 cursor = cursor.max(cut[1]);
163 }
164 if cursor < end {
165 out.push_run([cursor, end]);
166 }
167 }
168 out
169 }
170
171 #[must_use]
176 pub fn intersection(&self, other: &Self) -> Self {
177 let mut out = Self::new();
178 let (mut left, mut right) = (0, 0);
179 while let (Some(a), Some(b)) = (self.runs.get(left), other.runs.get(right)) {
180 let overlap = [a[0].max(b[0]), a[1].min(b[1])];
181 if overlap[0] < overlap[1] {
182 out.push_run(overlap);
183 }
184 if a[1] <= b[0] {
190 left += self
191 .runs
192 .get(left..)
193 .map_or(0, |rest| rest.partition_point(|run| run[1] <= b[0]));
194 } else if b[1] <= a[0] {
195 right += other
196 .runs
197 .get(right..)
198 .map_or(0, |rest| rest.partition_point(|run| run[1] <= a[0]));
199 } else if a[1] <= b[1] {
200 left += 1;
201 } else {
202 right += 1;
203 }
204 }
205 out
206 }
207
208 fn push_run(&mut self, run: [u64; 2]) {
214 if run[0] >= run[1] {
215 return;
216 }
217 match self.runs.last_mut() {
218 Some(last) if run[0] <= last[1] => last[1] = last[1].max(run[1]),
219 _ => self.runs.push(run),
220 }
221 }
222
223 #[must_use]
226 pub fn sample(&self, count: usize) -> Vec<u64> { self.iter().take(count).collect() }
227}
228
229impl From<Vec<[u64; 2]>> for SeqSet {
232 fn from(mut runs: Vec<[u64; 2]>) -> Self {
233 runs.sort_unstable();
234 let mut set = Self::new();
235 for run in runs {
236 set.push_run(run);
237 }
238 set
239 }
240}
241
242impl From<SeqSet> for Vec<[u64; 2]> {
243 fn from(set: SeqSet) -> Self { set.runs }
244}
245
246impl FromIterator<u64> for SeqSet {
247 fn from_iter<I: IntoIterator<Item = u64>>(iter: I) -> Self {
248 let mut set = Self::new();
249 for seq in iter {
250 set.insert(seq);
251 }
252 set
253 }
254}
255
256#[cfg(test)]
257mod tests {
258 use {
259 super::SeqSet,
260 assert2::{assert, check},
261 std::collections::BTreeSet,
262 };
263
264 fn members(set: &SeqSet) -> BTreeSet<u64> { set.iter().collect() }
267
268 fn runs(list: &[[u64; 2]]) -> SeqSet { SeqSet::from(list.to_vec()) }
269
270 #[yare::parameterized(
271 ascending = { &[0, 1, 2, 3], &[[0, 4]] },
272 descending = { &[3, 2, 1, 0], &[[0, 4]] },
273 gap_then_fill = { &[0, 2, 1], &[[0, 3]] },
274 two_runs = { &[0, 1, 5, 6], &[[0, 2], [5, 7]] },
275 interleaved = { &[10, 0, 11, 1, 12], &[[0, 2], [10, 13]] },
276 repeats = { &[4, 4, 4], &[[4, 5]] },
277 )]
278 fn inserts_merge_into_canonical_runs(inserted: &[u64], runs: &[[u64; 2]]) {
279 let set: SeqSet = inserted.iter().copied().collect();
280 check!(set.runs == runs);
281 }
282
283 #[test]
284 fn insert_reports_whether_a_member_was_new() {
285 let mut set = SeqSet::new();
286 check!(set.insert(7));
287 check!(!set.insert(7));
288 check!(set.insert(8));
289 check!(set.insert_range(0, 10) == 8);
290 check!(set.insert_range(5, 5) == 0);
291 check!(set.len() == 10);
292 }
293
294 #[yare::parameterized(
295 middle = { 5, true, &[[0, 5], [6, 10]] },
296 first = { 0, true, &[[1, 10]] },
297 last = { 9, true, &[[0, 9]] },
298 absent = { 12, false, &[[0, 10]] },
299 )]
300 fn remove_splits_a_run(seq: u64, was_member: bool, runs: &[[u64; 2]]) {
301 let mut set = SeqSet::range(0, 10);
302 check!(set.remove(seq) == was_member);
303 check!(set.runs == runs);
304 check!(!set.contains(seq));
305 }
306
307 #[yare::parameterized(
308 disjoint = { SeqSet::range(0, 5), SeqSet::range(10, 15), SeqSet::range(0, 5) },
309 covering = { SeqSet::range(0, 5), SeqSet::range(0, 10), SeqSet::new() },
310 hole = { SeqSet::range(0, 10), [4, 5].into_iter().collect(), [0, 1, 2, 3, 6, 7, 8, 9].into_iter().collect() },
311 overlapping_tail = { SeqSet::range(0, 10), SeqSet::range(8, 20), SeqSet::range(0, 8) },
312 )]
313 fn difference_keeps_only_the_left_side(left: SeqSet, right: SeqSet, expected: SeqSet) {
314 check!(left.difference(&right) == expected);
315 }
316
317 #[test]
318 fn union_and_intersection_agree_with_membership() {
319 let left: SeqSet = [1, 2, 3, 10].into_iter().collect();
320 let right: SeqSet = [3, 4, 10, 11].into_iter().collect();
321 check!(left.union(&right) == [1, 2, 3, 4, 10, 11].into_iter().collect());
322 check!(left.intersection(&right) == [3, 10].into_iter().collect());
323 }
324
325 #[test]
326 fn the_json_form_is_the_run_list() {
327 let set: SeqSet = [0, 1, 2, 9].into_iter().collect();
328 let json = serde_json::to_string(&set).unwrap();
329 assert!(json == "[[0,3],[9,10]]");
330 check!(serde_json::from_str::<SeqSet>(&json).unwrap() == set);
331 check!(set.last() == Some(9));
332 check!(set.sample(2) == vec![0, 1]);
333 }
334
335 #[test]
336 fn a_non_canonical_run_list_reads_back_canonical() {
337 let set: SeqSet = serde_json::from_str("[[5,8],[0,2],[2,5],[7,9]]").unwrap();
338 check!(set == SeqSet::range(0, 9));
339 }
340
341 #[yare::parameterized(
342 both_empty = { &[], &[] },
343 left_empty = { &[], &[[3, 8]] },
344 right_empty = { &[[3, 8]], &[] },
345 equal = { &[[3, 8], [10, 12]], &[[3, 8], [10, 12]] },
346 disjoint = { &[[0, 5]], &[[10, 15]] },
347 touching = { &[[0, 5]], &[[5, 10]] },
348 touching_both_sides = { &[[0, 5], [10, 15]], &[[5, 10]] },
349 overlapping = { &[[0, 8]], &[[5, 12]] },
350 nested = { &[[0, 20]], &[[5, 8], [10, 12]] },
351 nested_reversed = { &[[5, 8], [10, 12]], &[[0, 20]] },
352 cut_spans_two_runs = { &[[0, 4], [6, 10], [12, 14]], &[[2, 13]] },
353 many_runs_interleaved = { &[[0, 2], [4, 6], [8, 10], [12, 14], [16, 18]], &[[1, 5], [7, 8], [9, 13], [17, 30]] },
354 single_members = { &[[0, 1], [2, 3], [4, 5]], &[[1, 2], [3, 4], [5, 6]] },
355 far_apart = { &[[0, 1], [u64::MAX - 2, u64::MAX]], &[[1, 2], [u64::MAX - 1, u64::MAX]] },
356 )]
357 fn set_operations_match_a_member_by_member_model(left: &[[u64; 2]], right: &[[u64; 2]]) {
358 let (left, right) = (runs(left), runs(right));
359 let (model_left, model_right) = (members(&left), members(&right));
360 for (name, got, expected) in [
361 ("union", left.union(&right), &model_left | &model_right),
362 (
363 "difference",
364 left.difference(&right),
365 &model_left - &model_right,
366 ),
367 (
368 "intersection",
369 left.intersection(&right),
370 &model_left & &model_right,
371 ),
372 (
373 "union_all",
374 SeqSet::union_all([&left, &right]),
375 &model_left | &model_right,
376 ),
377 ] {
378 check!(members(&got) == expected, "{name}");
379 check!(
381 got == expected.iter().copied().collect::<SeqSet>(),
382 "{name}"
383 );
384 }
385 }
386
387 #[test]
391 fn set_operations_stay_linear_on_many_runs() {
392 const RUNS: u64 = 200_000;
393 let left = SeqSet::from((0..RUNS).map(|n| [4 * n, 4 * n + 2]).collect::<Vec<_>>());
394 let right = SeqSet::from(
395 (0..RUNS)
396 .map(|n| [4 * n + 1, 4 * n + 3])
397 .collect::<Vec<_>>(),
398 );
399 check!(
400 left.union(&right)
401 == SeqSet::from((0..RUNS).map(|n| [4 * n, 4 * n + 3]).collect::<Vec<_>>())
402 );
403 check!(left.union(&right).len() == 3 * RUNS);
404 check!(left.difference(&right).len() == RUNS);
405 check!(left.intersection(&right).len() == RUNS);
406 let many: Vec<SeqSet> = (0..RUNS).map(|n| SeqSet::range(2 * n, 2 * n + 1)).collect();
407 check!(SeqSet::union_all(&many).len() == RUNS);
408 }
409
410 #[test]
411 fn iter_walks_down_from_the_largest_member_in_reverse() {
412 let set = runs(&[[0, 2], [5, 7]]);
413 check!(set.iter().rev().collect::<Vec<_>>() == [6, 5, 1, 0]);
414 }
415}