diff --git a/benches/fastpfor_benchmark.rs b/benches/fastpfor_benchmark.rs index 46a2408..bc173e6 100644 --- a/benches/fastpfor_benchmark.rs +++ b/benches/fastpfor_benchmark.rs @@ -1,10 +1,12 @@ use core::ops::Range; +use std::hint::black_box; +use std::io::Cursor; +use std::num::NonZeroU32; + use criterion::{criterion_group, criterion_main, BenchmarkId, Criterion, Throughput}; use fastpfor::rust::{FastPFOR, Integer, BLOCK_SIZE_128, BLOCK_SIZE_256, DEFAULT_PAGE_SIZE}; use rand::rngs::StdRng; use rand::{RngExt as _, SeedableRng}; -use std::hint::black_box; -use std::io::Cursor; const SIZES: &[usize; 2] = &[1024, 4096]; const SEED: u64 = 456; @@ -92,7 +94,7 @@ fn compress_data(codec: &mut FastPFOR, data: &[u32]) -> usize { } /// Helper function to compress data and return compressed buffer -fn prepare_compressed_data(data: &[u32], block_size: u32) -> Vec { +fn prepare_compressed_data(data: &[u32], block_size: NonZeroU32) -> Vec { let mut codec = FastPFOR::new(DEFAULT_PAGE_SIZE, block_size); let mut compressed = vec![0u32; data.len() * 2]; let mut input_offset = Cursor::new(0); diff --git a/src/rust/integer_compression/fastpfor.rs b/src/rust/integer_compression/fastpfor.rs index 8dca93b..cedc49b 100644 --- a/src/rust/integer_compression/fastpfor.rs +++ b/src/rust/integer_compression/fastpfor.rs @@ -1,20 +1,21 @@ use std::io::Cursor; +use std::num::NonZeroU32; use crate::rust::cursor::IncrementCursor; use crate::rust::integer_compression::{bitpacking, helpers}; use crate::rust::{bytebuffer, FastPForResult, Integer, Skippable}; /// Block size constant for 256 integers per block -pub const BLOCK_SIZE_256: u32 = 256; +pub const BLOCK_SIZE_256: NonZeroU32 = NonZeroU32::new(256).unwrap(); /// Block size constant for 128 integers per block -pub const BLOCK_SIZE_128: u32 = 128; +pub const BLOCK_SIZE_128: NonZeroU32 = NonZeroU32::new(128).unwrap(); /// Overhead cost (in bits) for storing each exception's position in the block const OVERHEAD_OF_EACH_EXCEPT: u32 = 8; /// Default page size in number of integers -pub const DEFAULT_PAGE_SIZE: u32 = 65536; +pub const DEFAULT_PAGE_SIZE: NonZeroU32 = NonZeroU32::new(65536).unwrap(); /// Fast Patched Frame-of-Reference ([`FastPFOR`](https://github.com/lemire/FastPFor)) integer compression codec. /// @@ -73,7 +74,7 @@ impl Skippable for FastPFOR { output_offset: &mut Cursor, num: u32, ) -> FastPForResult<()> { - if inlength == 0 && self.block_size == BLOCK_SIZE_128 { + if inlength == 0 && self.block_size == BLOCK_SIZE_128.get() { // Return early if there is no data to uncompress and block size is 128 return Ok(()); } @@ -142,7 +143,9 @@ impl FastPFOR { /// Creates codec with specified page and block sizes. /// /// Pre-allocates buffers for metadata and exception storage. - pub fn new(page_size: u32, block_size: u32) -> FastPFOR { + pub fn new(page_size: NonZeroU32, block_size: NonZeroU32) -> FastPFOR { + let page_size = page_size.get(); + let block_size = block_size.get(); FastPFOR { page_size, block_size, @@ -450,7 +453,7 @@ mod tests { fn fastpfor_test() { let mut codec1 = FastPFOR::default(); let mut codec2 = FastPFOR::default(); - let mut data = vec![0u32; BLOCK_SIZE_256 as usize]; + let mut data = vec![0u32; BLOCK_SIZE_256.get() as usize]; data[126] = -1i32 as u32; let mut out_buf = vec![0; data.len() * 4]; let mut input_offset = Cursor::new(0); @@ -480,7 +483,9 @@ mod tests { .unwrap(); let answer = out_buf_uncomp[..output_offset.position() as usize].to_vec(); - for k in 0..BLOCK_SIZE_256 { + assert_eq!(answer.len(), BLOCK_SIZE_256.get() as usize); + assert_eq!(data.len(), BLOCK_SIZE_256.get() as usize); + for k in 0..BLOCK_SIZE_256.get() { assert_eq!(answer[k as usize], data[k as usize], "bug in {k}"); } } @@ -489,10 +494,7 @@ mod tests { fn fastpfor_test_128() { let mut codec1 = FastPFOR::new(DEFAULT_PAGE_SIZE, BLOCK_SIZE_128); let mut codec2 = FastPFOR::new(DEFAULT_PAGE_SIZE, BLOCK_SIZE_128); - let mut data = vec![0; BLOCK_SIZE_128 as usize]; - for i in 0..BLOCK_SIZE_128 { - data[i as usize] = 0; - } + let mut data = vec![0; BLOCK_SIZE_128.get() as usize]; data[126] = -1i32 as u32; let mut out_buf = vec![0; data.len() * 4]; let mut input_offset = Cursor::new(0); @@ -522,7 +524,9 @@ mod tests { .unwrap(); let answer = out_buf_uncomp[..output_offset.position() as usize].to_vec(); - for k in 0..BLOCK_SIZE_128 { + assert_eq!(answer.len(), BLOCK_SIZE_128.get() as usize); + assert_eq!(data.len(), BLOCK_SIZE_128.get() as usize); + for k in 0..BLOCK_SIZE_128.get() { assert_eq!(answer[k as usize], data[k as usize], "bug in {k}"); } } diff --git a/tests/basic_tests.rs b/tests/basic_tests.rs index 5139b66..43f19b2 100644 --- a/tests/basic_tests.rs +++ b/tests/basic_tests.rs @@ -2,6 +2,7 @@ #![allow(clippy::needless_range_loop)] use std::io::Cursor; +use std::num::NonZeroU32; use fastpfor::rust::{ fast_pack, fast_unpack, Composition, FastPFOR, Integer, VariableByte, BLOCK_SIZE_128, @@ -381,10 +382,10 @@ fn test_random_numbers() { #[test] fn test_fastpfor_headless_compress_unfit_pagesize() { // The input size is a multiple of 128 but does not fit the page size - let test_input_size = 512 + BLOCK_SIZE_128; - let page_size = 512; + let test_input_size = BLOCK_SIZE_128.checked_add(512).unwrap(); + let page_size = NonZeroU32::new(512).unwrap(); - let input: Vec = (0..test_input_size).collect(); + let input: Vec = (0..test_input_size.get()).collect(); let mut output: Vec = vec![0; input.len()]; let mut decoded: Vec = vec![0; input.len()]; let mut input_offset = Cursor::new(0u32); @@ -419,8 +420,8 @@ fn test_fastpfor_headless_compress_unfit_pagesize() { #[test] fn test_exception_value_vector_resizes() { - let page_size = 512; - let test_input_size = page_size * 2; + let page_size = NonZeroU32::new(512).unwrap(); + let test_input_size = page_size.get() * 2; // every even index value is large which will trigger exception buffer to be resize let input: Vec = (0..test_input_size) diff --git a/tests/cpp_compat_tests.rs b/tests/cpp_compat_tests.rs index c85fec3..2f0a046 100644 --- a/tests/cpp_compat_tests.rs +++ b/tests/cpp_compat_tests.rs @@ -15,7 +15,7 @@ fn test_rust_decompresses_cpp_encoded_data() { let mut codec_rs = rust::FastPFOR::new(rust::DEFAULT_PAGE_SIZE, rust::BLOCK_SIZE_128); for n in test_input_sizes() { - for input in get_test_cases(n + rust::BLOCK_SIZE_128 as usize) { + for input in get_test_cases(n + rust::BLOCK_SIZE_128.get() as usize) { // Buffer for the C++ encoded let mut compressed_buffer = vec![0; input.len()]; @@ -58,7 +58,7 @@ fn test_rust_and_cpp_fastpfor32_compression_matches() { let mut codec_rs = rust::FastPFOR::new(rust::DEFAULT_PAGE_SIZE, rust::BLOCK_SIZE_128); for n in test_input_sizes() { - for input in get_test_cases(n + rust::BLOCK_SIZE_128 as usize) { + for input in get_test_cases(n + rust::BLOCK_SIZE_128.get() as usize) { // Buffer for the C++ encoded let mut compressed_buffer = vec![0; input.len()];