density_rs/algorithms/cheetah/
cheetah.rs1use crate::algorithms::PLAIN_FLAG;
2use crate::codec::codec::Codec;
3use crate::codec::decoder::Decoder;
4use crate::codec::quad_encoder::QuadEncoder;
5use crate::errors::decode_error::DecodeError;
6use crate::errors::encode_error::EncodeError;
7use crate::io::read_buffer::ReadBuffer;
8use crate::io::read_signature::ReadSignature;
9use crate::io::write_buffer::WriteBuffer;
10use crate::io::write_signature::WriteSignature;
11use crate::{BIT_SIZE_U16, BIT_SIZE_U32, BYTE_SIZE_U32};
12use std::slice::{from_raw_parts, from_raw_parts_mut};
13
14pub(crate) const CHEETAH_HASH_BITS: usize = BIT_SIZE_U16;
15pub(crate) const CHEETAH_HASH_MULTIPLIER: u32 = 0x9D6EF916;
16
17
18pub(crate) const FLAG_SIZE_BITS: u8 = 2;
19pub(crate) const MAP_A_FLAG: u64 = 0x1;
20pub(crate) const MAP_B_FLAG: u64 = 0x2;
21pub(crate) const PREDICTED_FLAG: u64 = 0x3;
22pub(crate) const DECODE_FLAG_MASK: u64 = 0x3;
23pub(crate) const DECODE_FLAG_MASK_BITS: u8 = 2;
24
25pub struct State {
26 pub(crate) last_hash: u16,
27 pub(crate) chunk_map: Vec<ChunkData>,
28 pub(crate) prediction_map: Vec<PredictionData>,
29}
30
31#[derive(Copy, Clone)]
32pub struct ChunkData {
33 pub(crate) chunk_a: u32,
34 pub(crate) chunk_b: u32,
35}
36
37#[derive(Copy, Clone)]
38pub struct PredictionData {
39 pub(crate) next: u32,
40}
41
42pub struct Cheetah {
43 pub state: State,
44}
45
46impl Cheetah {
47 pub fn new() -> Self {
48 Cheetah {
49 state: State {
50 last_hash: 0,
51 chunk_map: vec![ChunkData { chunk_a: 0, chunk_b: 0 }; 1 << CHEETAH_HASH_BITS],
52 prediction_map: vec![PredictionData { next: 0 }; 1 << CHEETAH_HASH_BITS],
53 },
54 }
55 }
56
57 pub fn encode(input: &[u8], output: &mut [u8]) -> Result<usize, EncodeError> {
58 let mut cheetah = Cheetah::new();
59 cheetah.encode(input, output)
60 }
61
62 pub fn decode(input: &[u8], output: &mut [u8]) -> Result<usize, DecodeError> {
63 let mut cheetah = Cheetah::new();
64 cheetah.decode(input, output)
65 }
66
67 #[inline(always)]
68 fn decode_plain(&mut self, in_buffer: &mut ReadBuffer) -> (u16, u32) {
69 let quad = in_buffer.read_u32_le();
70 let hash = (quad.wrapping_mul(CHEETAH_HASH_MULTIPLIER) >> (BIT_SIZE_U32 - CHEETAH_HASH_BITS)) as u16;
71 let chunk_data = &mut self.state.chunk_map[hash as usize];
72 chunk_data.chunk_b = chunk_data.chunk_a;
73 chunk_data.chunk_a = quad;
74 self.state.prediction_map[self.state.last_hash as usize] = PredictionData { next: quad };
75 (hash, quad)
76 }
77
78 #[inline(always)]
79 fn decode_map_a(&mut self, in_buffer: &mut ReadBuffer) -> (u16, u32) {
80 let hash = in_buffer.read_u16_le();
81 let chunk_data = &mut self.state.chunk_map[hash as usize];
82 let quad = chunk_data.chunk_a;
83 self.state.prediction_map[self.state.last_hash as usize] = PredictionData { next: quad };
84 (hash, quad)
85 }
86
87 #[inline(always)]
88 fn decode_map_b(&mut self, in_buffer: &mut ReadBuffer) -> (u16, u32) {
89 let hash = in_buffer.read_u16_le();
90 let chunk_data = &mut self.state.chunk_map[hash as usize];
91 let quad = chunk_data.chunk_b;
92 chunk_data.chunk_b = chunk_data.chunk_a;
93 chunk_data.chunk_a = quad;
94 self.state.prediction_map[self.state.last_hash as usize] = PredictionData { next: quad };
95 (hash, quad)
96 }
97
98 #[inline(always)]
99 fn decode_predicted(&mut self) -> (u16, u32) {
100 let quad = self.state.prediction_map[self.state.last_hash as usize].next;
101 let hash = (quad.wrapping_mul(CHEETAH_HASH_MULTIPLIER) >> (BIT_SIZE_U32 - CHEETAH_HASH_BITS)) as u16;
102 (hash, quad)
103 }
104
105 #[unsafe(no_mangle)]
106 pub extern "C" fn cheetah_encode(input: *const u8, input_size: usize, output: *mut u8, output_size: usize) -> usize {
107 unsafe { Self::encode(from_raw_parts(input, input_size), from_raw_parts_mut(output, output_size)).unwrap_or(0) }
108 }
109
110 #[unsafe(no_mangle)]
111 pub extern "C" fn cheetah_decode(input: *const u8, input_size: usize, output: *mut u8, output_size: usize) -> usize {
112 unsafe { Self::decode(from_raw_parts(input, input_size), from_raw_parts_mut(output, output_size)).unwrap_or(0) }
113 }
114
115 #[unsafe(no_mangle)]
116 pub extern "C" fn cheetah_safe_encode_buffer_size(size: usize) -> usize {
117 Self::safe_encode_buffer_size(size)
118 }
119}
120
121impl QuadEncoder for Cheetah {
122 #[inline(always)]
123 fn encode_quad(&mut self, quad: u32, out_buffer: &mut WriteBuffer, signature: &mut WriteSignature) {
124 let hash_u16 = (quad.wrapping_mul(CHEETAH_HASH_MULTIPLIER) >> (BIT_SIZE_U32 - CHEETAH_HASH_BITS)) as u16;
125 let predicted_chunk = &mut self.state.prediction_map[self.state.last_hash as usize].next;
126 if *predicted_chunk != quad {
127 let chunk_data = &mut self.state.chunk_map[hash_u16 as usize];
128 let offer_a = &mut chunk_data.chunk_a;
129 if *offer_a != quad {
130 let offer_b = &mut chunk_data.chunk_b;
131 if *offer_b != quad {
132 signature.push_bits(PLAIN_FLAG, FLAG_SIZE_BITS); out_buffer.push(&quad.to_le_bytes());
134 } else {
135 signature.push_bits(MAP_B_FLAG, FLAG_SIZE_BITS); out_buffer.push(&hash_u16.to_le_bytes());
137 }
138 *offer_b = *offer_a;
139 *offer_a = quad;
140 } else {
141 signature.push_bits(MAP_A_FLAG, FLAG_SIZE_BITS); out_buffer.push(&hash_u16.to_le_bytes());
143 }
144 *predicted_chunk = quad;
145 } else {
146 signature.push_bits(PREDICTED_FLAG, FLAG_SIZE_BITS); }
148 self.state.last_hash = hash_u16;
149 }
150}
151
152impl Decoder for Cheetah {
153 #[inline(always)]
154 fn decode_unit(&mut self, in_buffer: &mut ReadBuffer, signature: &mut ReadSignature, out_buffer: &mut WriteBuffer) {
155 let (hash, quad) = match signature.read_bits(DECODE_FLAG_MASK, DECODE_FLAG_MASK_BITS) {
156 PLAIN_FLAG => { self.decode_plain(in_buffer) }
157 MAP_A_FLAG => { self.decode_map_a(in_buffer) }
158 MAP_B_FLAG => { self.decode_map_b(in_buffer) }
159 _ => { self.decode_predicted() }
160 };
161 self.state.last_hash = hash;
162 out_buffer.push(&quad.to_le_bytes());
163 }
164
165 #[inline(always)]
166 fn decode_partial_unit(&mut self, in_buffer: &mut ReadBuffer, signature: &mut ReadSignature, out_buffer: &mut WriteBuffer) -> bool {
167 let (hash, quad) = match signature.read_bits(DECODE_FLAG_MASK, DECODE_FLAG_MASK_BITS) {
168 PLAIN_FLAG => {
169 match in_buffer.remaining() {
170 0 => { return true; }
171 1..=3 => {
172 out_buffer.push(in_buffer.read(in_buffer.remaining()));
173 return true;
174 }
175 _ => { self.decode_plain(in_buffer) }
176 }
177 }
178 MAP_A_FLAG => { self.decode_map_a(in_buffer) }
179 MAP_B_FLAG => { self.decode_map_b(in_buffer) }
180 _ => { self.decode_predicted() }
181 };
182 self.state.last_hash = hash;
183 out_buffer.push(&quad.to_le_bytes());
184 false
185 }
186}
187
188impl Codec for Cheetah {
189 #[inline(always)]
190 fn block_size() -> usize { BYTE_SIZE_U32 * (Self::signature_significant_bytes() << 3) / FLAG_SIZE_BITS as usize }
191
192 #[inline(always)]
193 fn decode_unit_size() -> usize { 4 }
194
195 #[inline(always)]
196 fn signature_significant_bytes() -> usize { 8 }
197
198 fn clear_state(&mut self) {
199 self.state.last_hash = 0;
200 self.state.chunk_map.fill(ChunkData { chunk_a: 0, chunk_b: 0 });
201 self.state.prediction_map.fill(PredictionData { next: 0 });
202 }
203}