use crate::structures::util::read_uvarint;
const HARD_WORD_CAP: usize = 64 * 1024 * 1024;
pub fn run_gc_prog(prog: &[u8], max_words: usize) -> Vec<bool> {
let cap = max_words.min(HARD_WORD_CAP);
let mut out: Vec<bool> = Vec::new();
let mut p = 0usize;
loop {
if out.len() >= cap {
break;
}
let inst = match prog.get(p) {
Some(&b) => b,
None => break,
};
p = match p.checked_add(1) {
Some(v) => v,
None => break,
};
if inst & 0x80 == 0 {
let n = (inst & 0x7f) as usize;
if n == 0 {
break; }
for i in 0..n {
let Some(byte_idx) = p.checked_add(i.checked_div(8).unwrap_or(0)) else {
break;
};
let bit = i.checked_rem(8).unwrap_or(0);
match prog.get(byte_idx) {
Some(&byte) => out.push((byte >> bit) & 1 == 1),
None => break,
}
if out.len() >= cap {
break;
}
}
let nbytes = n.saturating_add(7).checked_div(8).unwrap_or(0);
p = match p.checked_add(nbytes) {
Some(v) => v,
None => break,
};
} else {
let mut n = (inst & 0x7f) as usize;
if n == 0 {
match read_uvarint(prog.get(p..).unwrap_or(&[])) {
Some((v, used)) => {
n = v as usize;
p = p.saturating_add(used);
}
None => break,
}
}
let c = match read_uvarint(prog.get(p..).unwrap_or(&[])) {
Some((v, used)) => {
p = p.saturating_add(used);
v as usize
}
None => break,
};
if n == 0 || n > out.len() {
break;
}
let start = out.len().saturating_sub(n);
let pattern: Vec<bool> = out.get(start..).map(<[bool]>::to_vec).unwrap_or_default();
for _ in 0..c {
if out.len() >= cap {
break;
}
out.extend_from_slice(&pattern);
}
}
}
out.truncate(max_words);
out
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct PointerMap {
pub base_va: u64,
pub ptr_size: u8,
pub words: Vec<bool>,
}
impl PointerMap {
pub fn pointer_count(&self) -> usize {
self.words.iter().filter(|&&b| b).count()
}
pub fn pointer_vas(&self) -> impl Iterator<Item = u64> + '_ {
let stride = self.ptr_size as u64;
let base = self.base_va;
self.words
.iter()
.enumerate()
.filter_map(move |(i, &is_ptr)| {
if is_ptr {
base.checked_add((i as u64).checked_mul(stride)?)
} else {
None
}
})
}
pub fn is_pointer(&self, va: u64) -> Option<bool> {
let stride = self.ptr_size as u64;
if stride == 0 {
return None;
}
let off = va.checked_sub(self.base_va)?;
if off.checked_rem(stride)? != 0 {
return None;
}
let idx = usize::try_from(off.checked_div(stride)?).ok()?;
self.words.get(idx).copied()
}
}