1#[derive(Clone, Debug, Default, PartialEq, Eq)]
10pub struct IntSet {
11 iv: Vec<(i128, i128)>,
12}
13
14impl IntSet {
15 pub fn new() -> Self {
16 IntSet { iv: Vec::new() }
17 }
18
19 pub fn from_intervals(items: impl IntoIterator<Item = (i128, i128)>) -> Self {
22 let mut v: Vec<(i128, i128)> = items.into_iter().filter(|&(lo, hi)| lo <= hi).collect();
23 v.sort_unstable();
24 let mut out: Vec<(i128, i128)> = Vec::with_capacity(v.len());
25 for (lo, hi) in v {
26 match out.last_mut() {
27 Some(last) if lo <= last.1.saturating_add(1) => {
28 if hi > last.1 {
29 last.1 = hi;
30 }
31 }
32 _ => out.push((lo, hi)),
33 }
34 }
35 IntSet { iv: out }
36 }
37
38 pub fn intervals(&self) -> &[(i128, i128)] {
39 &self.iv
40 }
41
42 pub fn is_empty(&self) -> bool {
43 self.iv.is_empty()
44 }
45
46 pub fn contains(&self, v: i128) -> bool {
47 match self.iv.binary_search_by(|&(lo, _)| lo.cmp(&v)) {
48 Ok(_) => true,
49 Err(0) => false,
50 Err(i) => self.iv[i - 1].1 >= v,
51 }
52 }
53
54 pub fn count(&self) -> u128 {
56 self.iv
57 .iter()
58 .map(|&(lo, hi)| (hi - lo) as u128 + 1)
59 .fold(0u128, u128::saturating_add)
60 }
61
62 pub fn union(&self, other: &IntSet) -> IntSet {
63 IntSet::from_intervals(self.iv.iter().chain(other.iv.iter()).copied())
64 }
65
66 pub fn subtract(&self, other: &IntSet) -> IntSet {
68 let mut out = Vec::new();
69 for &(lo, hi) in &self.iv {
70 let mut cur = lo;
71 let mut done = false;
72 for &(olo, ohi) in &other.iv {
73 if ohi < cur {
74 continue;
75 }
76 if olo > hi {
77 break;
78 }
79 if olo > cur {
80 out.push((cur, olo - 1));
81 }
82 if ohi >= hi {
83 done = true;
84 break;
85 }
86 cur = ohi + 1;
87 }
88 if !done {
89 out.push((cur, hi));
90 }
91 }
92 IntSet { iv: out }
93 }
94
95 pub fn intersects(&self, other: &IntSet) -> bool {
96 let (mut i, mut j) = (0, 0);
97 while i < self.iv.len() && j < other.iv.len() {
98 let (alo, ahi) = self.iv[i];
99 let (blo, bhi) = other.iv[j];
100 if ahi < blo {
101 i += 1;
102 } else if bhi < alo {
103 j += 1;
104 } else {
105 return true;
106 }
107 }
108 false
109 }
110
111 pub fn clip(&self, lo: i128, hi: i128) -> IntSet {
113 IntSet::from_intervals(self.iv.iter().filter_map(|&(a, b)| {
114 let (a, b) = (a.max(lo), b.min(hi));
115 (a <= b).then_some((a, b))
116 }))
117 }
118
119 pub fn values(&self, limit: u128) -> Option<Vec<i128>> {
122 if self.count() > limit {
123 return None;
124 }
125 let mut out = Vec::new();
126 for &(lo, hi) in &self.iv {
127 let mut v = lo;
128 while v <= hi {
129 out.push(v);
130 v += 1;
131 }
132 }
133 Some(out)
134 }
135}
136
137#[cfg(test)]
138mod tests {
139 use super::*;
140
141 #[test]
142 fn merges_overlapping_and_adjacent() {
143 let s = IntSet::from_intervals([(5, 7), (1, 2), (3, 4), (6, 9), (20, 20)]);
144 assert_eq!(s.intervals(), &[(1, 9), (20, 20)]);
145 assert_eq!(s.count(), 10);
146 }
147
148 #[test]
149 fn empty_interval_is_dropped() {
150 assert!(IntSet::from_intervals([(3, 2)]).is_empty());
151 }
152
153 #[test]
154 fn contains_on_boundaries() {
155 let s = IntSet::from_intervals([(2, 4), (10, 12)]);
156 for v in [2, 3, 4, 10, 11, 12] {
157 assert!(s.contains(v), "{v}");
158 }
159 for v in [1, 5, 9, 13, -1] {
160 assert!(!s.contains(v), "{v}");
161 }
162 }
163
164 #[test]
165 fn subtract_splits_and_removes() {
166 let a = IntSet::from_intervals([(0, 10)]);
167 let b = IntSet::from_intervals([(0, 1), (5, 6), (10, 20)]);
168 assert_eq!(a.subtract(&b).intervals(), &[(2, 4), (7, 9)]);
169 assert!(a.subtract(&a).is_empty());
170 }
171
172 #[test]
173 fn intersects_and_clip() {
174 let a = IntSet::from_intervals([(0, 3), (10, 12)]);
175 assert!(a.intersects(&IntSet::from_intervals([(3, 5)])));
176 assert!(!a.intersects(&IntSet::from_intervals([(4, 9)])));
177 assert_eq!(a.clip(2, 11).intervals(), &[(2, 3), (10, 11)]);
178 }
179
180 #[test]
181 fn values_respects_limit() {
182 let a = IntSet::from_intervals([(1, 3), (7, 7)]);
183 assert_eq!(a.values(10), Some(vec![1, 2, 3, 7]));
184 assert_eq!(a.values(3), None);
185 }
186}