concept_graph/
footprint.rs1use std::mem::size_of;
18
19use roaring::RoaringBitmap;
20
21const CONTAINER: usize = 40;
27
28#[must_use]
35#[expect(
36 clippy::integer_division,
37 reason = "both counts are exact multiples of their divisor, so no remainder exists to lose"
38)]
39pub fn bitmap(set: &RoaringBitmap) -> usize {
40 let stats = set.statistics();
41 let containers = usize::try_from(stats.n_containers).unwrap_or(usize::MAX);
42 let arrays = usize::try_from(stats.n_bytes_array_containers).unwrap_or(usize::MAX) / 2;
43 let bitsets = usize::try_from(stats.n_bytes_bitset_containers).unwrap_or(usize::MAX) / 8;
44 let runs = usize::try_from(stats.n_bytes_run_containers).unwrap_or(usize::MAX);
45 arrays
46 .saturating_add(bitsets)
47 .saturating_add(runs)
48 .saturating_add(containers.saturating_mul(CONTAINER))
49}
50
51#[must_use]
53pub fn bitmaps(sets: &[RoaringBitmap]) -> usize {
54 let own = sets.len().saturating_mul(size_of::<RoaringBitmap>());
55 sets.iter()
56 .fold(own, |total, set| total.saturating_add(bitmap(set)))
57}
58
59#[must_use]
61pub fn vector<T>(values: &Vec<T>) -> usize {
62 values.capacity().saturating_mul(size_of::<T>())
63}
64
65#[must_use]
67pub fn strings(values: &Vec<String>) -> usize {
68 values.iter().fold(vector(values), |total, text| {
69 total.saturating_add(text.capacity())
70 })
71}
72
73#[must_use]
79pub fn entries<K, V>(len: usize) -> usize {
80 len.saturating_mul(size_of::<K>().saturating_add(size_of::<V>()))
81}
82
83#[cfg(test)]
84mod tests {
85 use roaring::RoaringBitmap;
86
87 use super::{bitmap, bitmaps, entries, strings, vector};
88
89 #[test]
90 fn an_empty_bitmap_holds_nothing() {
91 assert_eq!(bitmap(&RoaringBitmap::new()), 0);
92 }
93
94 #[test]
95 fn a_sparse_bitmap_costs_two_bytes_a_value_and_one_container() {
96 let set: RoaringBitmap = (0..100).collect();
97 assert!(bitmap(&set) >= 200 + 40, "{}", bitmap(&set));
99 assert!(bitmap(&set) < 1024, "{}", bitmap(&set));
100 }
101
102 #[test]
103 fn a_dense_bitmap_costs_a_bitset_container() {
104 let set: RoaringBitmap = (0..20_000).collect();
105 assert_eq!(bitmap(&set), 8192 + 40);
108 }
109
110 #[test]
111 fn a_list_of_bitmaps_carries_its_own_vector() {
112 let sets = vec![RoaringBitmap::new(), RoaringBitmap::new()];
113 assert_eq!(bitmaps(&sets), 2 * size_of::<RoaringBitmap>());
114 }
115
116 #[test]
117 fn a_vector_is_counted_at_its_capacity() {
118 let mut values: Vec<u32> = Vec::with_capacity(16);
119 values.push(1);
120 assert_eq!(vector(&values), 64);
121 }
122
123 #[test]
124 fn strings_carry_their_text() {
125 let values = vec![String::from("abcd")];
126 assert_eq!(strings(&values), vector(&values) + 4);
127 }
128
129 #[test]
130 fn map_entries_are_counted_at_their_own_width() {
131 assert_eq!(entries::<u64, u32>(10), 10 * (8 + 4));
132 }
133}