1use alloc::{Allocator, SliceWrapper, SliceWrapperMut};
2use core;
3
4use super::histogram;
5pub use super::input_pair::{InputPair, InputReference, InputReferenceMut};
6
7#[derive(Debug, Copy, Clone, Default)]
8pub struct BlockSwitch(pub u8);
9
10pub trait Nop<T> {
12 fn nop() -> T;
13}
14
15impl BlockSwitch {
16 #[inline(always)]
17 pub fn new(block_type: u8) -> Self {
18 BlockSwitch(block_type)
19 }
20 #[inline(always)]
21 pub fn block_type(&self) -> u8 {
22 self.0
23 }
24}
25
26#[derive(Debug, Copy, Clone, Default)]
27pub struct LiteralBlockSwitch(pub BlockSwitch, pub u8);
28
29impl LiteralBlockSwitch {
30 pub fn new(block_type: u8, stride: u8) -> Self {
31 LiteralBlockSwitch(BlockSwitch::new(block_type), stride)
32 }
33 #[inline(always)]
34 pub fn block_type(&self) -> u8 {
35 self.0.block_type()
36 }
37 #[inline(always)]
38 pub fn stride(&self) -> u8 {
39 self.1
40 }
41 #[inline(always)]
42 pub fn update_stride(&mut self, new_stride: u8) {
43 self.1 = new_stride;
44 }
45}
46
47pub const LITERAL_PREDICTION_MODE_SIGN: u8 = 3;
48pub const LITERAL_PREDICTION_MODE_UTF8: u8 = 2;
49pub const LITERAL_PREDICTION_MODE_MSB6: u8 = 1;
50pub const LITERAL_PREDICTION_MODE_LSB6: u8 = 0;
51
52#[derive(Default, Copy, Clone, Debug, PartialEq, Eq, Hash)]
53pub struct LiteralPredictionModeNibble(pub u8);
54
55impl LiteralPredictionModeNibble {
56 #[inline(always)]
57 pub fn new(prediction_mode: u8) -> Result<Self, ()> {
58 if prediction_mode < 16 {
59 return Ok(LiteralPredictionModeNibble(prediction_mode));
60 }
61 Err(())
62 }
63 #[inline(always)]
64 pub fn prediction_mode(&self) -> u8 {
65 self.0
66 }
67 #[inline(always)]
68 pub fn signed() -> Self {
69 LiteralPredictionModeNibble(LITERAL_PREDICTION_MODE_SIGN)
70 }
71 #[inline(always)]
72 pub fn utf8() -> Self {
73 LiteralPredictionModeNibble(LITERAL_PREDICTION_MODE_UTF8)
74 }
75 #[inline(always)]
76 pub fn msb6() -> Self {
77 LiteralPredictionModeNibble(LITERAL_PREDICTION_MODE_MSB6)
78 }
79 #[inline(always)]
80 pub fn lsb6() -> Self {
81 LiteralPredictionModeNibble(LITERAL_PREDICTION_MODE_LSB6)
82 }
83 #[inline(always)]
84 pub fn to_context_enum(&self) -> Result<histogram::ContextType, ()> {
85 match self.0 {
86 LITERAL_PREDICTION_MODE_LSB6 => Ok(histogram::ContextType::CONTEXT_LSB6),
87 LITERAL_PREDICTION_MODE_MSB6 => Ok(histogram::ContextType::CONTEXT_MSB6),
88 LITERAL_PREDICTION_MODE_UTF8 => Ok(histogram::ContextType::CONTEXT_UTF8),
89 LITERAL_PREDICTION_MODE_SIGN => Ok(histogram::ContextType::CONTEXT_SIGNED),
90 _ => Err(()),
91 }
92 }
93}
94pub const NUM_SPEED_VALUES: usize = 12;
95pub const NUM_MIXING_VALUES: usize = 16 * 256 + 16 * 256;
96pub const NUM_PREDMODE_SETUP_VALUES: usize = 4;
97pub const RESERVED_OFFSET: usize = 3;
98pub const ADV_CONTEXT_MAP_OFFSET: usize = 2;
99pub const MIXING_MATH_OFFSET: usize = 1;
100pub const PREDMODE_OFFSET: usize = 0;
101pub const MIXING_OFFSET: usize = NUM_PREDMODE_SETUP_VALUES + PREDMODE_OFFSET;
102pub const SPEED_OFFSET: usize = MIXING_OFFSET + NUM_MIXING_VALUES;
103pub const DISTANCE_CONTEXT_MAP_OFFSET: usize = SPEED_OFFSET + NUM_SPEED_VALUES;
104pub const MAX_PREDMODE_SPEED_AND_DISTANCE_CONTEXT_MAP_SIZE: usize =
105 DISTANCE_CONTEXT_MAP_OFFSET + 256 * 4;
106pub const MAX_LITERAL_CONTEXT_MAP_SIZE: usize = 256 * 64;
107pub const MAX_ADV_LITERAL_CONTEXT_MAP_SIZE: usize = 256 * 64 * 2;
108#[derive(Debug)]
109pub struct PredictionModeContextMap<SliceType: SliceWrapper<u8>> {
110 pub literal_context_map: SliceType,
111 pub predmode_speed_and_distance_context_map: SliceType,
112}
113impl<SliceType: SliceWrapper<u8> + SliceWrapperMut<u8>> PredictionModeContextMap<SliceType> {
114 #[inline]
115 pub fn distance_context_map_mut(&mut self) -> &mut [u8] {
116 self.predmode_speed_and_distance_context_map
117 .slice_mut()
118 .split_at_mut(DISTANCE_CONTEXT_MAP_OFFSET)
119 .1
120 }
121 #[inline]
122 pub fn set_stride_context_speed(&mut self, speed_max: [(u16, u16); 2]) {
123 let cm_slice = self.predmode_speed_and_distance_context_map.slice_mut();
124 for high in 0..2 {
125 cm_slice[Self::stride_context_speed_offset() + high] =
126 Self::u16_to_f8(speed_max[high].0);
127 cm_slice[Self::stride_context_speed_max_offset() + high] =
128 Self::u16_to_f8(speed_max[high].1);
129 }
130 }
131 #[inline]
132 pub fn set_context_map_speed(&mut self, speed_max: [(u16, u16); 2]) {
133 let cm_slice = self.predmode_speed_and_distance_context_map.slice_mut();
134 for high in 0..2 {
135 cm_slice[Self::context_map_speed_offset() + high] = Self::u16_to_f8(speed_max[high].0);
136 cm_slice[Self::context_map_speed_max_offset() + high] =
137 Self::u16_to_f8(speed_max[high].1);
138 }
139 }
140 pub fn set_mixing_math(&mut self, math_enum: u8) {
141 let cm_slice = self.predmode_speed_and_distance_context_map.slice_mut();
142 cm_slice[MIXING_MATH_OFFSET] = math_enum;
143 }
144 pub fn set_adv_context_map(&mut self, is_adv: u8) {
145 let cm_slice = self.predmode_speed_and_distance_context_map.slice_mut();
146 cm_slice[ADV_CONTEXT_MAP_OFFSET] = is_adv;
147 }
148 #[inline]
149 pub fn set_mixing_values(&mut self, mixing_mask: &[u8; NUM_MIXING_VALUES]) {
150 let cm_slice = self.predmode_speed_and_distance_context_map.slice_mut();
151 cm_slice[MIXING_OFFSET..(MIXING_OFFSET + NUM_MIXING_VALUES)]
152 .clone_from_slice(&mixing_mask[..]);
153 }
154 #[inline]
155 pub fn get_mixing_values_mut(&mut self) -> &mut [u8] {
156 let cm_slice = self.predmode_speed_and_distance_context_map.slice_mut();
157 &mut cm_slice[MIXING_OFFSET..(MIXING_OFFSET + NUM_MIXING_VALUES)]
158 }
159 #[inline]
160 pub fn set_combined_stride_context_speed(&mut self, speed_max: [(u16, u16); 2]) {
161 let cm_slice = self.predmode_speed_and_distance_context_map.slice_mut();
162 for high in 0..2 {
163 cm_slice[Self::combined_stride_context_speed_offset() + high] =
164 Self::u16_to_f8(speed_max[high].0);
165 cm_slice[Self::combined_stride_context_speed_max_offset() + high] =
166 Self::u16_to_f8(speed_max[high].1);
167 }
168 }
169 pub fn set_literal_prediction_mode(&mut self, val: LiteralPredictionModeNibble) {
170 let cm_slice = self.predmode_speed_and_distance_context_map.slice_mut();
171 cm_slice[PREDMODE_OFFSET] = val.0;
172 }
173}
174impl<SliceType: SliceWrapper<u8>> PredictionModeContextMap<SliceType> {
175 #[inline]
176 pub fn from_mut<Other: SliceWrapper<u8>>(
177 other: PredictionModeContextMap<Other>,
178 ) -> PredictionModeContextMap<SliceType>
179 where
180 SliceType: From<Other>,
181 {
182 PredictionModeContextMap::<SliceType> {
183 literal_context_map: SliceType::from(other.literal_context_map),
184 predmode_speed_and_distance_context_map: SliceType::from(
185 other.predmode_speed_and_distance_context_map,
186 ),
187 }
188 }
189 #[inline]
190 pub fn get_mixing_values(&self) -> &[u8] {
191 let cm_slice = self.predmode_speed_and_distance_context_map.slice();
192 &cm_slice[MIXING_OFFSET..(MIXING_OFFSET + NUM_MIXING_VALUES)]
193 }
194 #[inline]
195 pub fn get_mixing_math(&self) -> u8 {
196 let cm_slice = self.predmode_speed_and_distance_context_map.slice();
197 if cm_slice.len() <= MIXING_MATH_OFFSET {
198 return 1;
199 }
200 cm_slice[MIXING_MATH_OFFSET]
201 }
202 #[inline]
203 pub fn get_is_adv_context_map(&self) -> u8 {
204 let cm_slice = self.predmode_speed_and_distance_context_map.slice();
205 if cm_slice.len() <= ADV_CONTEXT_MAP_OFFSET {
206 return 0;
207 }
208 cm_slice[ADV_CONTEXT_MAP_OFFSET]
209 }
210 #[inline]
211 pub fn has_context_speeds(&self) -> bool {
212 self.predmode_speed_and_distance_context_map.slice().len() >= DISTANCE_CONTEXT_MAP_OFFSET
213 }
214 #[inline]
215 pub fn size_of_combined_array(distance_context_map_size: usize) -> usize {
216 distance_context_map_size + DISTANCE_CONTEXT_MAP_OFFSET
217 }
218 #[inline]
219 pub fn context_speeds_standard_len(&self) -> usize {
220 NUM_SPEED_VALUES
221 }
222 #[inline]
223 pub fn context_speeds_f8(&self) -> &[u8] {
224 &self.predmode_speed_and_distance_context_map.slice()
225 [SPEED_OFFSET..DISTANCE_CONTEXT_MAP_OFFSET]
226 }
227 #[inline]
228 pub fn distance_context_map(&self) -> &[u8] {
229 self.predmode_speed_and_distance_context_map
230 .slice()
231 .split_at(DISTANCE_CONTEXT_MAP_OFFSET)
232 .1
233 }
234 #[inline]
235 pub fn f8_to_u16(data: u8) -> u16 {
236 self::u8_to_speed(data)
237 }
238 #[inline]
239 pub fn u16_to_f8(data: u16) -> u8 {
240 self::speed_to_u8(data)
241 }
242 #[inline]
243 pub fn stride_context_speed_offset() -> usize {
244 SPEED_OFFSET
245 }
246 #[inline]
247 pub fn stride_context_speed_max_offset() -> usize {
248 SPEED_OFFSET + 2
249 }
250 #[inline]
251 pub fn context_map_speed_offset() -> usize {
252 SPEED_OFFSET + 4
253 }
254 #[inline]
255 pub fn context_map_speed_max_offset() -> usize {
256 SPEED_OFFSET + 6
257 }
258 #[inline]
259 pub fn combined_stride_context_speed_offset() -> usize {
260 SPEED_OFFSET + 8
261 }
262 #[inline]
263 pub fn combined_stride_context_speed_max_offset() -> usize {
264 SPEED_OFFSET + 10
265 }
266 #[inline]
267 pub fn literal_prediction_mode(&self) -> LiteralPredictionModeNibble {
268 let cm_slice = self.predmode_speed_and_distance_context_map.slice();
269 if PREDMODE_OFFSET < cm_slice.len() {
270 LiteralPredictionModeNibble(cm_slice[PREDMODE_OFFSET])
271 } else {
272 LiteralPredictionModeNibble::default()
273 }
274 }
275 pub fn stride_context_speed(&self) -> [(u16, u16); 2] {
276 let v = self.stride_context_speed_f8();
277 [
278 (self::u8_to_speed(v[0].0), self::u8_to_speed(v[0].1)),
279 (self::u8_to_speed(v[1].0), self::u8_to_speed(v[1].1)),
280 ]
281 }
282 pub fn context_map_speed(&self) -> [(u16, u16); 2] {
283 let v = self.context_map_speed_f8();
284 [
285 (self::u8_to_speed(v[0].0), self::u8_to_speed(v[0].1)),
286 (self::u8_to_speed(v[1].0), self::u8_to_speed(v[1].1)),
287 ]
288 }
289 pub fn combined_stride_context_speed(&self) -> [(u16, u16); 2] {
290 let v = self.combined_stride_context_speed_f8();
291 [
292 (self::u8_to_speed(v[0].0), self::u8_to_speed(v[0].1)),
293 (self::u8_to_speed(v[1].0), self::u8_to_speed(v[1].1)),
294 ]
295 }
296 #[inline]
297 pub fn stride_context_speed_f8(&self) -> [(u8, u8); 2] {
298 let cm_slice = self.predmode_speed_and_distance_context_map.slice();
299 let low_speed = cm_slice[Self::stride_context_speed_offset()];
300 let high_speed = cm_slice[Self::stride_context_speed_offset() + 1];
301 let low_max = cm_slice[Self::stride_context_speed_max_offset()];
302 let high_max = cm_slice[Self::stride_context_speed_max_offset() + 1];
303 [(low_speed, low_max), (high_speed, high_max)]
304 }
305 #[inline]
306 pub fn combined_stride_context_speed_f8(&self) -> [(u8, u8); 2] {
307 let cm_slice = self.predmode_speed_and_distance_context_map.slice();
308 let low_speed = cm_slice[Self::combined_stride_context_speed_offset()];
309 let high_speed = cm_slice[Self::combined_stride_context_speed_offset() + 1];
310 let low_max = cm_slice[Self::combined_stride_context_speed_max_offset()];
311 let high_max = cm_slice[Self::combined_stride_context_speed_max_offset() + 1];
312 [(low_speed, low_max), (high_speed, high_max)]
313 }
314 #[inline]
315 pub fn context_map_speed_f8(&self) -> [(u8, u8); 2] {
316 let cm_slice = self.predmode_speed_and_distance_context_map.slice();
317 let low_speed = cm_slice[Self::context_map_speed_offset()];
318 let high_speed = cm_slice[Self::context_map_speed_offset() + 1];
319 let low_max = cm_slice[Self::context_map_speed_max_offset()];
320 let high_max = cm_slice[Self::context_map_speed_max_offset() + 1];
321 [(low_speed, low_max), (high_speed, high_max)]
322 }
323}
324
325impl<SliceType: SliceWrapper<u8> + Clone> Clone for PredictionModeContextMap<SliceType> {
326 #[inline(always)]
327 fn clone(&self) -> Self {
328 PredictionModeContextMap::<SliceType> {
329 literal_context_map: self.literal_context_map.clone(),
330 predmode_speed_and_distance_context_map: self
331 .predmode_speed_and_distance_context_map
332 .clone(),
333 }
334 }
335}
336impl<SliceType: SliceWrapper<u8> + Clone + Copy> Copy for PredictionModeContextMap<SliceType> {}
337
338#[derive(Debug, Clone, Copy)]
339pub struct CopyCommand {
340 pub distance: u32,
341 pub num_bytes: u32,
342}
343
344impl Nop<CopyCommand> for CopyCommand {
345 #[inline(always)]
346 fn nop() -> Self {
347 CopyCommand {
348 distance: 1,
349 num_bytes: 0,
350 }
351 }
352}
353
354#[derive(Debug, Clone, Copy)]
355pub struct DictCommand {
356 pub word_size: u8,
357 pub transform: u8,
358 pub final_size: u8,
359 pub empty: u8,
360 pub word_id: u32,
361}
362
363impl Nop<DictCommand> for DictCommand {
364 #[inline(always)]
365 fn nop() -> Self {
366 DictCommand {
367 word_size: 0,
368 transform: 0,
369 final_size: 0,
370 empty: 1,
371 word_id: 0,
372 }
373 }
374}
375
376#[derive(Debug)]
377#[cfg(not(feature = "external-literal-probability"))]
378pub struct FeatureFlagSliceType<SliceType: SliceWrapper<u8>>(core::marker::PhantomData<SliceType>);
379
380#[cfg(not(feature = "external-literal-probability"))]
381impl<SliceType: SliceWrapper<u8>> SliceWrapper<u8> for FeatureFlagSliceType<SliceType> {
382 fn slice(&self) -> &[u8] {
383 &[]
384 }
385}
386
387#[cfg(not(feature = "external-literal-probability"))]
388impl<SliceType: SliceWrapper<u8> + Default> Default for FeatureFlagSliceType<SliceType> {
389 fn default() -> Self {
390 FeatureFlagSliceType::<SliceType>(core::marker::PhantomData::<SliceType>)
391 }
392}
393
394#[derive(Debug)]
395#[cfg(feature = "external-literal-probability")]
396pub struct FeatureFlagSliceType<SliceType: SliceWrapper<u8>>(pub SliceType);
397
398#[cfg(feature = "external-literal-probability")]
399impl<SliceType: SliceWrapper<u8>> SliceWrapper<u8> for FeatureFlagSliceType<SliceType> {
400 #[inline(always)]
401 fn slice(&self) -> &[u8] {
402 self.0.slice()
403 }
404}
405
406#[cfg(feature = "external-literal-probability")]
407impl<SliceType: SliceWrapper<u8> + Default> Default for FeatureFlagSliceType<SliceType> {
408 #[inline(always)]
409 fn default() -> Self {
410 FeatureFlagSliceType::<SliceType>(SliceType::default())
411 }
412}
413
414impl<SliceType: SliceWrapper<u8> + Clone> Clone for FeatureFlagSliceType<SliceType> {
415 #[inline(always)]
416 fn clone(&self) -> Self {
417 FeatureFlagSliceType::<SliceType>(self.0)
418 }
419}
420impl<SliceType: SliceWrapper<u8> + Clone + Copy> Copy for FeatureFlagSliceType<SliceType> {}
421
422#[derive(Debug)]
423pub struct LiteralCommand<SliceType: SliceWrapper<u8>> {
424 pub data: SliceType,
425 pub prob: FeatureFlagSliceType<SliceType>,
426 pub high_entropy: bool, }
428impl<SliceType: SliceWrapper<u8>> SliceWrapper<u8> for LiteralCommand<SliceType> {
429 #[inline(always)]
430 fn slice(&self) -> &[u8] {
431 self.data.slice()
432 }
433}
434impl<SliceType: SliceWrapper<u8> + SliceWrapperMut<u8>> SliceWrapperMut<u8>
435 for LiteralCommand<SliceType>
436{
437 #[inline(always)]
438 fn slice_mut(&mut self) -> &mut [u8] {
439 self.data.slice_mut()
440 }
441}
442
443impl<SliceType: SliceWrapper<u8> + Default> Nop<LiteralCommand<SliceType>>
444 for LiteralCommand<SliceType>
445{
446 #[inline(always)]
447 fn nop() -> Self {
448 LiteralCommand {
449 data: SliceType::default(),
450 prob: FeatureFlagSliceType::<SliceType>::default(),
451 high_entropy: false,
452 }
453 }
454}
455impl<SliceType: SliceWrapper<u8> + Clone> Clone for LiteralCommand<SliceType> {
456 #[inline(always)]
457 fn clone(&self) -> LiteralCommand<SliceType> {
458 LiteralCommand::<SliceType> {
459 data: self.data.clone(),
460 prob: self.prob.clone(),
461 high_entropy: self.high_entropy,
462 }
463 }
464}
465impl<SliceType: SliceWrapper<u8> + Clone + Copy> Copy for LiteralCommand<SliceType> {}
466
467#[derive(Debug)]
468pub enum Command<SliceType: SliceWrapper<u8>> {
469 Copy(CopyCommand),
470 Dict(DictCommand),
471 Literal(LiteralCommand<SliceType>),
472 BlockSwitchCommand(BlockSwitch),
473 BlockSwitchLiteral(LiteralBlockSwitch),
474 BlockSwitchDistance(BlockSwitch),
475 PredictionMode(PredictionModeContextMap<SliceType>),
476}
477impl<SliceType: SliceWrapper<u8> + Default> Command<SliceType> {
478 #[inline]
479 pub fn free_array<F>(&mut self, apply_func: &mut F)
480 where
481 F: FnMut(SliceType),
482 {
483 match self {
484 Command::Literal(ref mut lit) => apply_func(core::mem::take(&mut lit.data)),
485 Command::PredictionMode(ref mut pm) => {
486 apply_func(core::mem::take(&mut pm.literal_context_map));
487 apply_func(core::mem::take(
488 &mut pm.predmode_speed_and_distance_context_map,
489 ));
490 }
491 _ => {}
492 }
493 }
494}
495
496impl<SliceType: SliceWrapper<u8>> Default for Command<SliceType> {
497 #[inline(always)]
498 fn default() -> Self {
499 Command::<SliceType>::nop()
500 }
501}
502
503impl<SliceType: SliceWrapper<u8>> Nop<Command<SliceType>> for Command<SliceType> {
504 #[inline(always)]
505 fn nop() -> Command<SliceType> {
506 Command::Copy(CopyCommand::nop())
507 }
508}
509
510impl<SliceType: SliceWrapper<u8> + Clone> Clone for Command<SliceType> {
511 #[inline]
512 fn clone(&self) -> Command<SliceType> {
513 match self {
514 Command::Copy(copy) => Command::Copy(*copy),
515 Command::Dict(dict) => Command::Dict(*dict),
516 Command::Literal(literal) => Command::Literal(literal.clone()),
517 Command::BlockSwitchCommand(switch) => Command::BlockSwitchCommand(*switch),
518 Command::BlockSwitchLiteral(switch) => Command::BlockSwitchLiteral(*switch),
519 Command::BlockSwitchDistance(switch) => Command::BlockSwitchDistance(*switch),
520 Command::PredictionMode(pm) => Command::PredictionMode(pm.clone()),
521 }
522 }
523}
524
525impl<SliceType: SliceWrapper<u8> + Clone + Copy> Copy for Command<SliceType> {}
526
527#[inline(always)]
528pub fn free_cmd_inline<SliceTypeAllocator: Allocator<u8>>(
529 xself: &mut Command<SliceTypeAllocator::AllocatedMemory>,
530 m8: &mut SliceTypeAllocator,
531) {
532 match *xself {
533 Command::Literal(ref mut lit) => m8.free_cell(core::mem::take(&mut lit.data)),
534 Command::PredictionMode(ref mut pm) => {
535 m8.free_cell(core::mem::take(&mut pm.literal_context_map));
536 m8.free_cell(core::mem::take(
537 &mut pm.predmode_speed_and_distance_context_map,
538 ));
539 }
540 Command::Dict(_)
541 | Command::Copy(_)
542 | Command::BlockSwitchCommand(_)
543 | Command::BlockSwitchLiteral(_)
544 | Command::BlockSwitchDistance(_) => {}
545 }
546}
547
548#[inline(never)]
549pub fn free_cmd<SliceTypeAllocator: Allocator<u8>>(
550 xself: &mut Command<SliceTypeAllocator::AllocatedMemory>,
551 m8: &mut SliceTypeAllocator,
552) {
553 free_cmd_inline(xself, m8)
554}
555
556#[derive(Clone, Copy, Default, Debug)]
557pub struct SliceOffset(pub usize, pub u32);
558impl SliceWrapper<u8> for SliceOffset {
559 fn slice(&self) -> &[u8] {
560 &[]
562 }
563}
564
565pub trait Freezable {
566 fn freeze(&self) -> SliceOffset;
567}
568
569pub trait Unfreezable {
570 fn thaw<'a>(&self, data: &'a [u8]) -> InputReference<'a>;
571 fn thaw_mut<'a>(&self, data: &'a mut [u8]) -> InputReferenceMut<'a>;
572 fn thaw_pair<'a>(&self, pair: &InputPair<'a>) -> Result<InputReference<'a>, ()>;
573}
574
575impl<'a> From<InputReference<'a>> for SliceOffset {
576 fn from(f: InputReference<'a>) -> Self {
577 debug_assert!(f.data.len() <= 0xffff_ffff);
578 SliceOffset(f.orig_offset, f.data.len() as u32)
579 }
580}
581impl Unfreezable for SliceOffset {
582 fn thaw<'a>(&self, data: &'a [u8]) -> InputReference<'a> {
583 InputReference {
584 data: data.split_at(self.0).1.split_at(self.1 as usize).0,
585 orig_offset: self.0,
586 }
587 }
588 fn thaw_mut<'a>(&self, data: &'a mut [u8]) -> InputReferenceMut<'a> {
589 InputReferenceMut {
590 data: data.split_at_mut(self.0).1.split_at_mut(self.1 as usize).0,
591 orig_offset: self.0,
592 }
593 }
594 fn thaw_pair<'a>(&self, pair: &InputPair<'a>) -> Result<InputReference<'a>, ()> {
595 if self.0 >= pair.1.orig_offset {
596 return Ok(InputReference {
597 data: pair
598 .1
599 .data
600 .split_at(self.0 - pair.1.orig_offset)
601 .1
602 .split_at(self.1 as usize)
603 .0,
604 orig_offset: self.0,
605 });
606 }
607 let offset = self.0 - pair.0.orig_offset;
608 if offset + self.1 as usize <= pair.0.data.len() {
609 Ok(InputReference {
611 data: pair.0.data.split_at(offset).1.split_at(self.1 as usize).0,
612 orig_offset: self.0,
613 })
614 } else {
615 Err(())
616 }
617 }
618}
619impl SliceOffset {
620 pub fn offset(&self) -> usize {
621 self.0
622 }
623 pub fn len(&self) -> usize {
624 self.1 as usize
625 }
626 pub fn len32(&self) -> u32 {
627 self.1
628 }
629}
630
631pub type StaticCommand = Command<SliceOffset>;
632
633pub trait CommandProcessor<'a> {
634 fn push(&mut self, val: Command<InputReference<'a>>);
635 fn push_literals(&mut self, data: &InputPair<'a>) {
636 if data.0.len() != 0 {
637 self.push(Command::Literal(LiteralCommand {
638 data: data.0,
639 prob: FeatureFlagSliceType::<InputReference>::default(),
640 high_entropy: false,
641 }));
642 }
643 if data.1.len() != 0 {
644 self.push(Command::Literal(LiteralCommand {
645 data: data.1,
646 prob: FeatureFlagSliceType::<InputReference>::default(),
647 high_entropy: false,
648 }));
649 }
650 }
651 fn push_rand_literals(&mut self, data: &InputPair<'a>) {
652 if data.0.len() != 0 {
653 self.push(Command::Literal(LiteralCommand {
654 data: data.0,
655 prob: FeatureFlagSliceType::<InputReference>::default(),
656 high_entropy: true,
657 }));
658 }
659 if data.1.len() != 0 {
660 self.push(Command::Literal(LiteralCommand {
661 data: data.1,
662 prob: FeatureFlagSliceType::<InputReference>::default(),
663 high_entropy: true,
664 }));
665 }
666 }
667 fn push_block_switch_literal(&mut self, block_type: u8) {
668 self.push(Command::BlockSwitchLiteral(LiteralBlockSwitch::new(
669 block_type, 0,
670 )))
671 }
672}
673
674impl<SliceType: Unfreezable + SliceWrapper<u8>> Command<SliceType> {
675 pub fn thaw_pair<'a>(&self, data: &InputPair<'a>) -> Command<InputReference<'a>> {
676 match self {
677 Command::Literal(ref lit) => Command::Literal(LiteralCommand {
678 data: lit.data.thaw_pair(data).unwrap(),
679 prob: FeatureFlagSliceType::default(),
680 high_entropy: lit.high_entropy,
681 }),
682 Command::PredictionMode(ref pm) => Command::PredictionMode(PredictionModeContextMap {
683 literal_context_map: pm.literal_context_map.thaw_pair(data).unwrap(),
684 predmode_speed_and_distance_context_map: pm
685 .predmode_speed_and_distance_context_map
686 .thaw_pair(data)
687 .unwrap(),
688 }),
689 Command::Dict(ref d) => Command::Dict(*d),
690 Command::Copy(ref c) => Command::Copy(*c),
691 Command::BlockSwitchCommand(ref c) => Command::BlockSwitchCommand(*c),
692 Command::BlockSwitchLiteral(ref c) => Command::BlockSwitchLiteral(*c),
693 Command::BlockSwitchDistance(ref c) => Command::BlockSwitchDistance(*c),
694 }
695 }
696
697 pub fn thaw<'a>(&self, data: &'a [u8]) -> Command<InputReference<'a>> {
698 match self {
699 Command::Literal(ref lit) => Command::Literal(LiteralCommand {
700 data: lit.data.thaw(data),
701 prob: FeatureFlagSliceType::default(),
702 high_entropy: lit.high_entropy,
703 }),
704 Command::PredictionMode(ref pm) => Command::PredictionMode(PredictionModeContextMap {
705 literal_context_map: pm.literal_context_map.thaw(data),
706 predmode_speed_and_distance_context_map: pm
707 .predmode_speed_and_distance_context_map
708 .thaw(data),
709 }),
710 Command::Dict(ref d) => Command::Dict(*d),
711 Command::Copy(ref c) => Command::Copy(*c),
712 Command::BlockSwitchCommand(ref c) => Command::BlockSwitchCommand(*c),
713 Command::BlockSwitchLiteral(ref c) => Command::BlockSwitchLiteral(*c),
714 Command::BlockSwitchDistance(ref c) => Command::BlockSwitchDistance(*c),
715 }
716 }
717}
718
719impl<SliceType: SliceWrapper<u8> + Freezable> Command<SliceType> {
720 pub fn freeze(&self) -> Command<SliceOffset> {
721 match self {
722 Command::Literal(ref lit) => Command::Literal(LiteralCommand {
723 data: lit.data.freeze(),
724 prob: FeatureFlagSliceType::default(),
725 high_entropy: lit.high_entropy,
726 }),
727 Command::PredictionMode(ref pm) => Command::PredictionMode(PredictionModeContextMap {
728 literal_context_map: pm.literal_context_map.freeze(),
729 predmode_speed_and_distance_context_map: pm
730 .predmode_speed_and_distance_context_map
731 .freeze(),
732 }),
733 Command::Dict(ref d) => Command::Dict(*d),
734 Command::Copy(ref c) => Command::Copy(*c),
735 Command::BlockSwitchCommand(ref c) => Command::BlockSwitchCommand(*c),
736 Command::BlockSwitchLiteral(ref c) => Command::BlockSwitchLiteral(*c),
737 Command::BlockSwitchDistance(ref c) => Command::BlockSwitchDistance(*c),
738 }
739 }
740}
741
742#[inline(always)]
743pub fn speed_to_u8(data: u16) -> u8 {
744 let length = 16 - data.leading_zeros() as u8;
745 let mantissa = if data != 0 {
746 let rem = data - (1 << (length - 1));
747 (rem << 3) >> (length - 1)
748 } else {
749 0
750 };
751 (length << 3) | mantissa as u8
752}
753
754#[inline(always)]
755pub fn u8_to_speed(data: u8) -> u16 {
756 if data < 8 {
757 0
758 } else {
759 let log_val = (data >> 3) - 1;
760 let rem = (u16::from(data) & 0x07) << log_val;
761 (1u16 << log_val) | (rem >> 3)
762 }
763}
764
765#[cfg(test)]
766mod test {
767 use super::{speed_to_u8, u8_to_speed};
768 fn tst_u8_to_speed(data: u16) {
769 assert_eq!(u8_to_speed(speed_to_u8(data)), data);
770 }
771 #[test]
772 fn test_u8_to_speed() {
773 tst_u8_to_speed(0);
774 tst_u8_to_speed(1);
775 tst_u8_to_speed(2);
776 tst_u8_to_speed(3);
777 tst_u8_to_speed(4);
778 tst_u8_to_speed(5);
779 tst_u8_to_speed(6);
780 tst_u8_to_speed(7);
781 tst_u8_to_speed(8);
782 tst_u8_to_speed(10);
783 tst_u8_to_speed(12);
784 tst_u8_to_speed(16);
785 tst_u8_to_speed(24);
786 tst_u8_to_speed(32);
787 tst_u8_to_speed(48);
788 tst_u8_to_speed(64);
789 tst_u8_to_speed(96);
790 tst_u8_to_speed(768);
791 tst_u8_to_speed(1280);
792 tst_u8_to_speed(1536);
793 tst_u8_to_speed(1664);
794 }
795}