ruzstd/decoding/
sequence_execution.rs

1use super::scratch::DecoderScratch;
2use crate::decoding::errors::ExecuteSequencesError;
3
4/// Take the provided decoder and execute the sequences stored within
5pub fn execute_sequences(scratch: &mut DecoderScratch) -> Result<(), ExecuteSequencesError> {
6    let mut literals_copy_counter = 0;
7    let old_buffer_size = scratch.buffer.len();
8    let mut seq_sum = 0;
9
10    for idx in 0..scratch.sequences.len() {
11        let seq = scratch.sequences[idx];
12
13        if seq.ll > 0 {
14            let high = literals_copy_counter + seq.ll as usize;
15            if high > scratch.literals_buffer.len() {
16                return Err(ExecuteSequencesError::NotEnoughBytesForSequence {
17                    wanted: high,
18                    have: scratch.literals_buffer.len(),
19                });
20            }
21            let literals = &scratch.literals_buffer[literals_copy_counter..high];
22            literals_copy_counter += seq.ll as usize;
23
24            scratch.buffer.push(literals);
25        }
26
27        let actual_offset = do_offset_history(seq.of, seq.ll, &mut scratch.offset_hist);
28        if actual_offset == 0 {
29            return Err(ExecuteSequencesError::ZeroOffset);
30        }
31        if seq.ml > 0 {
32            scratch
33                .buffer
34                .repeat(actual_offset as usize, seq.ml as usize)?;
35        }
36
37        seq_sum += seq.ml;
38        seq_sum += seq.ll;
39    }
40    if literals_copy_counter < scratch.literals_buffer.len() {
41        let rest_literals = &scratch.literals_buffer[literals_copy_counter..];
42        scratch.buffer.push(rest_literals);
43        seq_sum += rest_literals.len() as u32;
44    }
45
46    let diff = scratch.buffer.len() - old_buffer_size;
47    assert!(
48        seq_sum as usize == diff,
49        "Seq_sum: {} is different from the difference in buffersize: {}",
50        seq_sum,
51        diff
52    );
53    Ok(())
54}
55
56/// Update the most recently used offsets to reflect the provided offset value, and return the
57/// "actual" offset needed because offsets are not stored in a raw way, some transformations are needed
58/// before you get a functional number.
59fn do_offset_history(offset_value: u32, lit_len: u32, scratch: &mut [u32; 3]) -> u32 {
60    let actual_offset = if lit_len > 0 {
61        match offset_value {
62            1..=3 => scratch[offset_value as usize - 1],
63            _ => {
64                //new offset
65                offset_value - 3
66            }
67        }
68    } else {
69        match offset_value {
70            1..=2 => scratch[offset_value as usize],
71            3 => scratch[0] - 1,
72            _ => {
73                //new offset
74                offset_value - 3
75            }
76        }
77    };
78
79    //update history
80    if lit_len > 0 {
81        match offset_value {
82            1 => {
83                //nothing
84            }
85            2 => {
86                scratch[1] = scratch[0];
87                scratch[0] = actual_offset;
88            }
89            _ => {
90                scratch[2] = scratch[1];
91                scratch[1] = scratch[0];
92                scratch[0] = actual_offset;
93            }
94        }
95    } else {
96        match offset_value {
97            1 => {
98                scratch[1] = scratch[0];
99                scratch[0] = actual_offset;
100            }
101            2 => {
102                scratch[2] = scratch[1];
103                scratch[1] = scratch[0];
104                scratch[0] = actual_offset;
105            }
106            _ => {
107                scratch[2] = scratch[1];
108                scratch[1] = scratch[0];
109                scratch[0] = actual_offset;
110            }
111        }
112    }
113
114    actual_offset
115}