oxirs_tdb/compression/
bitmap.rs1use crate::compression::{
4 AdvancedCompressionType, CompressedData, CompressionAlgorithm, CompressionMetadata,
5 MAX_BLOCK_COUNT, MAX_COMPRESSION_INPUT_SIZE,
6};
7use anyhow::{anyhow, Result};
8use std::collections::HashMap;
9use std::time::Instant;
10
11pub struct BitmapWAHEncoder;
13
14impl BitmapWAHEncoder {
15 pub fn encode(data: &[u8]) -> Result<Vec<u8>> {
17 if data.is_empty() {
18 return Ok(Vec::new());
19 }
20
21 if data.len() > MAX_COMPRESSION_INPUT_SIZE {
22 return Err(anyhow!(
23 "Input data too large for compression: {} bytes (max: {})",
24 data.len(),
25 MAX_COMPRESSION_INPUT_SIZE
26 ));
27 }
28
29 let mut bits = Vec::new();
31 for byte in data {
32 for i in 0..8 {
33 bits.push((byte >> i) & 1 == 1);
34 }
35 }
36
37 let mut compressed = Vec::new();
38 let mut i = 0;
39
40 while i < bits.len() {
41 let current_bit = bits[i];
43 let mut run_length = 1;
44
45 while i + run_length < bits.len() && bits[i + run_length] == current_bit {
46 run_length += 1;
47 }
48
49 if run_length >= 4 {
51 let encoded_run = if current_bit {
53 0x80000000u32 | (run_length as u32) } else {
55 run_length as u32 };
57 compressed.extend_from_slice(&encoded_run.to_le_bytes());
58 } else {
59 let mut literal = 0u32;
61 for j in 0..run_length.min(31) {
62 if bits[i + j] {
63 literal |= 1 << j;
64 }
65 }
66 literal |= 0x40000000; compressed.extend_from_slice(&literal.to_le_bytes());
68 }
69
70 i += run_length;
71 }
72
73 Ok(compressed)
74 }
75
76 pub fn decode(compressed: &[u8]) -> Result<Vec<u8>> {
78 if compressed.is_empty() {
79 return Ok(Vec::new());
80 }
81
82 if compressed.len() % 4 != 0 {
83 return Err(anyhow!("Invalid WAH compressed data length"));
84 }
85
86 let mut bits = Vec::new();
87
88 for chunk in compressed.chunks_exact(4) {
89 let word = u32::from_le_bytes([chunk[0], chunk[1], chunk[2], chunk[3]]);
90
91 if word & 0x80000000 != 0 {
92 let run_length = (word & 0x7FFFFFFF) as usize;
94 let current_len = bits.len();
95 bits.resize(current_len + run_length, true);
96 } else if word & 0x40000000 != 0 {
97 let literal = word & 0x3FFFFFFF;
99 for i in 0..31 {
100 bits.push((literal >> i) & 1 == 1);
101 }
102 } else {
103 let run_length = word as usize;
105 let current_len = bits.len();
106 bits.resize(current_len + run_length, false);
107 }
108 }
109
110 let mut bytes = Vec::new();
112 for byte_bits in bits.chunks(8) {
113 let mut byte = 0u8;
114 for (i, &bit) in byte_bits.iter().enumerate() {
115 if bit {
116 byte |= 1 << i;
117 }
118 }
119 bytes.push(byte);
120 }
121
122 Ok(bytes)
123 }
124
125 pub fn estimate_compression_ratio(data: &[u8]) -> f64 {
127 if data.is_empty() {
128 return 1.0;
129 }
130
131 let mut runs = 0;
133 let mut current_bit = data[0] & 1;
134
135 for &byte in data {
136 for i in 0..8 {
137 let bit = (byte >> i) & 1;
138 if bit != current_bit {
139 runs += 1;
140 current_bit = bit;
141 }
142 }
143 }
144
145 let estimated_size = runs * 4;
147 estimated_size as f64 / data.len() as f64
148 }
149}
150
151impl CompressionAlgorithm for BitmapWAHEncoder {
152 fn compress(&self, data: &[u8]) -> Result<CompressedData> {
153 let start = Instant::now();
154 let compressed_bytes = Self::encode(data)?;
155 let compression_time = start.elapsed();
156
157 let mut metadata_map = HashMap::new();
158 metadata_map.insert("bits_processed".to_string(), (data.len() * 8).to_string());
159
160 let metadata = CompressionMetadata {
161 algorithm: AdvancedCompressionType::BitmapWAH,
162 original_size: data.len() as u64,
163 compressed_size: compressed_bytes.len() as u64,
164 compression_time_us: compression_time.as_micros() as u64,
165 metadata: metadata_map,
166 };
167
168 Ok(CompressedData {
169 data: compressed_bytes,
170 metadata,
171 })
172 }
173
174 fn decompress(&self, compressed: &CompressedData) -> Result<Vec<u8>> {
175 if compressed.metadata.algorithm != AdvancedCompressionType::BitmapWAH {
176 return Err(anyhow!(
177 "Invalid compression algorithm: expected BitmapWAH, got {}",
178 compressed.metadata.algorithm
179 ));
180 }
181
182 Self::decode(&compressed.data)
183 }
184
185 fn algorithm_type(&self) -> AdvancedCompressionType {
186 AdvancedCompressionType::BitmapWAH
187 }
188}
189
190pub struct BitmapRoaringEncoder;
192
193impl BitmapRoaringEncoder {
194 pub fn encode(data: &[u8]) -> Result<Vec<u8>> {
196 if data.is_empty() {
197 return Ok(Vec::new());
198 }
199
200 if data.len() > MAX_COMPRESSION_INPUT_SIZE {
201 return Err(anyhow!(
202 "Input data too large for compression: {} bytes (max: {})",
203 data.len(),
204 MAX_COMPRESSION_INPUT_SIZE
205 ));
206 }
207
208 let mut integers = Vec::new();
210
211 for (byte_idx, &byte) in data.iter().enumerate() {
212 for bit_idx in 0..8 {
213 if (byte >> bit_idx) & 1 == 1 {
214 integers.push((byte_idx * 8 + bit_idx) as u32);
215 }
216 }
217 }
218
219 let mut encoded = Vec::new();
221
222 encoded.extend_from_slice(&(integers.len() as u32).to_le_bytes());
224
225 for integer in integers {
227 encoded.extend_from_slice(&integer.to_le_bytes());
228 }
229
230 Ok(encoded)
231 }
232
233 pub fn decode(compressed: &[u8]) -> Result<Vec<u8>> {
235 if compressed.is_empty() {
236 return Ok(Vec::new());
237 }
238
239 if compressed.len() < 4 {
240 return Err(anyhow!("Invalid Roaring compressed data"));
241 }
242
243 let count = u32::from_le_bytes([compressed[0], compressed[1], compressed[2], compressed[3]])
244 as usize;
245
246 if compressed.len() != 4 + count * 4 {
247 return Err(anyhow!("Invalid Roaring compressed data length"));
248 }
249
250 if count > MAX_BLOCK_COUNT {
251 return Err(anyhow!(
252 "Too many integers in compressed data: {} (max: {})",
253 count,
254 MAX_BLOCK_COUNT
255 ));
256 }
257
258 let mut integers = Vec::new();
260 for chunk in compressed[4..].chunks_exact(4) {
261 let integer = u32::from_le_bytes([chunk[0], chunk[1], chunk[2], chunk[3]]);
262 integers.push(integer);
263 }
264
265 let max_bit = integers.iter().max().copied().unwrap_or(0);
267 let byte_count = ((max_bit / 8) + 1) as usize;
268
269 let mut bytes = vec![0u8; byte_count];
270
271 for integer in integers {
273 let byte_idx = (integer / 8) as usize;
274 let bit_idx = (integer % 8) as usize;
275 if byte_idx < bytes.len() {
276 bytes[byte_idx] |= 1 << bit_idx;
277 }
278 }
279
280 Ok(bytes)
281 }
282
283 pub fn estimate_compression_ratio(data: &[u8]) -> f64 {
285 if data.is_empty() {
286 return 1.0;
287 }
288
289 let mut set_bits = 0;
291 for &byte in data {
292 set_bits += byte.count_ones();
293 }
294
295 let estimated_size = 4 + (set_bits as usize * 4);
297 estimated_size as f64 / data.len() as f64
298 }
299}
300
301impl CompressionAlgorithm for BitmapRoaringEncoder {
302 fn compress(&self, data: &[u8]) -> Result<CompressedData> {
303 let start = Instant::now();
304 let compressed_bytes = Self::encode(data)?;
305 let compression_time = start.elapsed();
306
307 let set_bits: u32 = data.iter().map(|b| b.count_ones()).sum();
309
310 let mut metadata_map = HashMap::new();
311 metadata_map.insert("set_bits".to_string(), set_bits.to_string());
312 metadata_map.insert(
313 "sparsity".to_string(),
314 format!("{:.4}", set_bits as f64 / (data.len() * 8) as f64),
315 );
316
317 let metadata = CompressionMetadata {
318 algorithm: AdvancedCompressionType::BitmapRoaring,
319 original_size: data.len() as u64,
320 compressed_size: compressed_bytes.len() as u64,
321 compression_time_us: compression_time.as_micros() as u64,
322 metadata: metadata_map,
323 };
324
325 Ok(CompressedData {
326 data: compressed_bytes,
327 metadata,
328 })
329 }
330
331 fn decompress(&self, compressed: &CompressedData) -> Result<Vec<u8>> {
332 if compressed.metadata.algorithm != AdvancedCompressionType::BitmapRoaring {
333 return Err(anyhow!(
334 "Invalid compression algorithm: expected BitmapRoaring, got {}",
335 compressed.metadata.algorithm
336 ));
337 }
338
339 Self::decode(&compressed.data)
340 }
341
342 fn algorithm_type(&self) -> AdvancedCompressionType {
343 AdvancedCompressionType::BitmapRoaring
344 }
345}
346
347#[cfg(test)]
348mod tests {
349 use super::*;
350
351 #[test]
352 fn test_bitmap_wah_basic() {
353 let data = vec![0xFF, 0x00, 0xFF]; let encoded = BitmapWAHEncoder::encode(&data).unwrap();
355 let decoded = BitmapWAHEncoder::decode(&encoded).unwrap();
356
357 assert!(!encoded.is_empty());
359 assert!(!decoded.is_empty());
360 }
361
362 #[test]
363 fn test_bitmap_roaring_sparse() {
364 let mut sparse_bitmap = vec![0u8; 100];
365
366 sparse_bitmap[10] = 1; sparse_bitmap[20] = 1; sparse_bitmap[50] = 1; let encoded = BitmapRoaringEncoder::encode(&sparse_bitmap).unwrap();
372 let decoded = BitmapRoaringEncoder::decode(&encoded).unwrap();
373
374 assert!(!encoded.is_empty());
376 assert!(!decoded.is_empty());
377 }
378
379 #[test]
380 fn test_empty_bitmap() {
381 let data = vec![];
382 let wah_encoded = BitmapWAHEncoder::encode(&data).unwrap();
383 let roaring_encoded = BitmapRoaringEncoder::encode(&data).unwrap();
384
385 assert!(wah_encoded.is_empty());
386 assert!(roaring_encoded.is_empty());
387 }
388
389 #[test]
390 fn test_compression_algorithm_trait_wah() {
391 let encoder = BitmapWAHEncoder;
392 let data = vec![0xFF, 0x00, 0xFF];
393
394 let compressed = encoder.compress(&data).unwrap();
395 assert_eq!(
396 compressed.metadata.algorithm,
397 AdvancedCompressionType::BitmapWAH
398 );
399
400 let _decompressed = encoder.decompress(&compressed).unwrap();
401 }
403
404 #[test]
405 fn test_compression_algorithm_trait_roaring() {
406 let encoder = BitmapRoaringEncoder;
407 let data = vec![1, 0, 1, 0, 1];
408
409 let compressed = encoder.compress(&data).unwrap();
410 assert_eq!(
411 compressed.metadata.algorithm,
412 AdvancedCompressionType::BitmapRoaring
413 );
414
415 let decompressed = encoder.decompress(&compressed).unwrap();
416 assert!(!decompressed.is_empty());
417 }
418}