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]
55 pub fn from_sorted(positions: Vec<u32>) -> Self {
56 let (Some(first), Some(last)) = (positions.first().copied(), positions.last().copied())
57 else {
58 return Self::Empty;
59 };
60 let span = u64::from(last - first) + 1;
61 if last < u32::MAX && span == positions.len() as u64 {
62 return Self::Range(first..last + 1);
63 }
64 if let Some(runs) = inline_runs(&positions) {
65 let covered: u64 = runs.iter().map(|run| u64::from(run.end - run.start)).sum();
66 if covered == positions.len() as u64 && runs.len() * 2 < positions.len() {
67 return Self::Ranges(runs);
68 }
69 }
70 if let Some(mask_len) = last.checked_add(1)
71 && positions.len() as u64 * u64::from(DENSE_FRACTION) >= u64::from(mask_len)
72 {
73 return Self::Dense(mask_from_positions(mask_len, &positions));
74 }
75 Self::Sparse(positions)
76 }
77
78 #[must_use]
83 pub fn len(&self) -> u64 {
84 selection_len(self)
85 }
86
87 #[must_use]
89 pub fn is_empty(&self) -> bool {
90 self.len() == 0
91 }
92
93 #[must_use]
95 pub fn contains(&self, atom: u32) -> bool {
96 match self {
97 Self::Empty => false,
98 Self::All(count) => atom < *count,
99 Self::Range(run) => run.contains(&atom),
100 Self::Ranges(runs) => {
101 let candidate = runs.partition_point(|run| run.end <= atom);
102 runs.get(candidate).is_some_and(|run| run.contains(&atom))
103 }
104 Self::Sparse(positions) => positions.binary_search(&atom).is_ok(),
105 Self::Dense(mask) => mask.test(atom),
106 }
107 }
108
109 #[must_use]
121 pub fn position_bound(&self) -> u32 {
122 match self {
123 Self::Empty => 0,
124 Self::All(count) => *count,
125 Self::Range(run) => run.end,
126 Self::Ranges(runs) => match runs.last() {
127 Some(run) => run.end,
128 None => 0,
129 },
130 Self::Sparse(positions) => match positions.last() {
131 Some(last) => last.saturating_add(1),
132 None => 0,
133 },
134 Self::Dense(mask) => mask.len(),
135 }
136 }
137
138 #[must_use]
145 pub fn iter(&self) -> SelectionIter<'_> {
146 match self {
147 Self::Empty => SelectionIter::Run(0..0),
148 Self::All(count) => SelectionIter::Run(0..*count),
149 Self::Range(run) => SelectionIter::Run(run.start..run.end),
150 Self::Ranges(runs) => SelectionIter::Runs {
151 runs,
152 next: 0,
153 current: 0..0,
154 },
155 Self::Sparse(positions) => SelectionIter::Sparse(positions.iter()),
156 Self::Dense(mask) => SelectionIter::Dense(mask.ones()),
157 }
158 }
159}
160
161#[derive(Clone, Debug)]
163pub enum SelectionIter<'a> {
164 Run(Range<u32>),
167 Runs {
169 runs: &'a [Range<u32>],
171 next: usize,
173 current: Range<u32>,
175 },
176 Sparse(std::slice::Iter<'a, u32>),
178 Dense(Ones<'a>),
180}
181
182impl Iterator for SelectionIter<'_> {
183 type Item = u32;
184
185 fn next(&mut self) -> Option<u32> {
186 match self {
187 Self::Run(run) => run.next(),
188 Self::Runs {
189 runs,
190 next,
191 current,
192 } => loop {
193 if let Some(position) = current.next() {
194 return Some(position);
195 }
196 let run = runs.get(*next)?;
197 *next = next.checked_add(1)?;
198 *current = run.start..run.end;
199 },
200 Self::Sparse(positions) => positions.next().copied(),
201 Self::Dense(ones) => ones.next(),
202 }
203 }
204
205 fn size_hint(&self) -> (usize, Option<usize>) {
206 match self {
207 Self::Run(run) => run.size_hint(),
208 Self::Runs {
209 runs,
210 next,
211 current,
212 } => {
213 let remaining = match runs.get(*next..) {
214 Some(tail) => tail.iter().map(ExactSizeIterator::len).sum::<usize>(),
215 None => 0,
216 };
217 let total = current.len() + remaining;
218 (total, Some(total))
219 }
220 Self::Sparse(positions) => positions.size_hint(),
221 Self::Dense(ones) => ones.size_hint(),
222 }
223 }
224}
225
226impl ExactSizeIterator for SelectionIter<'_> {}
227
228impl std::iter::FusedIterator for SelectionIter<'_> {}
229
230impl FromIterator<u32> for AtomSelection {
231 fn from_iter<T: IntoIterator<Item = u32>>(iter: T) -> Self {
232 let mut positions: Vec<u32> = iter.into_iter().collect();
233 positions.sort_unstable();
234 positions.dedup();
235 Self::from_sorted(positions)
236 }
237}
238
239impl<'a> IntoIterator for &'a AtomSelection {
240 type Item = u32;
241 type IntoIter = SelectionIter<'a>;
242
243 fn into_iter(self) -> Self::IntoIter {
244 self.iter()
245 }
246}
247
248fn inline_runs(positions: &[u32]) -> Option<SmallVec<[Range<u32>; 4]>> {
249 let mut runs = SmallVec::<[Range<u32>; 4]>::new();
250 for position in positions.iter().copied() {
251 let end = position.checked_add(1)?;
252 if let Some(run) = runs.last_mut()
253 && run.end == position
254 {
255 run.end = end;
256 continue;
257 }
258 if runs.len() == runs.inline_size() {
259 return None;
260 }
261 runs.push(position..end);
262 }
263 Some(runs)
264}
265
266fn mask_from_positions(len: u32, positions: &[u32]) -> BitVec {
267 let mut mask = BitVec::repeat(false, len);
268 for position in positions {
269 mask.set(*position, true);
270 }
271 mask
272}
273
274fn selection_len(selection: &AtomSelection) -> u64 {
275 match selection {
276 AtomSelection::Empty => 0,
277 AtomSelection::All(count) => u64::from(*count),
278 AtomSelection::Range(run) => u64::from(run.end - run.start),
279 AtomSelection::Ranges(runs) => runs.iter().map(|run| u64::from(run.end - run.start)).sum(),
280 AtomSelection::Sparse(positions) => positions.len() as u64,
281 AtomSelection::Dense(mask) => u64::from(mask.count_ones()),
282 }
283}