1use crate::encode::constants::{Q1, Q3};
2use crate::encode::MatchUnit;
3use crate::types::Idx;
4
5use std::ops::Deref;
6
7#[cfg(test)]
8use crate::encode::constants::Q2;
9
10pub const HASH_BITS: u32 = 14;
11
12pub const HASH_WIDTH: usize = 4;
14
15pub struct HistoryTable(Box<[History]>, #[cfg(test)] Ward);
16
17impl HistoryTable {
18 const SIZE: usize = 1 << HASH_BITS;
19
20 #[inline(always)]
24 pub fn push<M: MatchUnit>(&mut self, item: Item) -> History {
25 #[cfg(test)]
26 debug_assert!(self.1.push(item));
27 let queue = self.get_mut::<M>(item.val);
28 let copy = *queue;
29 queue.push(item);
30 copy
31 }
32
33 #[inline(always)]
34 fn get_mut<M: MatchUnit>(&mut self, val: u32) -> &mut History {
35 unsafe { self.0.get_unchecked_mut(index::<M>(val)) }
36 }
37
38 #[cold]
47 pub fn clamp(&mut self, idx: Idx) {
48 #[cfg(test)]
49 debug_assert!(self.1.clamp(idx));
50 self.0.iter_mut().for_each(|u| u.clamp_rebias(idx, 0));
51 }
52
53 #[cold]
62 pub fn clamp_rebias(&mut self, idx: Idx, delta: u32) {
63 #[cfg(test)]
64 debug_assert!(self.1.clamp_rebias(idx, delta));
65 self.0.iter_mut().for_each(|u| u.clamp_rebias(idx, delta));
66 }
67
68 pub fn reset(&mut self) {
73 self.reset_with_idx(Idx::Q0)
74 }
75
76 #[cold]
77 pub fn reset_with_idx(&mut self, idx: Idx) {
78 self.0.iter_mut().for_each(|u| *u = History::new(Item::new(0, idx - Q1)));
79 #[cfg(test)]
80 {
81 self.1 = Ward::new(idx);
82 }
83 }
84}
85
86impl Default for HistoryTable {
87 fn default() -> Self {
88 Self(
89 vec![History::default(); Self::SIZE].into_boxed_slice(),
90 #[cfg(test)]
91 Ward::default(),
92 )
93 }
94}
95
96#[repr(align(32))]
100#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)]
101pub struct History([Item; HASH_WIDTH]);
102
103impl History {
104 #[inline(always)]
105 const fn new(item: Item) -> Self {
106 Self([item; HASH_WIDTH])
107 }
108
109 #[inline(always)]
110 fn push(&mut self, item: Item) {
111 debug_assert!(!is_wrapping(item.idx, self.0[HASH_WIDTH - 1].idx));
112 let mut i = HASH_WIDTH - 1;
113 while i != 0 {
114 self.0[i] = self.0[i - 1];
115 i -= 1;
116 }
117 self.0[0] = item;
118 }
119
120 #[inline(always)]
121 fn clamp_rebias(&mut self, idx: Idx, delta: u32) {
122 for item in self.0.iter_mut() {
123 debug_assert!(!is_wrapping(idx, item.idx));
124 if (idx - item.idx) as u32 > Q1 {
125 item.idx = idx - Q1 - delta;
126 } else {
127 item.idx -= delta;
128 }
129 }
130 }
131}
132
133impl Deref for History {
134 type Target = [Item];
135
136 #[inline(always)]
137 fn deref(&self) -> &Self::Target {
138 &self.0
139 }
140}
141
142#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)]
143#[repr(C, align(8))]
144pub struct Item {
145 pub val: u32,
146 pub idx: Idx,
147}
148
149impl Item {
150 #[inline(always)]
151 pub const fn new(val: u32, idx: Idx) -> Self {
152 Self { val, idx }
153 }
154}
155
156#[cfg(test)]
158#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)]
159struct Ward {
160 opt_val: Option<u32>,
161 idx: Idx,
162 clamp: Idx,
163}
164
165#[cfg(test)]
172impl Ward {
173 fn new(idx: Idx) -> Self {
174 Self { opt_val: None, idx, clamp: idx + Q2 }
175 }
176
177 fn push(&mut self, item: Item) -> bool {
178 if self.idx != item.idx || self.clamp == item.idx {
179 return false;
180 }
181 if let Some(val) = self.opt_val {
182 #[cfg(target_endian = "little")]
183 if (val >> 8) != item.val & 0x00FF_FFFF {
184 return false;
185 }
186 #[cfg(target_endian = "big")]
187 if (val << 8) != item.val & 0xFFFF_FF00 {
188 return false;
189 }
190 }
191 self.opt_val = Some(item.val);
192 self.idx += 1;
193 true
194 }
195
196 fn clamp(&mut self, idx: Idx) -> bool {
197 if self.idx == idx {
198 self.clamp = idx + Q2;
199 true
200 } else {
201 false
202 }
203 }
204
205 fn clamp_rebias(&mut self, idx: Idx, delta: u32) -> bool {
206 if self.idx == idx {
207 self.idx -= delta;
208 self.clamp = idx + Q2;
209 true
210 } else {
211 false
212 }
213 }
214}
215
216fn is_wrapping(a: Idx, b: Idx) -> bool {
218 ((a - b) as u32) >= Q3
219}
220
221#[inline(always)]
222fn index<M: MatchUnit>(u: u32) -> usize {
223 (M::hash_u(u) >> (32 - HASH_BITS)) as usize
224}
225
226#[cfg(test)]
227mod tests {
228 use crate::encode::constants::{Q0, Q2};
229 use crate::encode::dummy::Dummy;
230
231 use super::*;
232
233 #[test]
234 #[should_panic]
235 fn default_warden() {
236 let mut table = HistoryTable::default();
237 table.push::<Dummy>(Item::new(0, Idx::Q0));
238 }
239
240 #[test]
241 #[ignore = "expensive"]
242 fn clamp_rebias() {
243 let mut table = HistoryTable::default();
244 table.reset_with_idx(Idx::Q0);
245 for val in 0..Q2 {
246 table.get_mut::<Dummy>(val).push(Item::new(val, val.into()));
248 table.1.idx += 1;
249 }
250 table.clamp(Idx::Q2);
251 for history in table.0.iter() {
252 for &Item { val, idx } in history.0.iter() {
253 if val <= Q1 {
254 assert_eq!(idx, Idx::Q1);
255 } else {
256 assert!(!is_wrapping(idx, Idx::Q3));
257 assert!((Idx::Q2 - idx) as u32 <= Q1);
258 }
259 }
260 }
261 }
262
263 #[test]
264 #[ignore = "expensive"]
265 fn clamp_rebias_q1() {
266 let mut table = HistoryTable::default();
267 table.reset_with_idx(Idx::Q0);
268 for val in 0..Q2 {
269 table.get_mut::<Dummy>(val).push(Item::new(val, val.into()));
271 table.1.idx += 1;
272 }
273 table.clamp_rebias(Idx::Q2, Q1);
274 for history in table.0.iter() {
275 for &Item { val, idx } in history.0.iter() {
276 if val <= Q1 {
277 assert_eq!(idx, Idx::Q0);
278 } else {
279 assert!(!is_wrapping(idx, Idx::Q3));
280 assert!((Idx::Q1 - idx) as u32 <= Q1);
281 }
282 }
283 }
284 }
285
286 #[test]
287 fn history_clamp_rebias_q0_0() {
288 let mut history = History::default();
289 history.clamp_rebias(Idx::Q0, 0);
290 assert_eq!(history, History([Item::new(0, Idx::Q0); 4]));
291 }
292
293 #[test]
294 fn history_clamp_rebias_q0_q1() {
295 let mut history = History::default();
296 history.clamp_rebias(Idx::Q0, Q1);
297 assert_eq!(history, History([Item::new(0, Idx::Q0 - Q1); 4]));
298 }
299
300 #[test]
301 fn history_clamp_rebias_q1_0() {
302 let mut history = History::default();
303 history.clamp_rebias(Idx::Q1, 0);
304 assert_eq!(history, History([Item::new(0, Idx::Q0); 4]));
305 }
306
307 #[test]
308 fn history_clamp_rebias_q1_q1() {
309 let mut history = History::default();
310 history.clamp_rebias(Idx::Q1, Q1);
311 assert_eq!(history, History([Item::new(0, Idx::Q0 - Q1); 4]));
312 }
313
314 #[test]
315 fn history_clamp_rebias_q2_0() {
316 let mut history = History::default();
317 history.clamp_rebias(Idx::Q2, 0);
318 assert_eq!(history, History([Item::new(0, Idx::Q1); 4]));
319 }
320
321 #[test]
322 fn history_clamp_rebias_q2_q1() {
323 let mut history = History::default();
324 history.clamp_rebias(Idx::Q2, Q1);
325 assert_eq!(history, History([Item::new(0, Idx::Q1 - Q1); 4]));
326 }
327
328 #[test]
329 #[should_panic]
330 fn history_clamp_rebias_q3_0() {
331 let mut history = History::default();
332 history.clamp_rebias(Idx::Q3, 0);
333 }
334
335 #[test]
336 #[should_panic]
337 fn history_clamp_rebias_q3_q1() {
338 let mut history = History::default();
339 history.clamp_rebias(Idx::Q3, Q1);
340 }
341
342 #[test]
343 #[should_panic]
344 fn history_push_q0_sub_1() {
345 History::default().push(Item::new(0, Idx::Q0 - 1));
346 }
347
348 #[test]
349 fn history_push_q0() {
350 History::default().push(Item::new(0, Idx::Q0));
351 }
352
353 #[test]
354 fn history_push_q3_sub_1() {
355 History::default().push(Item::new(0, Idx::Q3 - 1));
356 }
357
358 #[test]
359 #[should_panic]
360 fn history_push_q3() {
361 History::default().push(Item::new(0, Idx::Q3));
362 }
363
364 #[test]
365 fn is_wrapping_q0_sub_1() {
366 (0..4).map(|u| Idx::new(u * Q1)).for_each(|idx| assert!(is_wrapping(idx - Q0 - 1, idx)));
367 }
368
369 #[test]
370 fn is_wrapping_q1() {
371 (0..4).map(|u| Idx::new(u * Q1)).for_each(|idx| assert!(is_wrapping(idx - Q1, idx)));
372 }
373
374 #[test]
375 fn not_wrapping_q1_sub_1() {
376 (0..4).map(|u| Idx::new(u * Q1)).for_each(|idx| assert!(!is_wrapping(idx - Q1 - 1, idx)));
377 }
378
379 #[test]
380 fn not_is_wrapping_q0() {
381 (0..4).map(|u| Idx::new(u * Q1)).for_each(|idx| assert!(!is_wrapping(idx - Q0, idx)));
382 }
383}