int_interval_set/batch/
isize.rs1#[cfg(test)]
8mod construction_tests;
9#[cfg(test)]
10mod membership_queries_tests;
11#[cfg(test)]
12mod statistics_tests;
13
14use int_interval::IsizeCO;
15
16#[derive(Clone, Debug, Default, PartialEq, Eq)]
17#[repr(transparent)]
18pub struct IsizeCOBatchSet(Vec<IsizeCO>);
19
20impl IsizeCOBatchSet {
25 #[inline]
26 pub fn into_inner(self) -> Vec<IsizeCO> {
27 self.0
28 }
29
30 #[inline]
31 pub fn as_slice(&self) -> &[IsizeCO] {
32 &self.0
33 }
34}
35
36impl IsizeCOBatchSet {
41 #[inline]
42 pub fn contains_interval(&self, iv: IsizeCO) -> bool {
43 let slice = self.as_slice();
44 let i = slice.partition_point(|seg| seg.start() <= iv.start());
45 i > 0 && slice[i - 1].contains_interval(iv)
46 }
47
48 #[inline]
49 pub fn contains_point(&self, x: isize) -> bool {
50 let slice = self.as_slice();
51 let i = slice.partition_point(|seg| seg.start() <= x);
52 i > 0 && slice[i - 1].contains(x)
53 }
54
55 #[inline]
56 pub fn interval_containing_point(&self, x: isize) -> Option<IsizeCO> {
57 let slice = self.as_slice();
58 let i = slice.partition_point(|seg| seg.start() <= x);
59
60 if i == 0 {
61 return None;
62 }
63
64 let iv = slice[i - 1];
65 iv.contains(x).then_some(iv)
66 }
67
68 #[inline]
69 pub fn intersects(&self, q: IsizeCO) -> bool {
70 let slice = self.as_slice();
71 let i = slice.partition_point(|seg| seg.start() < q.end_excl());
72
73 if i == 0 {
74 return false;
75 }
76
77 let mut j = i - 1;
78 while j < slice.len() {
79 let iv = slice[j];
80 if iv.start() >= q.end_excl() {
81 break;
82 }
83 if iv.intersects(q) {
84 return true;
85 }
86 j += 1;
87 }
88
89 false
90 }
91}
92
93impl IsizeCOBatchSet {
98 #[inline]
99 pub fn iter_intervals(&self) -> impl Iterator<Item = IsizeCO> {
100 self.as_slice().iter().copied()
101 }
102
103 #[inline]
104 pub fn iter_points(&self) -> impl Iterator<Item = isize> {
105 self.iter_intervals().flat_map(IsizeCO::iter)
106 }
107}
108
109impl IsizeCOBatchSet {
114 #[inline]
115 pub fn interval_count(&self) -> isize {
116 self.0.len() as isize
117 }
118
119 #[inline]
120 pub fn point_count(&self) -> usize {
121 self.0.iter().map(|iv| iv.len()).sum()
122 }
123
124 #[inline]
125 pub fn coverage_len_of(&self, q: IsizeCO) -> usize {
126 let slice = self.as_slice();
127 let mut i = slice.partition_point(|seg| seg.start() < q.start());
128 i = i.saturating_sub(1);
129
130 let mut acc = 0usize;
131 while i < slice.len() {
132 let iv = slice[i];
133 if iv.start() >= q.end_excl() {
134 break;
135 }
136
137 if let Some(overlap) = iv.intersection(q) {
138 acc += overlap.len();
139 }
140
141 i += 1;
142 }
143
144 acc
145 }
146
147 #[inline]
148 pub fn coverage_ratio_of(&self, q: IsizeCO) -> f32 {
149 self.coverage_len_of(q) as f32 / q.len() as f32
150 }
151}
152
153mod construction {
158 use super::*;
159
160 #[inline]
161 fn normalize(mut xs: Vec<IsizeCO>) -> Vec<IsizeCO> {
162 if xs.len() <= 1 {
163 return xs;
164 }
165
166 xs.sort_unstable_by(|a, b| {
167 a.start()
168 .cmp(&b.start())
169 .then(a.end_excl().cmp(&b.end_excl()))
170 });
171
172 let mut out = Vec::with_capacity(xs.len());
173
174 for iv in xs {
175 match out.last_mut() {
176 None => out.push(iv),
177 Some(last) => {
178 if last.is_contiguous_with(iv) {
179 *last = last.convex_hull(iv);
180 } else {
181 out.push(iv);
182 }
183 }
184 }
185 }
186
187 out
188 }
189
190 impl From<Vec<IsizeCO>> for IsizeCOBatchSet {
191 #[inline]
192 fn from(value: Vec<IsizeCO>) -> Self {
193 Self(normalize(value))
194 }
195 }
196
197 impl<const N: usize> From<[IsizeCO; N]> for IsizeCOBatchSet {
198 #[inline]
199 fn from(value: [IsizeCO; N]) -> Self {
200 Self::from(Vec::from(value))
201 }
202 }
203
204 impl FromIterator<IsizeCO> for IsizeCOBatchSet {
205 #[inline]
206 fn from_iter<T: IntoIterator<Item = IsizeCO>>(iter: T) -> Self {
207 Self::from(iter.into_iter().collect::<Vec<_>>())
208 }
209 }
210}