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