use std::io::Write;
use std::path::Path;
use anyhow::{Context, Result};
use byteorder::ByteOrder;
use rayon::prelude::*;
const HEADER: &[u8] = b"\xac\xed\x00\x05sr\x00$it.unimi.dsi.bits.LongArrayBitVector\x00\x00\x00\x00\x00\x00\x00\x01\x03\x00\x01\x4a\x00\x06lengthxp";
const TC_BLOCKDATA: u8 = 0x77;
const TC_BLOCKDATALONG: u8 = 0x7A;
const TC_ENDBLOCKDATA: u8 = 0x78;
const MAX_BLOCKDATA_SIZE: usize = 256;
const DEFAULT_BLOCKDATALONG_SIZE: usize = 0x100000; pub struct LongArrayBitVector<B> {
data: B,
num_bits: usize,
}
impl LongArrayBitVector<Vec<u64>> {
pub fn new_from_bitvec(bitvec: sux::bits::bit_vec::BitVec<Vec<usize>>) -> Self {
let (vec, num_bits) = bitvec.into_raw_parts();
assert_eq!(usize::BITS, u64::BITS);
let mut vec: Vec<u64> = unsafe { std::mem::transmute(vec) };
vec.par_iter_mut()
.for_each(|cell| *cell = u64::from_be(*cell).to_le());
LongArrayBitVector {
data: vec,
num_bits,
}
}
pub fn dump<P: AsRef<Path>>(&self, path: P) -> Result<()> {
let path = path.as_ref();
let file = std::fs::File::create(path)
.with_context(|| format!("Could not create {}", path.display()))?;
let mut file = std::io::BufWriter::new(file);
file.write_all(HEADER)?;
let mut length_buf = [0u8; 8];
byteorder::BigEndian::write_u64(&mut length_buf, self.num_bits as u64);
file.write_all(&length_buf)?;
for chunk in self.data.chunks(DEFAULT_BLOCKDATALONG_SIZE / 8) {
let chunk_size = chunk.len() * 8; if chunk_size > MAX_BLOCKDATA_SIZE {
file.write_all(&[TC_BLOCKDATALONG])?;
let chunk_size: i32 = chunk_size.try_into().expect("Chunk size overflows i32");
file.write_all(&chunk_size.to_be_bytes())
.with_context(|| format!("Could not write to {}", path.display()))?;
file.write_all(bytemuck::cast_slice(chunk))
.with_context(|| format!("Could not write to {}", path.display()))?;
} else {
file.write_all(&[TC_BLOCKDATA])?;
let chunk_size: u8 = chunk_size.try_into().expect("Chunk size overflows u8");
file.write_all(&chunk_size.to_be_bytes())
.with_context(|| format!("Could not write to {}", path.display()))?;
file.write_all(bytemuck::cast_slice(chunk))
.with_context(|| format!("Could not write to {}", path.display()))?;
}
}
file.write_all(&[TC_ENDBLOCKDATA])?;
Ok(())
}
}