stream_vbyte/
scalar.rs

1use std::cmp;
2
3use crate::{
4    decode::{decode_num_scalar, DecodeQuadSink, Decoder, WriteQuadToSlice},
5    encode::{encode_num_scalar, Encoder},
6    tables,
7};
8
9/// Encoder/Decoder that works on every platform, at the cost of speed compared to the SIMD
10/// accelerated versions.
11pub struct Scalar;
12
13impl Encoder for Scalar {
14    // This implementation encodes all provided input numbers.
15    fn encode_quads(
16        input: &[u32],
17        control_bytes: &mut [u8],
18        encoded_nums: &mut [u8],
19    ) -> (usize, usize) {
20        let mut bytes_written = 0;
21        let mut nums_encoded = 0;
22
23        for quads_encoded in 0..control_bytes.len() {
24            let num0 = input[nums_encoded];
25            let num1 = input[nums_encoded + 1];
26            let num2 = input[nums_encoded + 2];
27            let num3 = input[nums_encoded + 3];
28
29            let len0 = encode_num_scalar(num0, &mut encoded_nums[bytes_written..]);
30            let len1 = encode_num_scalar(num1, &mut encoded_nums[bytes_written + len0..]);
31            let len2 = encode_num_scalar(num2, &mut encoded_nums[bytes_written + len0 + len1..]);
32            let len3 = encode_num_scalar(
33                num3,
34                &mut encoded_nums[bytes_written + len0 + len1 + len2..],
35            );
36
37            // this is a few percent faster in my testing than using control_bytes.iter_mut()
38            control_bytes[quads_encoded] =
39                ((len0 - 1) | (len1 - 1) << 2 | (len2 - 1) << 4 | (len3 - 1) << 6) as u8;
40
41            bytes_written += len0 + len1 + len2 + len3;
42            nums_encoded += 4;
43        }
44
45        (nums_encoded, bytes_written)
46    }
47}
48
49impl Decoder for Scalar {
50    // Quads are decoded one at a time anyway so no need to bundle them up only to un-bundle them.
51    // Instead, we just call on_number for each decoded number.
52    type DecodedQuad = UnusedQuad;
53
54    // This implementation decodes all provided encoded data.
55    fn decode_quads<S: DecodeQuadSink<Self>>(
56        control_bytes: &[u8],
57        encoded_nums: &[u8],
58        control_bytes_to_decode: usize,
59        nums_already_decoded: usize,
60        sink: &mut S,
61    ) -> (usize, usize) {
62        let mut bytes_read: usize = 0;
63        let mut nums_decoded: usize = nums_already_decoded;
64        let control_byte_limit = cmp::min(control_bytes.len(), control_bytes_to_decode);
65
66        for &control_byte in control_bytes[0..control_byte_limit].iter() {
67            let (len0, len1, len2, len3) =
68                tables::DECODE_LENGTH_PER_NUM_TABLE[control_byte as usize];
69            let len0 = len0 as usize;
70            let len1 = len1 as usize;
71            let len2 = len2 as usize;
72            let len3 = len3 as usize;
73
74            sink.on_number(
75                decode_num_scalar(len0, &encoded_nums[bytes_read..]),
76                nums_decoded,
77            );
78            sink.on_number(
79                decode_num_scalar(len1, &encoded_nums[bytes_read + len0..]),
80                nums_decoded + 1,
81            );
82            sink.on_number(
83                decode_num_scalar(len2, &encoded_nums[bytes_read + len0 + len1..]),
84                nums_decoded + 2,
85            );
86            sink.on_number(
87                decode_num_scalar(len3, &encoded_nums[bytes_read + len0 + len1 + len2..]),
88                nums_decoded + 3,
89            );
90
91            bytes_read += len0 + len1 + len2 + len3;
92            nums_decoded += 4;
93        }
94
95        (nums_decoded - nums_already_decoded, bytes_read)
96    }
97}
98
99impl WriteQuadToSlice for Scalar {
100    fn write_quad_to_slice(_quad: Self::DecodedQuad, _slice: &mut [u32]) {
101        // scalar decoding doesn't use quads, so this will never be called
102        unreachable!()
103    }
104}
105
106/// `Scalar` decoder produces numbers one by one, so there is no quad to unbundle.
107/// Any implementations of `DecodedQuadSink<EmptyQuad>` can safely use `unreachable!()`
108/// or equivalent.
109pub struct UnusedQuad;
110
111/// The Scalar decoder doesn't use quads, but the type checker requires that there be
112/// a `DecodeQuadSink<Scalar>` impl for a sink nonetheless. This macro will generate
113/// an appropriate stub impl for a sink type.
114#[macro_export]
115macro_rules! decode_quad_scalar {
116    ($sink:ty) => {
117        impl stream_vbyte::decode::DecodeQuadSink<stream_vbyte::scalar::Scalar> for $sink {
118            fn on_quad(&mut self, _: stream_vbyte::scalar::UnusedQuad, _: usize) {
119                unreachable!()
120            }
121        }
122    };
123}