1use std::borrow::Cow;
2use std::iter::FusedIterator;
3
4use bitvec::order::Lsb0;
5use bitvec::slice::BitSlice;
6
7use crate::{Analyze, StatType};
8
9#[derive(Clone, PartialEq, Debug)]
14pub struct PresentValues<'a, T: Copy> {
15 bits: Option<Cow<'a, BitSlice<u8, Lsb0>>>,
18 values: Vec<T>,
20}
21
22impl<'a, T: Copy> PresentValues<'a, T> {
23 pub(crate) fn all_present(values: Vec<T>) -> Self {
25 Self { bits: None, values }
26 }
27
28 pub(crate) fn with_bits(bits: Cow<'a, BitSlice<u8, Lsb0>>, values: Vec<T>) -> Self {
31 Self {
32 bits: Some(bits),
33 values,
34 }
35 }
36}
37
38impl<T: Copy> PresentValues<'_, T> {
39 #[inline]
41 #[must_use]
42 pub fn is_present(&self, idx: usize) -> bool {
43 match &self.bits {
44 None => idx < self.values.len(),
45 Some(bits) => bits.get(idx).as_deref().copied().unwrap_or(false),
46 }
47 }
48
49 #[inline]
51 #[must_use]
52 pub fn feature_count(&self) -> usize {
53 match &self.bits {
54 None => self.values.len(),
55 Some(bits) => bits.len(),
56 }
57 }
58
59 #[inline]
61 #[must_use]
62 pub fn dense_values(&self) -> &[T] {
63 &self.values
64 }
65
66 #[inline]
72 #[must_use]
73 pub fn get(&self, idx: usize) -> Option<T> {
74 match &self.bits {
75 None => self.values.get(idx).copied(),
76 Some(bits) => {
77 if *bits.get(idx)? {
78 Some(self.values[bits[..idx].count_ones()])
79 } else {
80 None
81 }
82 }
83 }
84 }
85
86 #[must_use]
91 pub fn materialize(&self) -> Vec<Option<T>> {
92 self.iter_optional().collect()
93 }
94
95 #[must_use]
100 pub fn iter_optional(&self) -> PresenceOptIter<'_, T> {
101 PresenceOptIter {
102 bits: self.bits.as_deref(),
103 values: &self.values,
104 feat_idx: 0,
105 end: self.feature_count(),
106 dense_idx: 0,
107 back_dense: None,
108 }
109 }
110}
111
112impl<T: Analyze + Copy> Analyze for PresentValues<'_, T> {
113 fn collect_statistic(&self, stat: StatType) -> usize {
114 if stat == StatType::DecodedMetaSize {
115 0
116 } else {
117 let bits_size = self.bits.as_ref().map_or(0, |bits| bits.len().div_ceil(8));
118 bits_size + self.dense_values().collect_statistic(stat)
119 }
120 }
121}
122
123pub struct PresenceOptIter<'p, T: Copy> {
130 bits: Option<&'p BitSlice<u8, Lsb0>>,
132 values: &'p [T],
133 feat_idx: usize,
135 end: usize,
137 dense_idx: usize,
139 back_dense: Option<usize>,
142}
143
144impl<T: Copy> Iterator for PresenceOptIter<'_, T> {
145 type Item = Option<T>;
146
147 fn next(&mut self) -> Option<Option<T>> {
148 if self.feat_idx >= self.end {
149 return None;
150 }
151 let idx = self.feat_idx;
152 self.feat_idx += 1;
153 match self.bits {
154 None => Some(Some(self.values[idx])),
155 Some(bits) if bits[idx] => {
156 let v = self.values[self.dense_idx];
157 self.dense_idx += 1;
158 Some(Some(v))
159 }
160 Some(_) => Some(None),
161 }
162 }
163
164 fn size_hint(&self) -> (usize, Option<usize>) {
165 let remaining = self.len();
166 (remaining, Some(remaining))
167 }
168}
169
170impl<T: Copy> DoubleEndedIterator for PresenceOptIter<'_, T> {
171 fn next_back(&mut self) -> Option<Option<T>> {
172 if self.feat_idx >= self.end {
173 return None;
174 }
175 self.end -= 1;
176 let idx = self.end;
177 match self.bits {
178 None => Some(Some(self.values[idx])),
179 Some(bits) => {
180 let dense = self
182 .back_dense
183 .get_or_insert_with(|| bits[..=idx].count_ones());
184 if bits[idx] {
185 *dense -= 1;
186 Some(Some(self.values[*dense]))
187 } else {
188 Some(None)
189 }
190 }
191 }
192 }
193}
194
195impl<T: Copy> ExactSizeIterator for PresenceOptIter<'_, T> {
196 fn len(&self) -> usize {
197 self.end - self.feat_idx
198 }
199}
200
201impl<T: Copy> FusedIterator for PresenceOptIter<'_, T> {}
202
203#[cfg(test)]
204mod tests {
205 use bitvec::bitvec;
206 use rstest::rstest;
207
208 use super::*;
209 use crate::test_helpers::assert_size_hint_exact;
210
211 fn sparse(pattern: &[bool]) -> PresentValues<'static, u8> {
212 let mut bits = bitvec![u8, Lsb0;];
213 let mut values = Vec::new();
214 for (idx, &present) in pattern.iter().enumerate() {
215 bits.push(present);
216 if present {
217 values.push(u8::try_from(idx).unwrap());
218 }
219 }
220 PresentValues::with_bits(Cow::Owned(bits), values)
221 }
222
223 fn expected(pattern: &[bool]) -> Vec<Option<u8>> {
224 pattern
225 .iter()
226 .enumerate()
227 .map(|(idx, &p)| p.then(|| u8::try_from(idx).unwrap()))
228 .collect()
229 }
230
231 #[rstest]
232 #[case::empty(&[])]
233 #[case::single_present(&[true])]
234 #[case::single_absent(&[false])]
235 #[case::alternating(&[true, false, true, false, true])]
236 #[case::leading_absent(&[false, false, true, true, false, true, false])]
237 #[case::all_present(&[true; 9])]
238 #[case::all_absent(&[false; 9])]
239 #[case::spans_two_bytes(&[true, false, true, true, false, false, true, false, true, true, false])]
240 fn iter_optional_runs_backwards(#[case] pattern: &[bool]) {
241 let presence = sparse(pattern);
242 let want = expected(pattern);
243
244 assert_eq!(presence.iter_optional().collect::<Vec<_>>(), want);
245 assert_size_hint_exact(|| presence.iter_optional(), &want);
246
247 let mut back = presence.iter_optional().rev().collect::<Vec<_>>();
248 back.reverse();
249 assert_eq!(back, want);
250 }
251
252 #[rstest]
253 #[case::empty(&[])]
254 #[case::single(&[10])]
255 #[case::many(&[10, 20, 30, 40])]
256 fn iter_optional_runs_backwards_all_present(#[case] values: &[u8]) {
257 let presence = PresentValues::all_present(values.to_vec());
258 let want: Vec<_> = values.iter().copied().map(Some).collect();
259
260 assert_eq!(presence.iter_optional().collect::<Vec<_>>(), want);
261 assert_size_hint_exact(|| presence.iter_optional(), &want);
262
263 let mut back = presence.iter_optional().rev().collect::<Vec<_>>();
264 back.reverse();
265 assert_eq!(back, want);
266 assert_eq!(presence.iter_optional().next_back(), want.last().copied());
267 }
268
269 #[rstest]
270 #[case::sparse(&[true, false, true, false, true])]
271 #[case::all_absent(&[false, false])]
272 fn get_matches_iter_optional(#[case] pattern: &[bool]) {
273 let dense: Vec<u8> = expected(pattern).into_iter().flatten().collect();
274 let all_present = dense.iter().copied().map(Some).collect();
275 for (presence, want) in [
276 (sparse(pattern), expected(pattern)),
277 (PresentValues::all_present(dense.clone()), all_present),
278 ] {
279 assert_eq!(presence.feature_count(), want.len());
280 assert_eq!(presence.dense_values(), dense);
281 assert_eq!(presence.materialize(), want);
282 for (idx, &value) in want.iter().enumerate() {
283 assert_eq!(presence.get(idx), value);
284 assert_eq!(presence.is_present(idx), value.is_some());
285 }
286 assert_eq!(presence.get(want.len()), None);
287 assert!(!presence.is_present(want.len()));
288 }
289 }
290
291 #[rstest]
292 #[case::empty(&[])]
293 #[case::single_present(&[true])]
294 #[case::single_absent(&[false])]
295 #[case::alternating(&[true, false, true, false, true])]
296 #[case::all_present(&[true; 8])]
297 #[case::all_absent(&[false; 8])]
298 #[case::spans_two_bytes(&[true, false, true, true, false, false, true, false, true, true, false])]
299 fn iter_optional_meets_in_the_middle(#[case] pattern: &[bool]) {
300 let presence = sparse(pattern);
301 let want = expected(pattern);
302
303 let mut iter = presence.iter_optional();
304 let (mut front, mut back) = (Vec::new(), Vec::new());
305 while iter.len() > 0 {
306 assert_eq!(iter.len(), want.len() - front.len() - back.len());
307 front.extend(iter.next());
308 back.extend(iter.next_back());
309 }
310 back.reverse();
311 front.extend(back);
312
313 assert_eq!(front, want);
314 assert_eq!(iter.next(), None);
315 assert_eq!(iter.next_back(), None);
316 }
317}