1use std::u16;
2
3use lzvalue::LZValue;
4use huffman_table::{NUM_LITERALS_AND_LENGTHS, NUM_DISTANCE_CODES, END_OF_BLOCK_POSITION,
5 get_distance_code, get_length_code};
6
7pub type FrequencyType = u16;
12
13pub const MAX_BUFFER_LENGTH: usize = 1024 * 31;
18
19#[derive(Debug, PartialEq)]
20pub enum BufferStatus {
21 NotFull,
22 Full,
23}
24
25pub struct DynamicWriter {
27 buffer: Vec<LZValue>,
28 frequencies: [FrequencyType; NUM_LITERALS_AND_LENGTHS],
31 distance_frequencies: [FrequencyType; NUM_DISTANCE_CODES],
32}
33
34impl DynamicWriter {
35 #[inline]
36 pub fn check_buffer_length(&self) -> BufferStatus {
37 if self.buffer.len() >= MAX_BUFFER_LENGTH {
38 BufferStatus::Full
39 } else {
40 BufferStatus::NotFull
41 }
42 }
43
44 #[inline]
45 pub fn write_literal(&mut self, literal: u8) -> BufferStatus {
46 debug_assert!(self.buffer.len() < MAX_BUFFER_LENGTH);
47 self.buffer.push(LZValue::literal(literal));
48 self.frequencies[usize::from(literal)] += 1;
49 self.check_buffer_length()
50 }
51
52 #[inline]
53 pub fn write_length_distance(&mut self, length: u16, distance: u16) -> BufferStatus {
54 self.buffer.push(LZValue::length_distance(length, distance));
55 let l_code_num = get_length_code(length);
56 if cfg!(debug_assertions) {
58 self.frequencies[l_code_num] += 1;
59 } else {
60 unsafe {
65 *self.frequencies.get_unchecked_mut(l_code_num) += 1;
66 }
67 }
68 let d_code_num = get_distance_code(distance);
69 self.distance_frequencies[usize::from(d_code_num)] += 1;
71 self.check_buffer_length()
72 }
73
74 pub fn buffer_length(&self) -> usize {
75 self.buffer.len()
76 }
77
78 pub fn get_buffer(&self) -> &[LZValue] {
79 &self.buffer
80 }
81
82 pub fn new() -> DynamicWriter {
83 let mut w = DynamicWriter {
84 buffer: Vec::with_capacity(MAX_BUFFER_LENGTH),
85 frequencies: [0; NUM_LITERALS_AND_LENGTHS],
86 distance_frequencies: [0; NUM_DISTANCE_CODES],
87 };
88 w.frequencies[END_OF_BLOCK_POSITION] = 1;
91 w
92 }
93
94 #[inline]
97 pub fn write_length_rle(&mut self, length: u16) -> BufferStatus {
98 self.buffer.push(LZValue::length_distance(length, 1));
99 let l_code_num = get_length_code(length);
100 if cfg!(debug_assertions) {
102 self.frequencies[l_code_num] += 1;
103 } else {
104 unsafe {
109 *self.frequencies.get_unchecked_mut(l_code_num) += 1;
110 }
111 }
112 self.distance_frequencies[0] += 1;
113 self.check_buffer_length()
114 }
115
116 pub fn get_frequencies(&self) -> (&[u16], &[u16]) {
117 (&self.frequencies, &self.distance_frequencies)
118 }
119
120 pub fn clear_frequencies(&mut self) {
121 self.frequencies = [0; NUM_LITERALS_AND_LENGTHS];
122 self.distance_frequencies = [0; NUM_DISTANCE_CODES];
123 self.frequencies[END_OF_BLOCK_POSITION] = 1;
124 }
125
126 pub fn clear_data(&mut self) {
127 self.buffer.clear()
128 }
129
130 pub fn clear(&mut self) {
131 self.clear_frequencies();
132 self.clear_data();
133 }
134}
135
136#[cfg(test)]
137mod test {
138 use super::*;
139 use huffman_table::{get_length_code, get_distance_code};
140 #[test]
141 fn array_bounds() {
144 let w = DynamicWriter::new();
145
146 for i in 0..u16::max_value() {
147 get_length_code(i) < w.frequencies.len();
148 }
149
150 for i in 0..u16::max_value() {
151 get_distance_code(i) < w.distance_frequencies.len() as u8;
152 }
153 }
154}