pub(super) fn plio_encode(values: &[i64], npix: usize) -> Vec<i16> {
let mut ll: Vec<i16> = vec![0, 7, -100, 0, 0, 0, 0];
if npix == 0 {
return ll;
}
let pix = |i1: usize| values.get(i1 - 1).copied().unwrap_or(0).max(0);
let xs = 1usize;
let xe = xs + npix - 1;
let mut pv = pix(xs);
let mut x1 = xs as i64;
let mut iz = xs as i64;
let mut hi: i64 = 1;
let mut nv: i64 = 0;
for ip in xs..=xe {
let mut flush = true;
if ip < xe {
nv = pix(ip + 1);
if nv == pv {
flush = false; } else if pv == 0 {
pv = nv;
x1 = (ip + 1) as i64;
flush = false;
}
} else if pv == 0 {
x1 = xe as i64 + 1;
}
if flush {
let mut np = ip as i64 - x1 + 1; let mut nz = x1 - iz; let mut done = false;
if pv > 0 {
let dv = pv - hi; if dv != 0 {
hi = pv;
if dv.abs() > 4095 {
ll.push(((pv & 4095) + 4096) as i16);
ll.push((pv / 4096) as i16);
} else {
ll.push(if dv < 0 {
(-dv + 12288) as i16
} else {
(dv + 8192) as i16
});
if np == 1 && nz == 0 {
let last = ll.last_mut().unwrap();
*last |= 16384;
done = true;
}
}
}
}
if !done && nz > 0 {
while nz > 0 {
ll.push(nz.min(4095) as i16);
nz -= 4095;
}
if np == 1 && pv > 0 {
let last = ll.last_mut().unwrap();
*last = (*last as i64 + 20481) as i16;
done = true;
}
}
if !done {
while np > 0 {
ll.push((np.min(4095) + 16384) as i16); np -= 4095;
}
}
x1 = (ip + 1) as i64;
iz = x1;
pv = nv;
}
}
let total = ll.len();
ll[3] = (total % 32768) as i16;
ll[4] = (total / 32768) as i16;
ll
}
pub(super) fn plio_decode_into(ll: &[i16], npix: usize, px: &mut Vec<i64>) {
px.clear();
px.resize(npix, 0);
if npix == 0 {
return;
}
let v3 = ll.get(2).copied().unwrap_or(0) as i32;
let (lllen, llfirst) = if v3 > 0 {
(v3 as usize, 4usize)
} else {
let lo = ll.get(3).copied().unwrap_or(0) as u16 as usize;
let hi = ll.get(4).copied().unwrap_or(0) as u16 as usize;
let start = ll.get(1).copied().unwrap_or(0) as u16 as usize + 1;
((hi << 15) + lo, start)
};
if lllen == 0 {
return;
}
let xe = npix as i64; let mut skip_word = false;
let mut op = 1i64; let mut x1 = 1i64; let mut pv = 1i64; let mut ip = llfirst;
while ip <= lllen {
if skip_word {
skip_word = false;
ip += 1;
continue;
}
let Some(&word) = ll.get(ip - 1) else { break };
let word = word as u16 as i64;
let opcode = word >> 12;
let data = word & 4095;
match opcode {
0 | 4 | 5 => {
let x2 = x1 + data - 1;
let i2 = x2.min(xe);
let np = i2 - x1 + 1;
if np > 0 {
let otop = op + np - 1;
if opcode == 4 {
for i in op..=otop {
px[(i - 1) as usize] = pv;
}
} else if opcode == 5 && i2 == x2 {
px[(otop - 1) as usize] = pv;
}
op = otop + 1;
}
x1 = x2 + 1;
}
1 => {
let next = ll.get(ip).copied().unwrap_or(0) as u16 as i64;
pv = (next << 12) + data;
skip_word = true;
}
2 => pv += data,
3 => pv -= data,
6 => {
pv += data;
if x1 <= xe {
px[(op - 1) as usize] = pv;
op += 1;
}
x1 += 1;
}
7 => {
pv -= data;
if x1 <= xe {
px[(op - 1) as usize] = pv;
op += 1;
}
x1 += 1;
}
_ => {}
}
if x1 > xe {
break;
}
ip += 1;
}
}