1use bitvec::prelude::{BitBox, BitVec, Msb0, bitvec};
4use get_size2::GetSize;
5
6#[derive(Clone, Debug, Eq, Hash, PartialEq, GetSize)]
27pub struct RankBitBox {
28 #[get_size(size_fn = bit_box_size)]
29 bits: RankBitBoxStorage,
30 chunk_ranks: Box<[u32]>,
31}
32
33pub type RankBitBoxStorage = BitBox<Chunk, Msb0>;
34pub type RankBitBoxVec = BitVec<Chunk, Msb0>;
35
36fn bit_box_size(bits: &RankBitBoxStorage) -> usize {
37 std::mem::size_of_val(bits.as_raw_slice())
38}
39
40#[cfg(target_pointer_width = "64")]
42type Chunk = u64;
43#[cfg(not(target_pointer_width = "64"))]
44type Chunk = u32;
45
46const CHUNK_SIZE: usize = Chunk::BITS as usize;
47
48impl RankBitBox {
49 pub fn bits_with_capacity(cap: usize) -> RankBitBoxVec {
50 bitvec![Chunk, Msb0; 0; cap]
51 }
52
53 pub fn from_bits(bits: RankBitBoxVec) -> Self {
54 let chunk_ranks = bits
55 .as_raw_slice()
56 .iter()
57 .scan(0u32, |rank, chunk| {
58 let result = *rank;
59 *rank += chunk.count_ones();
60 Some(result)
61 })
62 .collect();
63 let bits = bits.into();
64 Self { bits, chunk_ranks }
65 }
66
67 #[inline]
68 pub fn len(&self) -> usize {
69 self.bits.len()
70 }
71
72 #[inline]
73 pub fn is_empty(&self) -> bool {
74 self.bits.is_empty()
75 }
76
77 #[inline]
78 pub fn get_bit(&self, index: usize) -> Option<bool> {
79 self.bits.get(index).map(|bit| *bit)
80 }
81
82 #[inline]
83 pub fn iter_ones(&self) -> impl DoubleEndedIterator<Item = usize> + '_ {
84 self.bits.iter_ones()
85 }
86
87 #[inline]
89 pub fn rank(&self, index: usize) -> u32 {
90 let chunk_index = index / CHUNK_SIZE;
91 let index_within_chunk = index % CHUNK_SIZE;
92 let chunk_rank = self.chunk_ranks[chunk_index];
93 if index_within_chunk == 0 {
94 return chunk_rank;
95 }
96
97 let chunk = self.bits.as_raw_slice()[chunk_index];
101 let chunk_mask = Chunk::MAX << (CHUNK_SIZE - index_within_chunk);
102 let rank_within_chunk = (chunk & chunk_mask).count_ones();
103 chunk_rank + rank_within_chunk
104 }
105}
106
107#[cfg(test)]
108mod tests {
109 use std::mem::size_of;
110
111 use get_size2::GetSize;
112
113 use super::{CHUNK_SIZE, Chunk, RankBitBox};
114
115 #[test]
116 fn heap_size_includes_bits_and_chunk_ranks() {
117 let bit_count = CHUNK_SIZE + 1;
118 let bits = RankBitBox::from_bits(RankBitBox::bits_with_capacity(bit_count));
119 let chunk_count = bit_count.div_ceil(CHUNK_SIZE);
120
121 assert_eq!(
122 bits.get_heap_size(),
123 chunk_count * (size_of::<Chunk>() + size_of::<u32>())
124 );
125 }
126}