use std::{
cmp,
mem::{size_of, transmute_copy},
};
use errors::{ParquetError, Result};
use util::{bit_packing::unpack32, memory::ByteBufferPtr};
macro_rules! read_num_bytes {
($ty:ty, $size:expr, $src:expr) => {{
assert!($size <= $src.len());
let mut data: $ty = Default::default();
unsafe {
::std::ptr::copy_nonoverlapping(
$src.as_ptr(),
&mut data as *mut $ty as *mut u8,
$size,
);
}
data
}};
}
#[inline]
pub fn convert_to_bytes<T>(val: &T, num_bytes: usize) -> Vec<u8> {
let mut bytes: Vec<u8> = vec![0; num_bytes];
memcpy_value(val, num_bytes, &mut bytes);
bytes
}
#[inline]
pub fn memcpy(source: &[u8], target: &mut [u8]) {
assert!(target.len() >= source.len());
unsafe {
::std::ptr::copy_nonoverlapping(source.as_ptr(), target.as_mut_ptr(), source.len())
}
}
#[inline]
pub fn memcpy_value<T>(source: &T, num_bytes: usize, target: &mut [u8]) {
assert!(
target.len() >= num_bytes,
"Not enough space. Only had {} bytes but need to put {} bytes",
target.len(),
num_bytes
);
unsafe {
::std::ptr::copy_nonoverlapping(
source as *const T as *const u8,
target.as_mut_ptr(),
num_bytes,
)
}
}
#[inline]
pub fn ceil(value: i64, divisor: i64) -> i64 {
let mut result = value / divisor;
if value % divisor != 0 {
result += 1
};
result
}
#[inline]
pub fn log2(mut x: u64) -> i32 {
if x == 1 {
return 0;
}
x -= 1;
let mut result = 0;
while x > 0 {
x >>= 1;
result += 1;
}
result
}
#[inline]
pub fn trailing_bits(v: u64, num_bits: usize) -> u64 {
if num_bits == 0 {
return 0;
}
if num_bits >= 64 {
return v;
}
let n = 64 - num_bits;
(v << n) >> n
}
#[inline]
pub fn set_array_bit(bits: &mut [u8], i: usize) { bits[i / 8] |= 1 << (i % 8); }
#[inline]
pub fn unset_array_bit(bits: &mut [u8], i: usize) { bits[i / 8] &= !(1 << (i % 8)); }
#[inline]
pub fn num_required_bits(x: u64) -> usize {
for i in (0..64).rev() {
if x & (1u64 << i) != 0 {
return i + 1;
}
}
0
}
pub struct BitWriter {
buffer: Vec<u8>,
max_bytes: usize,
buffered_values: u64,
byte_offset: usize,
bit_offset: usize,
start: usize,
}
impl BitWriter {
pub fn new(max_bytes: usize) -> Self {
Self {
buffer: vec![0; max_bytes],
max_bytes,
buffered_values: 0,
byte_offset: 0,
bit_offset: 0,
start: 0,
}
}
pub fn new_from_buf(buffer: Vec<u8>, start: usize) -> Self {
assert!(start < buffer.len());
let len = buffer.len();
Self {
buffer,
max_bytes: len,
buffered_values: 0,
byte_offset: start,
bit_offset: 0,
start,
}
}
#[inline]
pub fn consume(mut self) -> Vec<u8> {
self.flush();
self.buffer.truncate(self.byte_offset);
self.buffer
}
#[inline]
pub fn flush_buffer(&mut self) -> &[u8] {
self.flush();
&self.buffer()[0..self.byte_offset]
}
#[inline]
pub fn clear(&mut self) {
self.buffered_values = 0;
self.byte_offset = self.start;
self.bit_offset = 0;
}
#[inline]
pub fn flush(&mut self) {
let num_bytes = ceil(self.bit_offset as i64, 8) as usize;
assert!(self.byte_offset + num_bytes <= self.max_bytes);
memcpy_value(
&self.buffered_values,
num_bytes,
&mut self.buffer[self.byte_offset..],
);
self.buffered_values = 0;
self.bit_offset = 0;
self.byte_offset += num_bytes;
}
#[inline]
pub fn skip(&mut self, num_bytes: usize) -> Result<usize> {
self.flush();
assert!(self.byte_offset <= self.max_bytes);
if self.byte_offset + num_bytes > self.max_bytes {
return Err(general_err!(
"Not enough bytes left in BitWriter. Need {} but only have {}",
self.byte_offset + num_bytes,
self.max_bytes
));
}
let result = self.byte_offset;
self.byte_offset += num_bytes;
Ok(result)
}
#[inline]
pub fn get_next_byte_ptr(&mut self, num_bytes: usize) -> Result<&mut [u8]> {
let offset = self.skip(num_bytes)?;
Ok(&mut self.buffer[offset..offset + num_bytes])
}
#[inline]
pub fn bytes_written(&self) -> usize {
self.byte_offset - self.start + ceil(self.bit_offset as i64, 8) as usize
}
#[inline]
pub fn buffer(&self) -> &[u8] { &self.buffer[self.start..] }
#[inline]
pub fn byte_offset(&self) -> usize { self.byte_offset }
#[inline]
pub fn buffer_len(&self) -> usize { self.max_bytes }
#[inline]
pub fn put_value(&mut self, v: u64, num_bits: usize) -> bool {
assert!(num_bits <= 64);
assert_eq!(v.checked_shr(num_bits as u32).unwrap_or(0), 0);
if self.byte_offset * 8 + self.bit_offset + num_bits > self.max_bytes as usize * 8 {
return false;
}
self.buffered_values |= v << self.bit_offset;
self.bit_offset += num_bits;
if self.bit_offset >= 64 {
memcpy_value(
&self.buffered_values,
8,
&mut self.buffer[self.byte_offset..],
);
self.byte_offset += 8;
self.bit_offset -= 64;
self.buffered_values = 0;
self.buffered_values = v
.checked_shr((num_bits - self.bit_offset) as u32)
.unwrap_or(0);
}
assert!(self.bit_offset < 64);
true
}
#[inline]
pub fn put_aligned<T: Copy>(&mut self, val: T, num_bytes: usize) -> bool {
let result = self.get_next_byte_ptr(num_bytes);
if result.is_err() {
return false;
}
let mut ptr = result.unwrap();
memcpy_value(&val, num_bytes, &mut ptr);
true
}
#[inline]
pub fn put_aligned_offset<T: Copy>(
&mut self,
val: T,
num_bytes: usize,
offset: usize,
) -> bool
{
if num_bytes + offset > self.max_bytes {
return false;
}
memcpy_value(
&val,
num_bytes,
&mut self.buffer[offset..offset + num_bytes],
);
true
}
#[inline]
pub fn put_vlq_int(&mut self, mut v: u64) -> bool {
let mut result = true;
while v & 0xFFFFFFFFFFFFFF80 != 0 {
result &= self.put_aligned::<u8>(((v & 0x7F) | 0x80) as u8, 1);
v >>= 7;
}
result &= self.put_aligned::<u8>((v & 0x7F) as u8, 1);
result
}
#[inline]
pub fn put_zigzag_vlq_int(&mut self, v: i64) -> bool {
let u: u64 = ((v << 1) ^ (v >> 63)) as u64;
self.put_vlq_int(u)
}
}
pub const MAX_VLQ_BYTE_LEN: usize = 10;
pub struct BitReader {
buffer: ByteBufferPtr,
buffered_values: u64,
byte_offset: usize,
bit_offset: usize,
total_bytes: usize,
}
impl BitReader {
pub fn new(buffer: ByteBufferPtr) -> Self {
let total_bytes = buffer.len();
let num_bytes = cmp::min(8, total_bytes);
let buffered_values = read_num_bytes!(u64, num_bytes, buffer.as_ref());
BitReader {
buffer,
buffered_values,
byte_offset: 0,
bit_offset: 0,
total_bytes,
}
}
#[inline]
pub fn reset(&mut self, buffer: ByteBufferPtr) {
self.buffer = buffer;
self.total_bytes = self.buffer.len();
let num_bytes = cmp::min(8, self.total_bytes);
self.buffered_values = read_num_bytes!(u64, num_bytes, self.buffer.as_ref());
self.byte_offset = 0;
self.bit_offset = 0;
}
#[inline]
pub fn get_byte_offset(&self) -> usize {
self.byte_offset + ceil(self.bit_offset as i64, 8) as usize
}
#[inline]
pub fn get_value<T: Default>(&mut self, num_bits: usize) -> Option<T> {
assert!(num_bits <= 64);
assert!(num_bits <= size_of::<T>() * 8);
if self.byte_offset * 8 + self.bit_offset + num_bits > self.total_bytes * 8 {
return None;
}
let mut v =
trailing_bits(self.buffered_values, self.bit_offset + num_bits) >> self.bit_offset;
self.bit_offset += num_bits;
if self.bit_offset >= 64 {
self.byte_offset += 8;
self.bit_offset -= 64;
self.reload_buffer_values();
v |= trailing_bits(self.buffered_values, self.bit_offset)
.wrapping_shl((num_bits - self.bit_offset) as u32);
}
let result: T = unsafe { transmute_copy::<u64, T>(&v) };
Some(result)
}
#[inline]
pub fn get_batch<T: Default>(&mut self, batch: &mut [T], num_bits: usize) -> usize {
assert!(num_bits <= 32);
assert!(num_bits <= size_of::<T>() * 8);
let mut values_to_read = batch.len();
let needed_bits = num_bits * values_to_read;
let remaining_bits = (self.total_bytes - self.byte_offset) * 8 - self.bit_offset;
if remaining_bits < needed_bits {
values_to_read = remaining_bits / num_bits;
}
let mut i = 0;
if self.bit_offset != 0 {
while i < values_to_read && self.bit_offset != 0 {
batch[i] = self
.get_value(num_bits)
.expect("expected to have more data");
i += 1;
}
}
unsafe {
let in_buf = &self.buffer.data()[self.byte_offset..];
let mut in_ptr = in_buf as *const [u8] as *const u8 as *const u32;
if size_of::<T>() == 4 {
while values_to_read - i >= 32 {
let out_ptr = &mut batch[i..] as *mut [T] as *mut T as *mut u32;
in_ptr = unpack32(in_ptr, out_ptr, num_bits);
self.byte_offset += 4 * num_bits;
i += 32;
}
} else {
let mut out_buf = [0u32; 32];
let out_ptr = &mut out_buf as &mut [u32] as *mut [u32] as *mut u32;
while values_to_read - i >= 32 {
in_ptr = unpack32(in_ptr, out_ptr, num_bits);
self.byte_offset += 4 * num_bits;
for n in 0..32 {
if size_of::<T>() > size_of::<u32>() {
::std::ptr::copy_nonoverlapping(
out_buf[n..].as_ptr() as *const u32,
&mut batch[i] as *mut T as *mut u32,
1,
);
} else {
::std::ptr::copy_nonoverlapping(
out_buf[n..].as_ptr() as *const T,
&mut batch[i] as *mut T,
1,
);
}
i += 1;
}
}
}
}
assert!(values_to_read - i < 32);
self.reload_buffer_values();
while i < values_to_read {
batch[i] = self
.get_value(num_bits)
.expect("expected to have more data");
i += 1;
}
values_to_read
}
#[inline]
pub fn get_aligned<T: Default>(&mut self, num_bytes: usize) -> Option<T> {
let bytes_read = ceil(self.bit_offset as i64, 8) as usize;
if self.byte_offset + bytes_read + num_bytes > self.total_bytes {
return None;
}
self.byte_offset += bytes_read;
let v = read_num_bytes!(
T,
num_bytes,
self.buffer.start_from(self.byte_offset).as_ref()
);
self.byte_offset += num_bytes;
self.bit_offset = 0;
self.reload_buffer_values();
Some(v)
}
#[inline]
pub fn get_vlq_int(&mut self) -> Option<i64> {
let mut shift = 0;
let mut v: i64 = 0;
while let Some(byte) = self.get_aligned::<u8>(1) {
v |= ((byte & 0x7F) as i64) << shift;
shift += 7;
assert!(
shift <= MAX_VLQ_BYTE_LEN * 7,
"Num of bytes exceed MAX_VLQ_BYTE_LEN ({})",
MAX_VLQ_BYTE_LEN
);
if byte & 0x80 == 0 {
return Some(v);
}
}
None
}
#[inline]
pub fn get_zigzag_vlq_int(&mut self) -> Option<i64> {
self.get_vlq_int().map(|v| {
let u = v as u64;
((u >> 1) as i64 ^ -((u & 1) as i64))
})
}
#[inline]
fn reload_buffer_values(&mut self) {
let bytes_to_read = cmp::min(self.total_bytes - self.byte_offset, 8);
self.buffered_values = read_num_bytes!(
u64,
bytes_to_read,
self.buffer.start_from(self.byte_offset).as_ref()
);
}
}
impl From<Vec<u8>> for BitReader {
#[inline]
fn from(buffer: Vec<u8>) -> Self { BitReader::new(ByteBufferPtr::new(buffer)) }
}
#[cfg(test)]
mod tests {
use std::fmt::Debug;
use super::{
super::{memory::ByteBufferPtr, test_common::*},
*,
};
use rand::distributions::{Distribution, Standard};
#[test]
fn test_ceil() {
assert_eq!(ceil(0, 1), 0);
assert_eq!(ceil(1, 1), 1);
assert_eq!(ceil(1, 2), 1);
assert_eq!(ceil(1, 8), 1);
assert_eq!(ceil(7, 8), 1);
assert_eq!(ceil(8, 8), 1);
assert_eq!(ceil(9, 8), 2);
assert_eq!(ceil(9, 9), 1);
assert_eq!(ceil(10000000000, 10), 1000000000);
assert_eq!(ceil(10, 10000000000), 1);
assert_eq!(ceil(10000000000, 1000000000), 10);
}
#[test]
fn test_bit_reader_get_byte_offset() {
let buffer = vec![255; 10];
let mut bit_reader = BitReader::from(buffer);
assert_eq!(bit_reader.get_byte_offset(), 0);
bit_reader.get_value::<i32>(6);
assert_eq!(bit_reader.get_byte_offset(), 1);
bit_reader.get_value::<i32>(10);
assert_eq!(bit_reader.get_byte_offset(), 2);
bit_reader.get_value::<i32>(20);
assert_eq!(bit_reader.get_byte_offset(), 5);
bit_reader.get_value::<i32>(30);
assert_eq!(bit_reader.get_byte_offset(), 9);
}
#[test]
fn test_bit_reader_get_value() {
let buffer = vec![255, 0];
let mut bit_reader = BitReader::from(buffer);
assert_eq!(bit_reader.get_value::<i32>(1), Some(1));
assert_eq!(bit_reader.get_value::<i32>(2), Some(3));
assert_eq!(bit_reader.get_value::<i32>(3), Some(7));
assert_eq!(bit_reader.get_value::<i32>(4), Some(3));
}
#[test]
fn test_bit_reader_get_value_boundary() {
let buffer = vec![10, 0, 0, 0, 20, 0, 30, 0, 0, 0, 40, 0];
let mut bit_reader = BitReader::from(buffer);
assert_eq!(bit_reader.get_value::<i64>(32), Some(10));
assert_eq!(bit_reader.get_value::<i64>(16), Some(20));
assert_eq!(bit_reader.get_value::<i64>(32), Some(30));
assert_eq!(bit_reader.get_value::<i64>(16), Some(40));
}
#[test]
fn test_bit_reader_get_aligned() {
let buffer = ByteBufferPtr::new(vec![0x75, 0xCB]);
let mut bit_reader = BitReader::new(buffer.all());
assert_eq!(bit_reader.get_value::<i32>(3), Some(5));
assert_eq!(bit_reader.get_aligned::<i32>(1), Some(203));
assert_eq!(bit_reader.get_value::<i32>(1), None);
bit_reader.reset(buffer.all());
assert_eq!(bit_reader.get_aligned::<i32>(3), None);
}
#[test]
fn test_bit_reader_get_vlq_int() {
let buffer: Vec<u8> = vec![0x89, 0x01, 0xF2, 0xB5, 0x06];
let mut bit_reader = BitReader::from(buffer);
assert_eq!(bit_reader.get_vlq_int(), Some(137));
assert_eq!(bit_reader.get_vlq_int(), Some(105202));
}
#[test]
fn test_bit_reader_get_zigzag_vlq_int() {
let buffer: Vec<u8> = vec![0, 1, 2, 3];
let mut bit_reader = BitReader::from(buffer);
assert_eq!(bit_reader.get_zigzag_vlq_int(), Some(0));
assert_eq!(bit_reader.get_zigzag_vlq_int(), Some(-1));
assert_eq!(bit_reader.get_zigzag_vlq_int(), Some(1));
assert_eq!(bit_reader.get_zigzag_vlq_int(), Some(-2));
}
#[test]
fn test_set_array_bit() {
let mut buffer = vec![0, 0, 0];
set_array_bit(&mut buffer[..], 1);
assert_eq!(buffer, vec![2, 0, 0]);
set_array_bit(&mut buffer[..], 4);
assert_eq!(buffer, vec![18, 0, 0]);
unset_array_bit(&mut buffer[..], 1);
assert_eq!(buffer, vec![16, 0, 0]);
set_array_bit(&mut buffer[..], 10);
assert_eq!(buffer, vec![16, 4, 0]);
set_array_bit(&mut buffer[..], 10);
assert_eq!(buffer, vec![16, 4, 0]);
set_array_bit(&mut buffer[..], 11);
assert_eq!(buffer, vec![16, 12, 0]);
unset_array_bit(&mut buffer[..], 10);
assert_eq!(buffer, vec![16, 8, 0]);
}
#[test]
fn test_num_required_bits() {
assert_eq!(num_required_bits(0), 0);
assert_eq!(num_required_bits(1), 1);
assert_eq!(num_required_bits(2), 2);
assert_eq!(num_required_bits(4), 3);
assert_eq!(num_required_bits(8), 4);
assert_eq!(num_required_bits(10), 4);
assert_eq!(num_required_bits(12), 4);
assert_eq!(num_required_bits(16), 5);
}
#[test]
fn test_log2() {
assert_eq!(log2(1), 0);
assert_eq!(log2(2), 1);
assert_eq!(log2(3), 2);
assert_eq!(log2(4), 2);
assert_eq!(log2(5), 3);
assert_eq!(log2(5), 3);
assert_eq!(log2(6), 3);
assert_eq!(log2(7), 3);
assert_eq!(log2(8), 3);
assert_eq!(log2(9), 4);
}
#[test]
fn test_skip() {
let mut writer = BitWriter::new(5);
let old_offset = writer.skip(1).expect("skip() should return OK");
writer.put_aligned(42, 4);
writer.put_aligned_offset(0x10, 1, old_offset);
let result = writer.consume();
assert_eq!(result.as_ref(), [0x10, 42, 0, 0, 0]);
writer = BitWriter::new(4);
let result = writer.skip(5);
assert!(result.is_err());
}
#[test]
fn test_get_next_byte_ptr() {
let mut writer = BitWriter::new(5);
{
let first_byte = writer
.get_next_byte_ptr(1)
.expect("get_next_byte_ptr() should return OK");
first_byte[0] = 0x10;
}
writer.put_aligned(42, 4);
let result = writer.consume();
assert_eq!(result.as_ref(), [0x10, 42, 0, 0, 0]);
}
#[test]
fn test_consume_flush_buffer() {
let mut writer1 = BitWriter::new(3);
let mut writer2 = BitWriter::new(3);
for i in 1..10 {
writer1.put_value(i, 4);
writer2.put_value(i, 4);
}
let res1 = writer1.flush_buffer();
let res2 = writer2.consume();
assert_eq!(res1, &res2[..]);
}
#[test]
fn test_put_get_bool() {
let len = 8;
let mut writer = BitWriter::new(len);
for i in 0..8 {
let result = writer.put_value(i % 2, 1);
assert!(result);
}
writer.flush();
{
let buffer = writer.buffer();
assert_eq!(buffer[0], 0b10101010);
}
for i in 0..8 {
let result = match i {
0 | 1 | 4 | 5 => writer.put_value(false as u64, 1),
_ => writer.put_value(true as u64, 1),
};
assert!(result);
}
writer.flush();
{
let buffer = writer.buffer();
assert_eq!(buffer[0], 0b10101010);
assert_eq!(buffer[1], 0b11001100);
}
let mut reader = BitReader::from(writer.consume());
for i in 0..8 {
let val = reader
.get_value::<u8>(1)
.expect("get_value() should return OK");
assert_eq!(val, i % 2);
}
for i in 0..8 {
let val = reader
.get_value::<bool>(1)
.expect("get_value() should return OK");
match i {
0 | 1 | 4 | 5 => assert_eq!(val, false),
_ => assert_eq!(val, true),
}
}
}
#[test]
fn test_put_value_roundtrip() {
test_put_value_rand_numbers(32, 2);
test_put_value_rand_numbers(32, 3);
test_put_value_rand_numbers(32, 4);
test_put_value_rand_numbers(32, 5);
test_put_value_rand_numbers(32, 6);
test_put_value_rand_numbers(32, 7);
test_put_value_rand_numbers(32, 8);
test_put_value_rand_numbers(64, 16);
test_put_value_rand_numbers(64, 24);
test_put_value_rand_numbers(64, 32);
}
fn test_put_value_rand_numbers(total: usize, num_bits: usize) {
assert!(num_bits < 64);
let num_bytes = ceil(num_bits as i64, 8);
let mut writer = BitWriter::new(num_bytes as usize * total);
let values: Vec<u64> = random_numbers::<u64>(total)
.iter()
.map(|v| v & ((1 << num_bits) - 1))
.collect();
for i in 0..total {
assert!(
writer.put_value(values[i] as u64, num_bits),
"[{}]: put_value() failed",
i
);
}
let mut reader = BitReader::from(writer.consume());
for i in 0..total {
let v = reader
.get_value::<u64>(num_bits)
.expect("get_value() should return OK");
assert_eq!(
v, values[i],
"[{}]: expected {} but got {}",
i, values[i], v
);
}
}
#[test]
fn test_get_batch() {
const SIZE: &[usize] = &[1, 31, 32, 33, 128, 129];
for s in SIZE {
for i in 0..33 {
match i {
0...8 => test_get_batch_helper::<u8>(*s, i),
9...16 => test_get_batch_helper::<u16>(*s, i),
_ => test_get_batch_helper::<u32>(*s, i),
}
}
}
}
fn test_get_batch_helper<T>(total: usize, num_bits: usize)
where T: Default + Clone + Debug + Eq {
assert!(num_bits <= 32);
let num_bytes = ceil(num_bits as i64, 8);
let mut writer = BitWriter::new(num_bytes as usize * total);
let values: Vec<u32> = random_numbers::<u32>(total)
.iter()
.map(|v| v & ((1u64 << num_bits) - 1) as u32)
.collect();
let expected_values: Vec<T> = values
.iter()
.map(|v| unsafe { transmute_copy::<u32, T>(&v) })
.collect();
for i in 0..total {
assert!(writer.put_value(values[i] as u64, num_bits));
}
let buf = writer.consume();
let mut reader = BitReader::from(buf);
let mut batch = vec![T::default(); values.len()];
let values_read = reader.get_batch::<T>(&mut batch, num_bits);
assert_eq!(values_read, values.len());
for i in 0..batch.len() {
assert_eq!(
batch[i], expected_values[i],
"num_bits = {}, index = {}",
num_bits, i
);
}
}
#[test]
fn test_put_aligned_roundtrip() {
test_put_aligned_rand_numbers::<u8>(4, 3);
test_put_aligned_rand_numbers::<u8>(16, 5);
test_put_aligned_rand_numbers::<i16>(32, 7);
test_put_aligned_rand_numbers::<i16>(32, 9);
test_put_aligned_rand_numbers::<i32>(32, 11);
test_put_aligned_rand_numbers::<i32>(32, 13);
test_put_aligned_rand_numbers::<i64>(32, 17);
test_put_aligned_rand_numbers::<i64>(32, 23);
}
fn test_put_aligned_rand_numbers<T>(total: usize, num_bits: usize)
where
T: Copy + Default + Debug + PartialEq,
Standard: Distribution<T>, {
assert!(num_bits <= 32);
assert!(total % 2 == 0);
let aligned_value_byte_width = ::std::mem::size_of::<T>();
let value_byte_width = ceil(num_bits as i64, 8) as usize;
let mut writer =
BitWriter::new((total / 2) * (aligned_value_byte_width + value_byte_width));
let values: Vec<u32> = random_numbers::<u32>(total / 2)
.iter()
.map(|v| v & ((1 << num_bits) - 1))
.collect();
let aligned_values = random_numbers::<T>(total / 2);
for i in 0..total {
let j = i / 2;
if i % 2 == 0 {
assert!(
writer.put_value(values[j] as u64, num_bits),
"[{}]: put_value() failed",
i
);
} else {
assert!(
writer.put_aligned::<T>(aligned_values[j], aligned_value_byte_width),
"[{}]: put_aligned() failed",
i
);
}
}
let mut reader = BitReader::from(writer.consume());
for i in 0..total {
let j = i / 2;
if i % 2 == 0 {
let v = reader
.get_value::<u64>(num_bits)
.expect("get_value() should return OK");
assert_eq!(
v, values[j] as u64,
"[{}]: expected {} but got {}",
i, values[j], v
);
} else {
let v = reader
.get_aligned::<T>(aligned_value_byte_width)
.expect("get_aligned() should return OK");
assert_eq!(
v, aligned_values[j],
"[{}]: expected {:?} but got {:?}",
i, aligned_values[j], v
);
}
}
}
#[test]
fn test_put_vlq_int() {
let total = 64;
let mut writer = BitWriter::new(total * 32);
let values = random_numbers::<u32>(total);
for i in 0..total {
assert!(
writer.put_vlq_int(values[i] as u64),
"[{}]; put_vlq_int() failed",
i
);
}
let mut reader = BitReader::from(writer.consume());
for i in 0..total {
let v = reader
.get_vlq_int()
.expect("get_vlq_int() should return OK");
assert_eq!(
v as u32, values[i],
"[{}]: expected {} but got {}",
i, values[i], v
);
}
}
#[test]
fn test_put_zigzag_vlq_int() {
let total = 64;
let mut writer = BitWriter::new(total * 32);
let values = random_numbers::<i32>(total);
for i in 0..total {
assert!(
writer.put_zigzag_vlq_int(values[i] as i64),
"[{}]; put_zigzag_vlq_int() failed",
i
);
}
let mut reader = BitReader::from(writer.consume());
for i in 0..total {
let v = reader
.get_zigzag_vlq_int()
.expect("get_zigzag_vlq_int() should return OK");
assert_eq!(
v as i32, values[i],
"[{}]: expected {} but got {}",
i, values[i], v
);
}
}
}