1use std::sync::Arc;
2
3use rustc_hash::{FxHashMap, FxHashSet};
4
5use crate::types::{Fragment, FragmentId};
6
7pub struct IntervalIndex {
8 by_path: FxHashMap<Arc<str>, Vec<(u32, u32)>>,
9 ids: FxHashSet<FragmentId>,
10}
11
12impl IntervalIndex {
13 pub fn new() -> Self {
14 Self {
15 by_path: FxHashMap::default(),
16 ids: FxHashSet::default(),
17 }
18 }
19
20 pub fn add(&mut self, frag: &Fragment) {
21 self.add_id(&frag.id);
22 }
23
24 pub fn add_id(&mut self, frag_id: &FragmentId) {
25 self.ids.insert(frag_id.clone());
26 let intervals = self.by_path.entry(frag_id.path.clone()).or_default();
27 let item = (frag_id.start_line, frag_id.end_line);
28 let pos = intervals.binary_search(&item).unwrap_or_else(|e| e);
29 intervals.insert(pos, item);
30 }
31
32 pub fn contains(&self, frag_id: &FragmentId) -> bool {
33 self.ids.contains(frag_id)
34 }
35
36 pub fn overlaps(&self, frag: &Fragment) -> bool {
37 let intervals = match self.by_path.get(&frag.id.path) {
38 Some(v) => v,
39 None => return false,
40 };
41 let upper = intervals.partition_point(|&(s, _)| s <= frag.end_line());
42 for i in 0..upper {
43 let (start, end) = intervals[i];
44 if start == frag.start_line() && end == frag.end_line() {
45 continue;
46 }
47 if end > frag.start_line() {
55 return true;
56 }
57 }
58 false
59 }
60
61 pub fn is_superset_of(&self, frag: &Fragment) -> bool {
62 let intervals = match self.by_path.get(&frag.id.path) {
63 Some(v) => v,
64 None => return false,
65 };
66 let upper = intervals.partition_point(|&(s, _)| s <= frag.start_line());
67 for i in 0..upper {
68 let (start, end) = intervals[i];
69 if start == frag.start_line() && end == frag.end_line() {
70 continue;
71 }
72 if start <= frag.start_line() && frag.end_line() <= end {
73 return true;
74 }
75 }
76 false
77 }
78}