summaryrefslogtreecommitdiffstats
path: root/src/common/bitpacker.rs
diff options
context:
space:
mode:
authorPaul Masurel <paul.masurel@gmail.com>2017-05-15 22:30:18 +0900
committerPaul Masurel <paul.masurel@gmail.com>2017-05-15 22:30:18 +0900
commit4c8f9742f882dd1366f4130ac11a5ce4a786180f (patch)
treeaf07264eadf34f1dd55898e90ff23388734324f9 /src/common/bitpacker.rs
parenta23b7a181541f00d0a8b437af8617951526d23a6 (diff)
format
Diffstat (limited to 'src/common/bitpacker.rs')
-rw-r--r--src/common/bitpacker.rs81
1 files changed, 33 insertions, 48 deletions
diff --git a/src/common/bitpacker.rs b/src/common/bitpacker.rs
index f765a39..e16df39 100644
--- a/src/common/bitpacker.rs
+++ b/src/common/bitpacker.rs
@@ -6,19 +6,19 @@ use std::mem;
/// Computes the number of bits that will be used for bitpacking.
///
-/// In general the target is the minimum number of bits
+/// In general the target is the minimum number of bits
/// required to express the amplitude given in argument.
///
/// e.g. If the amplitude is 10, we can store all ints on simply 4bits.
-///
+///
/// The logic is slightly more convoluted here as for optimization
/// reasons, we want to ensure that a value spawns over at most 8 bytes
/// of aligns bytes.
-///
-/// Spawning over 9 bytes is possible for instance, if we do
+///
+/// Spawning over 9 bytes is possible for instance, if we do
/// bitpacking with an amplitude of 63 bits.
/// In this case, the second int will start on bit
-/// 63 (which belongs to byte 7) and ends at byte 15;
+/// 63 (which belongs to byte 7) and ends at byte 15;
/// Hence 9 bytes (from byte 7 to byte 15 included).
///
/// To avoid this, we force the number of bits to 64bits
@@ -30,12 +30,7 @@ use std::mem;
/// number of bits.
pub fn compute_num_bits(amplitude: u64) -> u8 {
let amplitude = (64u32 - amplitude.leading_zeros()) as u8;
- if amplitude <= 64 - 8 {
- amplitude
- }
- else {
- 64
- }
+ if amplitude <= 64 - 8 { amplitude } else { 64 }
}
pub struct BitPacker {
@@ -46,7 +41,6 @@ pub struct BitPacker {
}
impl BitPacker {
-
pub fn new(num_bits: usize) -> BitPacker {
BitPacker {
mini_buffer: 0u64,
@@ -55,7 +49,7 @@ impl BitPacker {
written_size: 0,
}
}
-
+
pub fn write<TWrite: Write>(&mut self, val: u64, output: &mut TWrite) -> io::Result<()> {
let val_u64 = val as u64;
if self.mini_buffer_written + self.num_bits > 64 {
@@ -63,30 +57,29 @@ impl BitPacker {
self.written_size += self.mini_buffer.serialize(output)?;
self.mini_buffer = val_u64.wrapping_shr((64 - self.mini_buffer_written) as u32);
self.mini_buffer_written = self.mini_buffer_written + (self.num_bits as usize) - 64;
- }
- else {
+ } else {
self.mini_buffer |= val_u64 << self.mini_buffer_written;
self.mini_buffer_written += self.num_bits;
if self.mini_buffer_written == 64 {
self.written_size += self.mini_buffer.serialize(output)?;
self.mini_buffer_written = 0;
self.mini_buffer = 0u64;
- }
+ }
}
Ok(())
}
-
- fn flush<TWrite: Write>(&mut self, output: &mut TWrite) -> io::Result<()>{
+
+ fn flush<TWrite: Write>(&mut self, output: &mut TWrite) -> io::Result<()> {
if self.mini_buffer_written > 0 {
let num_bytes = (self.mini_buffer_written + 7) / 8;
- let arr: [u8; 8] = unsafe { mem::transmute::<u64, [u8; 8]>(self.mini_buffer) };
+ let arr: [u8; 8] = unsafe { mem::transmute::<u64, [u8; 8]>(self.mini_buffer) };
output.write_all(&arr[..num_bytes])?;
self.written_size += num_bytes;
self.mini_buffer_written = 0;
}
Ok(())
}
-
+
pub fn close<TWrite: Write>(&mut self, output: &mut TWrite) -> io::Result<usize> {
self.flush(output)?;
Ok(self.written_size)
@@ -99,26 +92,24 @@ pub struct BitUnpacker {
num_bits: usize,
mask: u64,
data_ptr: *const u8,
- data_len: usize,
+ data_len: usize,
}
impl BitUnpacker {
pub fn new(data: &[u8], num_bits: usize) -> BitUnpacker {
- let mask: u64 =
- if num_bits == 64 {
- !0u64
- }
- else {
- (1u64 << num_bits) - 1u64
- };
+ let mask: u64 = if num_bits == 64 {
+ !0u64
+ } else {
+ (1u64 << num_bits) - 1u64
+ };
BitUnpacker {
num_bits: num_bits,
mask: mask,
data_ptr: data.as_ptr(),
- data_len: data.len()
+ data_len: data.len(),
}
}
-
+
pub fn get(&self, idx: usize) -> u64 {
if self.num_bits == 0 {
return 0;
@@ -127,13 +118,13 @@ impl BitUnpacker {
let bit_shift = idx * self.num_bits - addr * 8;
let val_unshifted_unmasked: u64;
if addr + 8 <= self.data_len {
- val_unshifted_unmasked = unsafe { * (self.data_ptr.offset(addr as isize) as *const u64) };
- }
- else {
+ val_unshifted_unmasked =
+ unsafe { *(self.data_ptr.offset(addr as isize) as *const u64) };
+ } else {
let mut arr = [0u8; 8];
if addr < self.data_len {
for i in 0..self.data_len - addr {
- arr[i] = unsafe { *self.data_ptr.offset( (addr + i) as isize) };
+ arr[i] = unsafe { *self.data_ptr.offset((addr + i) as isize) };
}
}
val_unshifted_unmasked = unsafe { mem::transmute::<[u8; 8], u64>(arr) };
@@ -141,7 +132,6 @@ impl BitUnpacker {
let val_shifted = (val_unshifted_unmasked >> bit_shift) as u64;
(val_shifted & self.mask)
}
-
}
@@ -150,7 +140,7 @@ impl BitUnpacker {
#[cfg(test)]
mod test {
use super::{BitPacker, BitUnpacker, compute_num_bits};
-
+
#[test]
fn test_compute_num_bits() {
assert_eq!(compute_num_bits(1), 1u8);
@@ -162,31 +152,26 @@ mod test {
assert_eq!(compute_num_bits(256), 9u8);
assert_eq!(compute_num_bits(5_000_000_000), 33u8);
}
-
+
fn test_bitpacker_util(len: usize, num_bits: usize) {
let mut data = Vec::new();
let mut bitpacker = BitPacker::new(num_bits);
let max_val: u64 = (1 << num_bits) - 1;
- let vals: Vec<u64> = (0u64..len as u64).map(|i| {
- if max_val == 0 {
- 0
- }
- else {
- i % max_val
- }
- }).collect();
+ let vals: Vec<u64> = (0u64..len as u64)
+ .map(|i| if max_val == 0 { 0 } else { i % max_val })
+ .collect();
for &val in &vals {
bitpacker.write(val, &mut data).unwrap();
}
let num_bytes = bitpacker.close(&mut data).unwrap();
- assert_eq!(num_bytes, (num_bits * len + 7) / 8);
+ assert_eq!(num_bytes, (num_bits * len + 7) / 8);
assert_eq!(data.len(), num_bytes);
let bitunpacker = BitUnpacker::new(&data, num_bits);
for (i, val) in vals.iter().enumerate() {
assert_eq!(bitunpacker.get(i), *val);
}
}
-
+
#[test]
fn test_bitpacker() {
test_bitpacker_util(10, 3);
@@ -195,4 +180,4 @@ mod test {
test_bitpacker_util(6, 14);
test_bitpacker_util(1000, 14);
}
-} \ No newline at end of file
+}