diff --git a/src/decode/lzma.rs b/src/decode/lzma.rs index b705e6d..510f062 100644 --- a/src/decode/lzma.rs +++ b/src/decode/lzma.rs @@ -1,6 +1,7 @@ use crate::decode::lzbuffer::{LzBuffer, LzCircularBuffer}; use crate::decode::rangecoder; use crate::decode::rangecoder::RangeDecoder; +use crate::decode::vec2d::Vec2D; use crate::decompress::Options; use crate::decompress::UnpackedSize; use crate::error; @@ -167,8 +168,8 @@ pub(crate) struct DecoderState { partial_input_buf: std::io::Cursor<[u8; MAX_REQUIRED_INPUT]>, pub(crate) lzma_props: LzmaProperties, unpacked_size: Option, - literal_probs: Vec>, - pos_slot_decoder: Vec, + literal_probs: Vec2D, + pos_slot_decoder: [rangecoder::BitTree; 4], align_decoder: rangecoder::BitTree, pos_decoders: [u16; 115], is_match: [u16; 192], // true = LZ, false = literal @@ -190,8 +191,13 @@ impl DecoderState { partial_input_buf: std::io::Cursor::new([0; MAX_REQUIRED_INPUT]), lzma_props, unpacked_size, - literal_probs: vec![vec![0x400; 0x300]; 1 << (lzma_props.lc + lzma_props.lp)], - pos_slot_decoder: vec![rangecoder::BitTree::new(6); 4], + literal_probs: Vec2D::init(1 << (lzma_props.lc + lzma_props.lp), 0x300, 0x400), + pos_slot_decoder: [ + rangecoder::BitTree::new(6), + rangecoder::BitTree::new(6), + rangecoder::BitTree::new(6), + rangecoder::BitTree::new(6), + ], align_decoder: rangecoder::BitTree::new(4), pos_decoders: [0x400; 115], is_match: [0x400; 192], @@ -211,10 +217,10 @@ impl DecoderState { new_props.validate(); if self.lzma_props.lc + self.lzma_props.lp == new_props.lc + new_props.lp { // We can reset here by filling the existing buffer with 0x400. - self.literal_probs.iter_mut().for_each(|v| v.fill(0x400)) + self.literal_probs.fill(0x400); } else { // We need to reallocate because of the new size of `lc+lp`. - self.literal_probs = vec![vec![0x400; 0x300]; 1 << (new_props.lc + new_props.lp)]; + self.literal_probs = Vec2D::init(1 << (new_props.lc + new_props.lp), 0x300, 0x400); } self.lzma_props = new_props; diff --git a/src/decode/mod.rs b/src/decode/mod.rs index 2a7b0b8..c61a702 100644 --- a/src/decode/mod.rs +++ b/src/decode/mod.rs @@ -6,6 +6,7 @@ pub mod lzma2; pub mod options; pub mod rangecoder; pub mod util; +pub mod vec2d; pub mod xz; #[cfg(feature = "stream")] diff --git a/src/decode/rangecoder.rs b/src/decode/rangecoder.rs index 4cee3ad..52271f9 100644 --- a/src/decode/rangecoder.rs +++ b/src/decode/rangecoder.rs @@ -190,8 +190,8 @@ impl BitTree { pub struct LenDecoder { choice: u16, choice2: u16, - low_coder: Vec, - mid_coder: Vec, + low_coder: [BitTree; 16], + mid_coder: [BitTree; 16], high_coder: BitTree, } @@ -200,8 +200,42 @@ impl LenDecoder { LenDecoder { choice: 0x400, choice2: 0x400, - low_coder: vec![BitTree::new(3); 16], - mid_coder: vec![BitTree::new(3); 16], + low_coder: [ + BitTree::new(3), + BitTree::new(3), + BitTree::new(3), + BitTree::new(3), + BitTree::new(3), + BitTree::new(3), + BitTree::new(3), + BitTree::new(3), + BitTree::new(3), + BitTree::new(3), + BitTree::new(3), + BitTree::new(3), + BitTree::new(3), + BitTree::new(3), + BitTree::new(3), + BitTree::new(3), + ], + mid_coder: [ + BitTree::new(3), + BitTree::new(3), + BitTree::new(3), + BitTree::new(3), + BitTree::new(3), + BitTree::new(3), + BitTree::new(3), + BitTree::new(3), + BitTree::new(3), + BitTree::new(3), + BitTree::new(3), + BitTree::new(3), + BitTree::new(3), + BitTree::new(3), + BitTree::new(3), + BitTree::new(3), + ], high_coder: BitTree::new(8), } } diff --git a/src/decode/vec2d.rs b/src/decode/vec2d.rs new file mode 100644 index 0000000..62203cb --- /dev/null +++ b/src/decode/vec2d.rs @@ -0,0 +1,74 @@ +use std::ops::{Index, IndexMut}; + +/// A 2 dimensional matrix in row-major order backed by a contiguous `Vec` +#[derive(Debug)] +pub struct Vec2D { + data: Vec, + cols: usize, + rows: usize, +} + +impl Vec2D { + /// Initialize a grid of size `rows * cols` with the given data element. + pub fn init(rows: usize, cols: usize, data: T) -> Vec2D + where + T: Clone, + { + Vec2D { + data: vec![data; rows * cols], + cols, + rows, + } + } + + /// Fills the grid with elements by cloning `value`. + pub fn fill(&mut self, value: T) + where + T: Clone, + { + self.data.fill(value) + } +} + +impl Index for Vec2D { + type Output = [T]; + + fn index(&self, idx: usize) -> &Self::Output { + if idx < self.rows { + let start_idx = idx * self.cols; + &self.data[start_idx..start_idx + self.cols] + } else { + panic!("row index {:?} out of bounds.", idx); + } + } +} + +impl IndexMut for Vec2D { + fn index_mut(&mut self, idx: usize) -> &mut Self::Output { + &mut self.data[(idx * self.cols)..] + } +} + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn vec2d_fill() { + let mut vec2d = Vec2D::init(3, 3, 0); + vec2d.fill(7); + assert_eq!(vec2d[0], [7, 7, 7]); + assert_eq!(vec2d[1], [7, 7, 7]); + } + + #[test] + fn vec2d_index() { + let vec2d = Vec2D { + data: vec![0, 1, 2, 3, 4, 5], + rows: 3, + cols: 3, + }; + assert_eq!(vec2d[0], [0, 1, 2]); + assert_eq!(vec2d[1], [3, 4, 5]); + } +}