1use entropy_map::MapWithDict;
7use std::time::Instant;
8
9pub struct EntropyMapLookup {
11 map: MapWithDict<u32, u8>,
12}
13
14impl EntropyMapLookup {
15 pub fn new(entries: &[(u32, u8)]) -> (Self, u64) {
18 let start = Instant::now();
19
20 let map_entries: Vec<(u32, u8)> = entries.iter().copied().collect();
22
23 let map = MapWithDict::from_iter_with_params(map_entries, 2.0)
24 .map_err(|e| format!("Failed to create MapWithDict: {:?}", e))
25 .unwrap();
26 let construction_time = start.elapsed().as_nanos() as u64;
27
28 (Self { map }, construction_time)
29 }
30
31 #[inline]
33 pub fn lookup(&self, key: u32) -> u8 {
34 self.map.get(&key).copied().unwrap_or(0)
35 }
36
37 pub fn lookup_batch(&self, keys: &[u32], results: &mut [u8]) {
39 assert_eq!(keys.len(), results.len());
40 for (i, &key) in keys.iter().enumerate() {
41 results[i] = self.lookup(key);
42 }
43 }
44
45 pub fn memory_usage(&self) -> usize {
47 std::mem::size_of_val(&self.map)
50 }
51}
52
53pub struct EntropyMapBitpackedLookup {
58 map: MapWithDict<u32, u8>,
59}
60
61impl EntropyMapBitpackedLookup {
62 pub fn new(entries: &[(u32, u8)]) -> (Self, u64) {
65 let start = Instant::now();
66
67 let map_entries: Vec<(u32, u8)> = entries.iter().copied().collect();
69
70 let map = MapWithDict::from_iter_with_params(map_entries, 2.0)
71 .map_err(|e| format!("Failed to create MapWithDict: {:?}", e))
72 .unwrap();
73 let construction_time = start.elapsed().as_nanos() as u64;
74
75 (Self { map }, construction_time)
76 }
77
78 #[inline]
80 pub fn lookup(&self, key: u32) -> u8 {
81 self.map.get(&key).copied().unwrap_or(0)
82 }
83
84 pub fn lookup_batch(&self, keys: &[u32], results: &mut [u8]) {
86 assert_eq!(keys.len(), results.len());
87 for (i, &key) in keys.iter().enumerate() {
88 results[i] = self.lookup(key);
89 }
90 }
91
92 pub fn memory_usage(&self) -> usize {
94 std::mem::size_of_val(&self.map)
97 }
98}
99
100pub fn create_sparse_entries_for_entropy(size: usize, density_percent: f32) -> Vec<(u32, u8)> {
102 let num_entries = ((size as f32) * (density_percent / 100.0)) as usize;
103 let mut entries = Vec::with_capacity(num_entries);
104
105 let step = size / num_entries.max(1);
107 for i in 0..num_entries {
108 let key = (i * step) as u32;
109 let value = ((key % 255) + 1) as u8; entries.push((key, value));
111 }
112
113 entries
114}
115
116pub fn benchmark_construction_time(sizes: &[usize], density: f32) -> Vec<(usize, u64, u64)> {
118 let mut results = Vec::new();
119
120 for &size in sizes {
121 let entries = create_sparse_entries_for_entropy(size, density);
122
123 let (_, dict_time) = EntropyMapLookup::new(&entries);
125
126 let (_, bitpacked_time) = EntropyMapBitpackedLookup::new(&entries);
128
129 results.push((size, dict_time, bitpacked_time));
130
131 println!(
132 "Size: {}, Dict: {}ns, Bitpacked: {}ns",
133 size, dict_time, bitpacked_time
134 );
135 }
136
137 results
138}
139
140#[cfg(test)]
141mod tests {
142 use super::*;
143
144 fn create_test_entries() -> Vec<(u32, u8)> {
145 vec![
146 (0, 100),
147 (5, 105),
148 (10, 110),
149 (100, 200),
150 (1000, 255),
151 (10000, 42),
152 ]
153 }
154
155 #[test]
156 fn test_entropy_map_lookup() {
157 let entries = create_test_entries();
158 let (lookup, _) = EntropyMapLookup::new(&entries);
159
160 assert_eq!(lookup.lookup(0), 100);
161 assert_eq!(lookup.lookup(5), 105);
162 assert_eq!(lookup.lookup(10), 110);
163 assert_eq!(lookup.lookup(1), 0); assert_eq!(lookup.lookup(20000), 0); }
166
167 #[test]
168 fn test_entropy_map_bitpacked_lookup() {
169 let entries = create_test_entries();
170 let (lookup, _) = EntropyMapBitpackedLookup::new(&entries);
171
172 assert_eq!(lookup.lookup(0), 100);
173 assert_eq!(lookup.lookup(5), 105);
174 assert_eq!(lookup.lookup(10), 110);
175 assert_eq!(lookup.lookup(1), 0); assert_eq!(lookup.lookup(20000), 0); }
178
179 #[test]
180 fn test_batch_lookup() {
181 let entries = create_test_entries();
182 let (dict_lookup, _) = EntropyMapLookup::new(&entries);
183 let (bitpacked_lookup, _) = EntropyMapBitpackedLookup::new(&entries);
184
185 let keys = vec![0, 1, 5, 10, 15, 100, 1000, 20000];
186 let expected = vec![100, 0, 105, 110, 0, 200, 255, 0];
187
188 let mut results = vec![0u8; keys.len()];
189
190 dict_lookup.lookup_batch(&keys, &mut results);
192 assert_eq!(results, expected);
193
194 results.fill(0);
196 bitpacked_lookup.lookup_batch(&keys, &mut results);
197 assert_eq!(results, expected);
198 }
199
200 #[test]
201 fn test_construction_time_measurement() {
202 let entries = create_test_entries();
203
204 let (_, dict_time) = EntropyMapLookup::new(&entries);
205 let (_, bitpacked_time) = EntropyMapBitpackedLookup::new(&entries);
206
207 assert!(dict_time > 0);
209 assert!(bitpacked_time > 0);
210
211 println!("Dict construction: {}ns", dict_time);
212 println!("Bitpacked construction: {}ns", bitpacked_time);
213 }
214}