use crate::compat;
pub(super) struct DictDecoder {
hist: Vec<u8>,
wr_pos: usize, rd_pos: usize, full: bool,
stash_start_pos: usize,
stash_end_pos: usize,
}
impl DictDecoder {
pub fn new(size: usize, dict: &[u8]) -> Self {
let mut hist = vec![0; size];
let min_size = size.min(dict.len());
hist[0..min_size].copy_from_slice(&dict[0..min_size]);
let mut wr_pos = min_size;
let mut full = false;
if wr_pos == size {
wr_pos = 0;
full = true;
}
Self {
hist,
wr_pos,
rd_pos: wr_pos,
full,
stash_start_pos: 0,
stash_end_pos: 0,
}
}
pub(super) fn hist_size(&self) -> usize {
if self.full {
return self.hist.len();
}
self.wr_pos
}
pub fn avail_read(&self) -> usize {
self.wr_pos - self.rd_pos
}
pub fn avail_write(&self) -> usize {
self.hist.len() - self.wr_pos
}
pub(super) fn write_slice(&mut self, max_len: usize) -> &mut [u8] {
let len = self.avail_write().min(max_len);
&mut self.hist[self.wr_pos..self.wr_pos + len]
}
pub(super) fn write_mark(&mut self, cnt: usize) {
self.wr_pos += cnt
}
pub(super) fn write_byte(&mut self, c: u8) {
self.hist[self.wr_pos] = c;
self.wr_pos += 1;
}
pub(super) fn write_copy(&mut self, dist: usize, length: usize) -> usize {
let dst_base = self.wr_pos;
let mut dst_pos = dst_base;
let mut src_pos = dst_pos as isize - dist as isize;
let mut end_pos = dst_pos + length;
if end_pos > self.hist.len() {
end_pos = self.hist.len();
}
if src_pos < 0 {
src_pos += self.hist.len() as isize;
let size1 = end_pos - dst_pos;
let size2 = self.hist.len() - src_pos as usize;
let size = size1.min(size2);
let start = src_pos as usize;
self.hist.copy_within(start..start + size, dst_pos);
dst_pos += size;
src_pos = 0;
}
let src_pos = src_pos as usize;
while dst_pos < end_pos {
let size1 = dst_pos - src_pos;
let size2 = end_pos - dst_pos;
let size = size1.min(size2);
self.hist.copy_within(src_pos..src_pos + size, dst_pos);
dst_pos += size;
}
self.wr_pos = dst_pos;
dst_pos - dst_base
}
pub(super) fn try_write_copy(&mut self, dist: usize, length: usize) -> usize {
let mut dst_pos = self.wr_pos;
let end_pos = dst_pos + length;
if dst_pos < dist || end_pos > self.hist.len() {
return 0;
}
let dst_base = dst_pos;
let src_pos = dst_pos - dist;
while dst_pos < end_pos {
let size1 = dst_pos - src_pos;
let size2 = end_pos - dst_pos;
let size = size1.min(size2);
self.hist.copy_within(src_pos..src_pos + size, dst_pos);
dst_pos += size;
}
self.wr_pos = dst_pos;
dst_pos - dst_base
}
#[allow(dead_code)]
pub(super) fn read_flush(&mut self) -> &[u8] {
let to_read = &self.hist[self.rd_pos..self.wr_pos];
self.rd_pos = self.wr_pos;
if self.wr_pos == self.hist.len() {
self.wr_pos = 0;
self.rd_pos = 0;
self.full = true;
}
to_read
}
pub(super) fn stash_flush(&mut self) {
self.stash_start_pos = self.rd_pos;
self.stash_end_pos = self.wr_pos;
self.rd_pos = self.wr_pos;
if self.wr_pos == self.hist.len() {
self.wr_pos = 0;
self.rd_pos = 0;
self.full = true;
}
}
pub(super) fn stash_len(&self) -> usize {
self.stash_end_pos - self.stash_start_pos
}
pub(super) fn stash_read(&mut self, b: &mut [u8]) -> usize {
let n = compat::copy(b, &self.hist[self.stash_start_pos..self.stash_end_pos]);
self.stash_start_pos += n;
n
}
}