const CHUNK_LOG: usize = 26; const CHUNK_LEN: usize = 1 << CHUNK_LOG;
const CHUNK_MASK: usize = CHUNK_LEN - 1;
#[derive(Default)]
pub struct ChunkU32 {
chunks: Vec<Vec<u32>>,
}
impl ChunkU32 {
#[allow(dead_code)]
pub fn is_empty(&self) -> bool {
self.chunks.is_empty()
}
#[cfg(test)]
pub fn from_vec(v: Vec<u32>) -> Self {
let mut c = Self::zeroed(v.len());
for (i, &x) in v.iter().enumerate() {
c.set(i, x);
}
c
}
pub fn zeroed(len: usize) -> Self {
let nchunks = len.div_ceil(CHUNK_LEN);
let mut chunks = Vec::with_capacity(nchunks);
let mut remaining = len;
for _ in 0..nchunks {
let this = remaining.min(CHUNK_LEN);
chunks.push(vec![0u32; this]);
remaining -= this;
}
ChunkU32 { chunks }
}
#[inline(always)]
pub fn set(&mut self, idx: usize, val: u32) {
let c = idx >> CHUNK_LOG;
let o = idx & CHUNK_MASK;
self.chunks[c][o] = val;
}
#[inline(always)]
pub fn get(&self, idx: usize) -> u32 {
let c = idx >> CHUNK_LOG;
let o = idx & CHUNK_MASK;
self.chunks[c][o]
}
pub fn free_below(&mut self, boundary: usize) {
let last_chunk = boundary >> CHUNK_LOG; for c in 0..last_chunk {
if !self.chunks[c].is_empty() {
#[cfg(target_os = "linux")]
{
let chunk = &self.chunks[c];
let ptr = chunk.as_ptr() as *mut libc::c_void;
let len = chunk.len() * std::mem::size_of::<u32>();
unsafe {
libc::madvise(ptr, len, libc::MADV_DONTNEED);
}
}
self.chunks[c] = Vec::new();
}
}
}
pub fn copy_range(&self, start: usize, end: usize, out: &mut Vec<u32>) {
out.clear();
let mut i = start;
while i < end {
let c = i >> CHUNK_LOG;
let o = i & CHUNK_MASK;
let chunk = &self.chunks[c];
let take = (CHUNK_LEN - o).min(end - i);
out.extend_from_slice(&chunk[o..o + take]);
i += take;
}
}
#[inline(always)]
pub fn range_slice(&self, start: usize, end: usize) -> Option<&[u32]> {
if start >= end {
return Some(&[]);
}
let c0 = start >> CHUNK_LOG;
let c1 = (end - 1) >> CHUNK_LOG;
if c0 == c1 {
let o0 = start & CHUNK_MASK;
let o1 = end & CHUNK_MASK;
let end_off = if o1 == 0 { CHUNK_LEN } else { o1 };
Some(&self.chunks[c0][o0..end_off])
} else {
None
}
}
}