1use bit_set::BitSet;
5
6use crate::license_detection::models::position_span::PositionSpan;
7
8#[derive(Clone, Debug, PartialEq, Eq)]
12pub struct PositionSet {
13 bitset: BitSet,
14 min_pos: usize,
15 max_pos: usize,
16}
17
18impl PositionSet {
19 pub fn from_usize_iter<I: IntoIterator<Item = usize>>(iter: I) -> Self {
21 let mut bitset = BitSet::new();
22 let mut min_pos = usize::MAX;
23 let mut max_pos = 0;
24
25 for pos in iter {
26 bitset.insert(pos);
27 min_pos = min_pos.min(pos);
28 max_pos = max_pos.max(pos);
29 }
30
31 Self {
32 bitset,
33 min_pos,
34 max_pos,
35 }
36 }
37
38 pub fn new() -> Self {
40 Self {
41 bitset: BitSet::new(),
42 min_pos: usize::MAX,
43 max_pos: 0,
44 }
45 }
46
47 pub fn len(&self) -> usize {
49 self.bitset.count()
50 }
51
52 pub fn is_empty(&self) -> bool {
54 self.bitset.is_empty()
55 }
56
57 pub fn min_pos(&self) -> usize {
61 self.min_pos
62 }
63
64 pub fn max_pos(&self) -> usize {
68 self.max_pos
69 }
70
71 pub fn insert(&mut self, pos: usize) -> bool {
73 let inserted = self.bitset.insert(pos);
74 if inserted {
75 self.min_pos = self.min_pos.min(pos);
76 self.max_pos = self.max_pos.max(pos);
77 }
78 inserted
79 }
80
81 pub fn extend_from_span(&mut self, span: &PositionSpan) {
83 match span {
84 PositionSpan::Range { start, end } => {
85 for pos in *start..*end {
86 self.insert(pos);
87 }
88 }
89 PositionSpan::Discrete(positions) => {
90 for &pos in positions {
91 self.insert(pos);
92 }
93 }
94 }
95 }
96
97 pub fn contains(&self, pos: usize) -> bool {
99 self.bitset.contains(pos)
100 }
101
102 pub fn remove(&mut self, pos: usize) -> bool {
104 self.bitset.remove(pos)
105 }
106
107 pub fn remove_span(&mut self, span: &PositionSpan) {
109 for pos in span.iter() {
110 self.remove(pos);
111 }
112 }
113
114 #[inline]
118 pub fn may_overlap_range(&self, range_start: usize, range_end: usize) -> bool {
119 if self.min_pos == usize::MAX {
121 return false;
122 }
123 range_end > self.min_pos && range_start <= self.max_pos
124 }
125
126 pub fn restricted_to_range(&self, start: usize, end: usize) -> PositionSet {
144 if self.min_pos == usize::MAX || end <= start {
145 return PositionSet::new();
146 }
147
148 let lo = start.max(self.min_pos);
150 let hi = end.min(self.max_pos + 1);
151 if hi <= lo {
152 return PositionSet::new();
153 }
154
155 let range_len = hi - lo;
164 let set_span = self.max_pos - self.min_pos + 1;
165 if range_len < set_span {
166 (lo..hi).filter(|&pos| self.bitset.contains(pos)).collect()
167 } else {
168 self.bitset
169 .iter()
170 .filter(|&pos| pos >= lo && pos < hi)
171 .collect()
172 }
173 }
174
175 pub fn union(&self, other: &PositionSet) -> PositionSet {
179 let mut result = self.clone();
180 for pos in other.iter() {
181 result.insert(pos);
182 }
183 result
184 }
185
186 pub fn difference(&self, other: &PositionSet) -> PositionSet {
188 let mut result = PositionSet::new();
189 for pos in self.bitset.iter() {
190 if !other.bitset.contains(pos) {
191 result.insert(pos);
192 }
193 }
194 result
195 }
196
197 pub fn intersection_len(&self, other: &PositionSet) -> usize {
199 self.bitset
200 .iter()
201 .filter(|&p| other.bitset.contains(p))
202 .count()
203 }
204
205 pub fn overlaps_span(&self, span: &PositionSpan) -> bool {
208 let (span_min, span_max) = span.bounds();
209 if span.is_empty() {
210 return false;
211 }
212 if !self.may_overlap_range(span_min, span_max) {
213 return false;
214 }
215 span.iter().any(|p| self.contains(p))
216 }
217
218 pub fn contains_range(&self, range: std::ops::Range<usize>) -> bool {
221 if range.is_empty() {
222 return true;
223 }
224 let (start, end) = (range.start, range.end);
225 if !self.may_overlap_range(start, end) {
226 return false;
227 }
228 (start..end).all(|pos| self.contains(pos))
229 }
230
231 pub fn iter(&self) -> impl Iterator<Item = usize> + '_ {
233 self.bitset.iter()
234 }
235
236 pub fn to_position_span(&self) -> PositionSpan {
240 if self.is_empty() {
241 return PositionSpan::empty();
242 }
243
244 let positions: Vec<usize> = self.iter().collect();
245 let is_contiguous = positions.windows(2).all(|w| w[1] == w[0] + 1);
246
247 if is_contiguous {
248 PositionSpan::range(self.min_pos, self.max_pos + 1)
249 } else {
250 PositionSpan::from_positions(positions)
251 }
252 }
253}
254
255impl Default for PositionSet {
256 fn default() -> Self {
257 Self::new()
258 }
259}
260
261impl std::iter::FromIterator<usize> for PositionSet {
262 fn from_iter<T: IntoIterator<Item = usize>>(iter: T) -> Self {
263 Self::from_usize_iter(iter)
264 }
265}
266
267#[cfg(test)]
268mod tests {
269 use super::*;
270
271 #[test]
272 fn test_new_empty() {
273 let set = PositionSet::new();
274 assert!(set.is_empty());
275 assert_eq!(set.len(), 0);
276 }
277
278 #[test]
279 fn test_from_usize_iter_sorted() {
280 let set = PositionSet::from_usize_iter(vec![1, 2, 3]);
281 assert_eq!(set.len(), 3);
282 assert_eq!(set.iter().collect::<Vec<_>>(), vec![1, 2, 3]);
283 }
284
285 #[test]
286 fn test_from_usize_iter_unsorted() {
287 let set = PositionSet::from_usize_iter(vec![3, 1, 2]);
288 assert_eq!(set.iter().collect::<Vec<_>>(), vec![1, 2, 3]);
289 }
290
291 #[test]
292 fn test_from_usize_iter_dedup() {
293 let set = PositionSet::from_usize_iter(vec![1, 2, 2, 3, 3, 3]);
294 assert_eq!(set.len(), 3);
295 assert_eq!(set.iter().collect::<Vec<_>>(), vec![1, 2, 3]);
296 }
297
298 #[test]
303 fn test_restricted_to_range_matches_naive_filter() {
304 let positions = vec![0usize, 1, 5, 6, 7, 100, 101, 5000, 5001, 9999];
305 let set = PositionSet::from_usize_iter(positions.iter().copied());
306
307 let naive = |start: usize, end: usize| -> Vec<usize> {
308 set.iter().filter(|&p| p >= start && p < end).collect()
309 };
310
311 let cases = [
312 (0, 0), (3, 3), (0, 10000), (5, 8), (6, 7), (0, 2), (5000, 6000), (200, 5000), (12000, 99999), ];
322
323 for (start, end) in cases {
324 let got: Vec<usize> = set.restricted_to_range(start, end).iter().collect();
325 assert_eq!(
326 got,
327 naive(start, end),
328 "restricted_to_range({start}, {end}) diverged from naive filter"
329 );
330 }
331 }
332
333 #[test]
334 fn test_restricted_to_range_empty_set() {
335 let set = PositionSet::new();
336 assert!(set.restricted_to_range(0, 100).is_empty());
337 }
338
339 #[test]
340 fn test_restricted_to_range_unbounded_end() {
341 let set = PositionSet::from_usize_iter(vec![1usize, 50, 999]);
344 let got: Vec<usize> = set.restricted_to_range(0, usize::MAX).iter().collect();
345 assert_eq!(got, vec![1, 50, 999]);
346
347 let got: Vec<usize> = set.restricted_to_range(50, usize::MAX).iter().collect();
348 assert_eq!(got, vec![50, 999]);
349 }
350
351 #[test]
352 fn test_insert() {
353 let mut set = PositionSet::new();
354 assert!(set.insert(2));
355 assert!(set.insert(1));
356 assert!(set.insert(3));
357 assert!(!set.insert(2)); assert_eq!(set.iter().collect::<Vec<_>>(), vec![1, 2, 3]);
359 }
360
361 #[test]
362 fn test_difference() {
363 let a = PositionSet::from_usize_iter(vec![1, 2, 3, 4]);
364 let b = PositionSet::from_usize_iter(vec![2, 4, 6]);
365 let diff = a.difference(&b);
366 assert_eq!(diff.iter().collect::<Vec<_>>(), vec![1, 3]);
367 }
368
369 #[test]
370 fn test_difference_empty() {
371 let a = PositionSet::from_usize_iter(vec![1, 2, 3]);
372 let b = PositionSet::new();
373 let diff = a.difference(&b);
374 assert_eq!(diff.iter().collect::<Vec<_>>(), vec![1, 2, 3]);
375 }
376
377 #[test]
378 fn test_difference_all_overlap() {
379 let a = PositionSet::from_usize_iter(vec![1, 2, 3]);
380 let b = PositionSet::from_usize_iter(vec![1, 2, 3]);
381 let diff = a.difference(&b);
382 assert!(diff.is_empty());
383 }
384
385 #[test]
386 fn test_contains() {
387 let set = PositionSet::from_usize_iter(vec![1, 3, 5]);
388 assert!(set.contains(1));
389 assert!(set.contains(3));
390 assert!(set.contains(5));
391 assert!(!set.contains(0));
392 assert!(!set.contains(2));
393 assert!(!set.contains(4));
394 }
395
396 #[test]
397 fn test_collect() {
398 let set: PositionSet = vec![3, 1, 2].into_iter().collect();
399 assert_eq!(set.iter().collect::<Vec<_>>(), vec![1, 2, 3]);
400 }
401
402 #[test]
403 fn test_extend_from_span_range() {
404 let mut set = PositionSet::new();
405 set.extend_from_span(&PositionSpan::range(5, 10));
406 assert_eq!(set.len(), 5);
407 assert!(set.contains(5));
408 assert!(set.contains(9));
409 assert!(!set.contains(4));
410 assert!(!set.contains(10));
411 }
412
413 #[test]
414 fn test_extend_from_span_discrete() {
415 let mut set = PositionSet::new();
416 set.extend_from_span(&PositionSpan::from_positions(vec![1, 3, 5]));
417 assert_eq!(set.len(), 3);
418 assert!(set.contains(1));
419 assert!(set.contains(3));
420 assert!(set.contains(5));
421 assert!(!set.contains(2));
422 }
423
424 #[test]
425 fn test_extend_from_span_merge() {
426 let mut set = PositionSet::from_usize_iter(vec![1, 2, 3]);
427 set.extend_from_span(&PositionSpan::range(2, 6));
428 assert_eq!(set.len(), 5);
429 assert_eq!(set.iter().collect::<Vec<_>>(), vec![1, 2, 3, 4, 5]);
430 }
431
432 #[test]
433 fn test_overlaps_span_range_yes() {
434 let set = PositionSet::from_usize_iter(vec![5, 6, 7]);
435 assert!(set.overlaps_span(&PositionSpan::range(6, 10)));
436 assert!(set.overlaps_span(&PositionSpan::range(0, 6)));
437 }
438
439 #[test]
440 fn test_overlaps_span_range_no() {
441 let set = PositionSet::from_usize_iter(vec![1, 2, 3]);
442 assert!(!set.overlaps_span(&PositionSpan::range(5, 10)));
443 assert!(!set.overlaps_span(&PositionSpan::range(10, 20)));
444 }
445
446 #[test]
447 fn test_overlaps_span_discrete_yes() {
448 let set = PositionSet::from_usize_iter(vec![1, 2, 3, 10, 11]);
449 assert!(set.overlaps_span(&PositionSpan::from_positions(vec![3, 4, 5])));
450 assert!(set.overlaps_span(&PositionSpan::from_positions(vec![0, 1])));
451 }
452
453 #[test]
454 fn test_overlaps_span_discrete_no() {
455 let set = PositionSet::from_usize_iter(vec![1, 2, 3]);
456 assert!(!set.overlaps_span(&PositionSpan::from_positions(vec![5, 6, 7])));
457 }
458
459 #[test]
460 fn test_overlaps_span_empty() {
461 let set = PositionSet::from_usize_iter(vec![1, 2, 3]);
462 assert!(!set.overlaps_span(&PositionSpan::empty()));
463 }
464
465 #[test]
466 fn test_contains_range_yes() {
467 let set = PositionSet::from_usize_iter(vec![1, 2, 3, 4, 5]);
468 assert!(set.contains_range(1..6));
469 assert!(set.contains_range(2..4));
470 assert!(set.contains_range(1..6));
471 }
472
473 #[test]
474 fn test_contains_range_no() {
475 let set = PositionSet::from_usize_iter(vec![1, 2, 3]);
476 assert!(!set.contains_range(0..4));
477 assert!(!set.contains_range(3..5));
478 assert!(!set.contains_range(5..10));
479 }
480
481 #[test]
482 fn test_contains_range_empty() {
483 let set = PositionSet::from_usize_iter(vec![1, 2, 3]);
484 assert!(set.contains_range(5..5));
485 assert!(set.contains_range(0..0));
486 }
487
488 #[test]
489 fn test_contains_range_disjoint() {
490 let set = PositionSet::from_usize_iter(vec![10, 11, 12]);
491 assert!(!set.contains_range(0..5));
492 assert!(!set.contains_range(15..20));
493 }
494
495 #[test]
496 fn test_to_position_span_empty() {
497 let set = PositionSet::new();
498 let span = set.to_position_span();
499 assert!(span.is_empty());
500 }
501
502 #[test]
503 fn test_to_position_span_contiguous() {
504 let set = PositionSet::from_usize_iter(vec![5, 6, 7, 8]);
505 let span = set.to_position_span();
506 assert_eq!(span, PositionSpan::range(5, 9));
507 }
508
509 #[test]
510 fn test_to_position_span_single() {
511 let set = PositionSet::from_usize_iter(vec![10]);
512 let span = set.to_position_span();
513 assert_eq!(span, PositionSpan::range(10, 11));
514 }
515
516 #[test]
517 fn test_to_position_span_discrete() {
518 let set = PositionSet::from_usize_iter(vec![1, 3, 5, 7]);
519 let span = set.to_position_span();
520 assert_eq!(span, PositionSpan::from_positions(vec![1, 3, 5, 7]));
521 }
522
523 #[test]
524 fn test_to_position_span_two_with_gap() {
525 let set = PositionSet::from_usize_iter(vec![1, 3]);
526 let span = set.to_position_span();
527 assert_eq!(span, PositionSpan::from_positions(vec![1, 3]));
528 }
529
530 #[test]
531 fn test_min_max_pos() {
532 let set = PositionSet::from_usize_iter(vec![5, 10, 15]);
533 assert_eq!(set.min_pos(), 5);
534 assert_eq!(set.max_pos(), 15);
535 }
536
537 #[test]
538 fn test_min_max_pos_empty() {
539 let set = PositionSet::new();
540 assert_eq!(set.min_pos(), usize::MAX);
541 assert_eq!(set.max_pos(), 0);
542 }
543}