molframe_core/column/
bits.rs1use crate::limits::CapacityError;
14use std::sync::Arc;
15
16#[derive(Clone, PartialEq, Eq, Debug, Default)]
21pub struct BitVec {
22 words: Arc<Vec<u64>>,
23 len: u32,
24}
25
26const BITS: u32 = u64::BITS;
27
28impl BitVec {
29 #[must_use]
31 pub fn new() -> Self {
32 Self {
33 words: Arc::new(Vec::new()),
34 len: 0,
35 }
36 }
37
38 #[must_use]
40 pub fn repeat(value: bool, len: u32) -> Self {
41 let word = if value { u64::MAX } else { 0 };
42 let words = Arc::new(vec![word; word_count(len)]);
43 let mut bits = Self { words, len };
44
45 bits.clear_tail();
46 bits
47 }
48
49 pub(crate) fn from_words(words: Vec<u64>, len: u32) -> Self {
55 debug_assert_eq!(words.len(), word_count(len));
56 Self {
57 words: Arc::new(words),
58 len,
59 }
60 }
61
62 #[must_use]
64 pub fn with_capacity(len: u32) -> Self {
65 Self {
66 words: Arc::new(Vec::with_capacity(word_count(len))),
67 len: 0,
68 }
69 }
70
71 #[must_use]
73 pub const fn len(&self) -> u32 {
74 self.len
75 }
76
77 #[must_use]
79 pub const fn is_empty(&self) -> bool {
80 self.len == 0
81 }
82
83 pub fn try_push(&mut self, value: bool) -> Result<(), CapacityError> {
89 let position = self.len;
90 let Some(next_len) = self.len.checked_add(1) else {
91 return Err(CapacityError::new("bit vector"));
92 };
93
94 if position.is_multiple_of(BITS) {
95 Arc::make_mut(&mut self.words).push(0);
96 }
97
98 self.len = next_len;
99
100 if !value {
101 return Ok(());
102 }
103
104 if let Some(word) = Arc::make_mut(&mut self.words).last_mut() {
105 *word |= bit_mask(position);
106 }
107 Ok(())
108 }
109
110 #[must_use]
112 pub fn get(&self, position: u32) -> Option<bool> {
113 if position >= self.len {
114 return None;
115 }
116
117 self.words
118 .get(word_index(position))
119 .map(|word| *word & bit_mask(position) != 0)
120 }
121
122 #[must_use]
124 pub fn test(&self, position: u32) -> bool {
125 self.get(position) == Some(true)
126 }
127
128 pub fn set(&mut self, position: u32, value: bool) {
130 if position >= self.len {
131 return;
132 }
133 let Some(word) = Arc::make_mut(&mut self.words).get_mut(word_index(position)) else {
134 return;
135 };
136
137 let mask = bit_mask(position);
138
139 if value {
140 *word |= mask;
141 } else {
142 *word &= !mask;
143 }
144 }
145
146 #[must_use]
148 pub fn count_ones(&self) -> u32 {
149 self.words.iter().map(|word| word.count_ones()).sum()
150 }
151
152 #[must_use]
154 pub fn all(&self) -> bool {
155 let complete_words = (self.len / BITS) as usize;
156
157 if !self
158 .words
159 .iter()
160 .take(complete_words)
161 .all(|word| *word == u64::MAX)
162 {
163 return false;
164 }
165
166 let tail_bits = self.len % BITS;
167
168 tail_bits == 0 || self.words.get(complete_words).copied() == Some(low_mask(tail_bits))
169 }
170
171 #[must_use]
173 pub fn none(&self) -> bool {
174 self.words.iter().all(|word| *word == 0)
175 }
176
177 #[must_use]
185 pub fn ones(&self) -> Ones<'_> {
186 Ones {
187 words: &self.words,
188 word: 0,
189 remaining: 0,
190 started: false,
191 }
192 }
193
194 pub fn intersect_with(&mut self, other: &Self) {
196 let shared = self.words.len().min(other.words.len());
197 let words = Arc::make_mut(&mut self.words);
198
199 for (word, other_word) in words[..shared].iter_mut().zip(&other.words[..shared]) {
200 *word &= *other_word;
201 }
202
203 for word in &mut words[shared..] {
204 *word = 0;
205 }
206 }
207
208 pub fn union_with(&mut self, other: &Self) {
213 for (word, other_word) in Arc::make_mut(&mut self.words)
214 .iter_mut()
215 .zip(other.words.iter())
216 {
217 *word |= *other_word;
218 }
219
220 self.clear_tail();
221 }
222
223 pub fn invert(&mut self) {
225 for word in Arc::make_mut(&mut self.words) {
226 *word = !*word;
227 }
228
229 self.clear_tail();
230 }
231
232 fn clear_tail(&mut self) {
235 let used = self.len % BITS;
236
237 if used == 0 {
238 return;
239 }
240 if let Some(word) = Arc::make_mut(&mut self.words).last_mut() {
241 *word &= low_mask(used);
242 }
243 }
244}
245
246impl BitVec {
247 pub fn try_from_iter<T: IntoIterator<Item = bool>>(iter: T) -> Option<Self> {
249 let iter = iter.into_iter();
250 let capacity = u32::try_from(iter.size_hint().0).ok()?;
251 let mut bits = Self::with_capacity(capacity);
252
253 for value in iter {
254 bits.try_push(value).ok()?;
255 }
256
257 Some(bits)
258 }
259}
260
261#[must_use]
266pub fn bit_width(max: u64) -> u8 {
267 match max {
268 0 => 1,
269 _ => narrow_width(u64::BITS - max.leading_zeros()),
270 }
271}
272
273const fn low_mask(width: u32) -> u64 {
275 if width >= u64::BITS {
276 u64::MAX
277 } else {
278 (1u64 << width) - 1
279 }
280}
281
282fn word_count(len: u32) -> usize {
283 len.div_ceil(BITS) as usize
284}
285
286const fn word_index(position: u32) -> usize {
287 (position / BITS) as usize
288}
289
290const fn bit_offset(position: u32) -> u32 {
291 position % BITS
292}
293
294const fn bit_mask(position: u32) -> u64 {
295 1u64 << bit_offset(position)
296}
297
298const fn placement(width: u32, index: u32) -> (usize, u32, usize) {
301 let start_bit = index as u64 * width as u64;
302 let byte = (start_bit / 8) as usize;
303 let offset = (start_bit % 8) as u32;
304 let bytes = (offset as usize + width as usize).div_ceil(8);
305
306 (byte, offset, bytes)
307}
308
309#[must_use]
315pub fn pack(values: &[u64], width: u8) -> Option<Vec<u8>> {
316 pack_mapped(values, width, |value| *value)
317}
318
319pub(super) fn pack_mapped<T, F>(values: &[T], width: u8, to_bits: F) -> Option<Vec<u8>>
320where
321 F: Fn(&T) -> u64,
322{
323 let width = u32::from(width.clamp(1, 64));
324 let total_bits = u64::try_from(values.len())
325 .ok()?
326 .checked_mul(u64::from(width))?;
327 let packed_len = usize::try_from(total_bits.div_ceil(8)).ok()?;
328 let mut packed = vec![0u8; packed_len];
329
330 for (index, value) in values.iter().enumerate() {
331 write_packed_value(
332 &mut packed,
333 width,
334 u32::try_from(index).ok()?,
335 to_bits(value),
336 );
337 }
338
339 Some(packed)
340}
341
342fn write_packed_value(packed: &mut [u8], width: u32, index: u32, value: u64) {
343 let (byte, offset, bytes) = placement(width, index);
344 let Some(end) = byte.checked_add(bytes) else {
345 return;
346 };
347 let Some(targets) = packed.get_mut(byte..end) else {
348 return;
349 };
350
351 let shifted = u128::from(value & low_mask(width)) << offset;
352
353 for (step, target) in targets.iter_mut().enumerate() {
354 *target |= ((shifted >> (8 * step)) & u128::from(u8::MAX)).to_le_bytes()[0];
355 }
356}
357
358#[must_use]
368pub fn unpack_one(packed: &[u8], width: u8, index: u32) -> Option<u64> {
369 let width = u32::from(width.clamp(1, 64));
370 let (byte, offset, bytes) = placement(width, index);
371 let end = byte.checked_add(bytes)?;
372 let source = packed.get(byte..end)?;
373
374 let mut window = [0u8; 8];
375 let take = source.len().min(8);
376 let (Some(head), Some(front)) = (window.get_mut(..take), source.get(..take)) else {
377 return None;
378 };
379 head.copy_from_slice(front);
380 let low = u64::from_le_bytes(window) >> offset;
381
382 let high = match source.get(8) {
385 Some(spill) if offset > 0 => u64::from(*spill) << (64 - offset),
386 _ => 0,
387 };
388
389 Some((low | high) & low_mask(width))
390}
391
392fn narrow_width(width: u32) -> u8 {
393 width.to_le_bytes()[0]
394}
395
396#[cfg(test)]
397#[path = "bits_tests.rs"]
398mod tests;
399
400#[derive(Clone, Debug)]
406pub struct Ones<'a> {
407 words: &'a [u64],
409 word: usize,
411 remaining: u64,
413 started: bool,
415}
416
417impl Iterator for Ones<'_> {
418 type Item = u32;
419
420 fn next(&mut self) -> Option<u32> {
421 loop {
422 if self.remaining != 0 {
423 let bit = self.remaining.trailing_zeros();
424 self.remaining &= self.remaining - 1;
425 let base = u32::try_from(self.word).ok()?.checked_mul(BITS)?;
426 return Some(base + bit);
427 }
428
429 if self.started {
433 self.word = self.word.checked_add(1)?;
434 }
435 self.started = true;
436 self.remaining = *self.words.get(self.word)?;
437 }
438 }
439
440 fn size_hint(&self) -> (usize, Option<usize>) {
441 let counted = self.remaining.count_ones() as usize;
444 let from = if self.started {
445 self.word.saturating_add(1)
446 } else {
447 self.word
448 };
449 let rest: usize = match self.words.get(from..) {
450 Some(tail) => tail.iter().map(|word| word.count_ones() as usize).sum(),
451 None => 0,
452 };
453 let total = counted + rest;
454 (total, Some(total))
455 }
456}
457
458impl std::iter::FusedIterator for Ones<'_> {}