molframe_core/selection/query/
representation.rs1use crate::column::{BitVec, Ones};
4use smallvec::SmallVec;
5use std::ops::Range;
6
7#[derive(Clone, PartialEq, Eq, Debug, Default)]
19pub enum AtomSelection {
20 #[default]
22 Empty,
23 All(u32),
25 Range(Range<u32>),
27 Ranges(SmallVec<[Range<u32>; 4]>),
29 Sparse(Vec<u32>),
31 Dense(BitVec),
33}
34
35const DENSE_FRACTION: u32 = 16;
36
37impl AtomSelection {
38 #[must_use]
40 pub fn range(atoms: Range<u32>) -> Self {
41 if atoms.start >= atoms.end {
42 Self::Empty
43 } else {
44 Self::Range(atoms)
45 }
46 }
47
48 #[must_use]
54 pub fn from_runs(runs: impl IntoIterator<Item = Range<u32>>) -> Self {
55 let mut ordered: Vec<Range<u32>> =
56 runs.into_iter().filter(|run| run.start < run.end).collect();
57 ordered.sort_by_key(|run| run.start);
59 let mut merged = SmallVec::<[Range<u32>; 4]>::new();
60 for run in ordered {
61 match merged.last_mut() {
62 Some(last) if run.start <= last.end => last.end = last.end.max(run.end),
63 _ => merged.push(run),
64 }
65 }
66 match merged.len() {
67 0 => Self::Empty,
68 1 => merged.pop().map_or(Self::Empty, Self::Range),
69 _ => Self::Ranges(merged),
70 }
71 }
72
73 #[must_use]
80 pub fn from_sorted(positions: Vec<u32>) -> Self {
81 let (Some(first), Some(last)) = (positions.first().copied(), positions.last().copied())
82 else {
83 return Self::Empty;
84 };
85 let span = u64::from(last - first) + 1;
86 if last < u32::MAX && span == positions.len() as u64 {
87 return Self::Range(first..last + 1);
88 }
89 if let Some(runs) = inline_runs(&positions) {
90 let covered: u64 = runs.iter().map(|run| u64::from(run.end - run.start)).sum();
91 if covered == positions.len() as u64 && runs.len() * 2 < positions.len() {
92 return Self::Ranges(runs);
93 }
94 }
95 if let Some(mask_len) = last.checked_add(1)
96 && positions.len() as u64 * u64::from(DENSE_FRACTION) >= u64::from(mask_len)
97 {
98 return Self::Dense(mask_from_positions(mask_len, &positions));
99 }
100 Self::Sparse(positions)
101 }
102
103 #[must_use]
108 pub fn len(&self) -> u64 {
109 selection_len(self)
110 }
111
112 #[must_use]
114 pub fn is_empty(&self) -> bool {
115 self.len() == 0
116 }
117
118 #[must_use]
120 pub fn contains(&self, atom: u32) -> bool {
121 match self {
122 Self::Empty => false,
123 Self::All(count) => atom < *count,
124 Self::Range(run) => run.contains(&atom),
125 Self::Ranges(runs) => {
126 let candidate = runs.partition_point(|run| run.end <= atom);
127 runs.get(candidate).is_some_and(|run| run.contains(&atom))
128 }
129 Self::Sparse(positions) => positions.binary_search(&atom).is_ok(),
130 Self::Dense(mask) => mask.test(atom),
131 }
132 }
133
134 #[must_use]
146 pub fn position_bound(&self) -> u32 {
147 match self {
148 Self::Empty => 0,
149 Self::All(count) => *count,
150 Self::Range(run) => run.end,
151 Self::Ranges(runs) => match runs.last() {
152 Some(run) => run.end,
153 None => 0,
154 },
155 Self::Sparse(positions) => match positions.last() {
156 Some(last) => last.saturating_add(1),
157 None => 0,
158 },
159 Self::Dense(mask) => mask.len(),
160 }
161 }
162
163 #[must_use]
170 pub fn iter(&self) -> SelectionIter<'_> {
171 match self {
172 Self::Empty => SelectionIter::Run(0..0),
173 Self::All(count) => SelectionIter::Run(0..*count),
174 Self::Range(run) => SelectionIter::Run(run.start..run.end),
175 Self::Ranges(runs) => SelectionIter::Runs {
176 runs,
177 next: 0,
178 current: 0..0,
179 },
180 Self::Sparse(positions) => SelectionIter::Sparse(positions.iter()),
181 Self::Dense(mask) => SelectionIter::Dense(mask.ones()),
182 }
183 }
184}
185
186#[derive(Clone, Debug)]
188pub enum SelectionIter<'a> {
189 Run(Range<u32>),
192 Runs {
194 runs: &'a [Range<u32>],
196 next: usize,
198 current: Range<u32>,
200 },
201 Sparse(std::slice::Iter<'a, u32>),
203 Dense(Ones<'a>),
205}
206
207impl Iterator for SelectionIter<'_> {
208 type Item = u32;
209
210 fn next(&mut self) -> Option<u32> {
211 match self {
212 Self::Run(run) => run.next(),
213 Self::Runs {
214 runs,
215 next,
216 current,
217 } => loop {
218 if let Some(position) = current.next() {
219 return Some(position);
220 }
221 let run = runs.get(*next)?;
222 *next = next.checked_add(1)?;
223 *current = run.start..run.end;
224 },
225 Self::Sparse(positions) => positions.next().copied(),
226 Self::Dense(ones) => ones.next(),
227 }
228 }
229
230 fn size_hint(&self) -> (usize, Option<usize>) {
231 match self {
232 Self::Run(run) => run.size_hint(),
233 Self::Runs {
234 runs,
235 next,
236 current,
237 } => {
238 let remaining = match runs.get(*next..) {
239 Some(tail) => tail.iter().map(ExactSizeIterator::len).sum::<usize>(),
240 None => 0,
241 };
242 let total = current.len() + remaining;
243 (total, Some(total))
244 }
245 Self::Sparse(positions) => positions.size_hint(),
246 Self::Dense(ones) => ones.size_hint(),
247 }
248 }
249}
250
251impl ExactSizeIterator for SelectionIter<'_> {}
252
253impl std::iter::FusedIterator for SelectionIter<'_> {}
254
255impl FromIterator<u32> for AtomSelection {
256 fn from_iter<T: IntoIterator<Item = u32>>(iter: T) -> Self {
257 let mut positions: Vec<u32> = iter.into_iter().collect();
258 positions.sort_unstable();
259 positions.dedup();
260 Self::from_sorted(positions)
261 }
262}
263
264impl<'a> IntoIterator for &'a AtomSelection {
265 type Item = u32;
266 type IntoIter = SelectionIter<'a>;
267
268 fn into_iter(self) -> Self::IntoIter {
269 self.iter()
270 }
271}
272
273fn inline_runs(positions: &[u32]) -> Option<SmallVec<[Range<u32>; 4]>> {
274 let mut runs = SmallVec::<[Range<u32>; 4]>::new();
275 for position in positions.iter().copied() {
276 let end = position.checked_add(1)?;
277 if let Some(run) = runs.last_mut()
278 && run.end == position
279 {
280 run.end = end;
281 continue;
282 }
283 if runs.len() == runs.inline_size() {
284 return None;
285 }
286 runs.push(position..end);
287 }
288 Some(runs)
289}
290
291fn mask_from_positions(len: u32, positions: &[u32]) -> BitVec {
292 let mut mask = BitVec::repeat(false, len);
293 for position in positions {
294 mask.set(*position, true);
295 }
296 mask
297}
298
299fn selection_len(selection: &AtomSelection) -> u64 {
300 match selection {
301 AtomSelection::Empty => 0,
302 AtomSelection::All(count) => u64::from(*count),
303 AtomSelection::Range(run) => u64::from(run.end - run.start),
304 AtomSelection::Ranges(runs) => runs.iter().map(|run| u64::from(run.end - run.start)).sum(),
305 AtomSelection::Sparse(positions) => positions.len() as u64,
306 AtomSelection::Dense(mask) => u64::from(mask.count_ones()),
307 }
308}