1use std::error::Error;
2use std::fmt::{self, Display, Formatter};
3
4pub const WINDOW_SIZE: usize = 32 * 1024;
6
7#[derive(Clone, Copy, Debug, Eq, PartialEq)]
12#[repr(transparent)]
13pub struct Symbol(pub(crate) u16);
14
15impl Symbol {
16 pub const fn literal(byte: u8) -> Self {
18 Self(byte as u16)
19 }
20
21 pub fn marker(index: usize) -> Result<Self, MarkerError> {
23 if index >= WINDOW_SIZE {
24 return Err(MarkerError::IndexOutOfRange(index));
25 }
26 Ok(Self((WINDOW_SIZE + index) as u16))
27 }
28
29 pub const fn encoded(self) -> u16 {
31 self.0
32 }
33
34 pub const fn as_literal(self) -> Option<u8> {
36 if self.0 <= u8::MAX as u16 {
37 Some(self.0 as u8)
38 } else {
39 None
40 }
41 }
42
43 fn marker_index(self) -> Option<usize> {
44 if self.0 >= WINDOW_SIZE as u16 {
45 Some(self.0 as usize - WINDOW_SIZE)
46 } else {
47 None
48 }
49 }
50
51 pub(crate) const fn from_encoded(encoded: u16) -> Self {
52 Self(encoded)
53 }
54}
55
56#[derive(Clone, Debug, Eq, PartialEq)]
58pub struct Window(Vec<u8>);
59
60impl Window {
61 pub fn new(bytes: Vec<u8>) -> Result<Self, MarkerError> {
63 if bytes.len() > WINDOW_SIZE {
64 return Err(MarkerError::WindowTooLarge(bytes.len()));
65 }
66 Ok(Self(bytes))
67 }
68
69 pub const fn empty() -> Self {
71 Self(Vec::new())
72 }
73
74 pub fn as_slice(&self) -> &[u8] {
76 &self.0
77 }
78
79 pub(crate) fn advanced_by(&self, bytes: &[u8]) -> Self {
80 if bytes.len() >= WINDOW_SIZE {
81 return Self(bytes[bytes.len() - WINDOW_SIZE..].to_vec());
82 }
83 let retained = WINDOW_SIZE.saturating_sub(bytes.len()).min(self.0.len());
84 let mut result = Vec::with_capacity(retained + bytes.len());
85 result.extend_from_slice(&self.0[self.0.len() - retained..]);
86 result.extend_from_slice(bytes);
87 Self(result)
88 }
89}
90
91#[derive(Clone, Debug, Default, Eq, PartialEq)]
93pub struct MarkerBuffer {
94 symbols: Vec<Symbol>,
95}
96
97impl MarkerBuffer {
98 pub const fn new(symbols: Vec<Symbol>) -> Self {
100 Self { symbols }
101 }
102
103 pub fn symbols(&self) -> &[Symbol] {
105 &self.symbols
106 }
107
108 pub(crate) fn len(&self) -> usize {
109 self.symbols.len()
110 }
111
112 pub(crate) fn append_resolved_range(
113 &self,
114 range: std::ops::Range<usize>,
115 output: &mut Vec<u8>,
116 window: &Window,
117 ) -> Result<(), MarkerError> {
118 let symbols = self
119 .symbols
120 .get(range)
121 .ok_or(MarkerError::IndexOutOfRange(self.symbols.len()))?;
122 output.reserve(symbols.len());
123 for &symbol in symbols {
124 output.push(resolve_symbol(symbol, window)?);
125 }
126 Ok(())
127 }
128
129 pub fn resolve(self, window: &Window) -> Result<Vec<u8>, MarkerError> {
131 self.resolve_ref(window)
132 }
133
134 pub(crate) fn resolve_ref(&self, window: &Window) -> Result<Vec<u8>, MarkerError> {
136 if self.symbols.len() >= 128 * 1024 && window.0.len() == WINDOW_SIZE {
137 let output = resolve_lut(&self.symbols, window);
138 return Ok(output);
139 }
140 let mut output = vec![0_u8; self.len()];
141 #[cfg(target_arch = "x86_64")]
142 if std::arch::is_x86_feature_detected!("sse4.1") {
143 unsafe { resolve_sse41(&self.symbols, &mut output, window)? };
147 return Ok(output);
148 }
149 #[cfg(target_arch = "aarch64")]
150 {
151 unsafe { resolve_neon(&self.symbols, &mut output, window)? };
154 Ok(output)
155 }
156 #[cfg(not(target_arch = "aarch64"))]
160 {
161 resolve_scalar(&self.symbols, &mut output, window)?;
162 Ok(output)
163 }
164 }
165}
166
167fn resolve_lut(symbols: &[Symbol], window: &Window) -> Vec<u8> {
174 debug_assert_eq!(window.0.len(), WINDOW_SIZE);
175
176 let mut lookup = [0_u8; u16::MAX as usize + 1];
177 for (value, byte) in lookup[..=u8::MAX as usize].iter_mut().enumerate() {
178 *byte = value as u8;
179 }
180 lookup[WINDOW_SIZE..].copy_from_slice(&window.0);
181 let mut output = Vec::with_capacity(symbols.len());
182 for (target, symbol) in output.spare_capacity_mut().iter_mut().zip(symbols) {
183 target.write(lookup[usize::from(symbol.encoded())]);
184 }
185 unsafe { output.set_len(symbols.len()) };
188 output
189}
190
191fn resolve_symbol(symbol: Symbol, window: &Window) -> Result<u8, MarkerError> {
192 if let Some(literal) = symbol.as_literal() {
193 return Ok(literal);
194 }
195 let index = symbol
196 .marker_index()
197 .expect("all non-literal symbol encodings are markers");
198 let missing = WINDOW_SIZE.saturating_sub(window.0.len());
199 if index < missing {
200 return Err(MarkerError::WindowTooSmall {
201 required: WINDOW_SIZE - index,
202 actual: window.0.len(),
203 });
204 }
205 Ok(window.0[index - missing])
206}
207
208fn resolve_scalar(
209 symbols: &[Symbol],
210 output: &mut [u8],
211 window: &Window,
212) -> Result<(), MarkerError> {
213 for (target, &symbol) in output.iter_mut().zip(symbols) {
214 *target = resolve_symbol(symbol, window)?;
215 }
216 Ok(())
217}
218
219#[cfg(target_arch = "x86_64")]
220#[target_feature(enable = "sse4.1")]
221unsafe fn resolve_sse41(
222 symbols: &[Symbol],
223 output: &mut [u8],
224 window: &Window,
225) -> Result<(), MarkerError> {
226 use core::arch::x86_64::{
227 __m128i, _mm_and_si128, _mm_loadu_si128, _mm_packus_epi16, _mm_set1_epi16,
228 _mm_storel_epi64, _mm_testz_si128,
229 };
230
231 let vectorized = symbols.len() / 8 * 8;
232 let high_byte_mask = _mm_set1_epi16(0xFF00_u16 as i16);
233 for offset in (0..vectorized).step_by(8) {
234 let values = unsafe { _mm_loadu_si128(symbols.as_ptr().add(offset).cast::<__m128i>()) };
237 if _mm_testz_si128(_mm_and_si128(values, high_byte_mask), high_byte_mask) != 0 {
238 let packed = _mm_packus_epi16(values, values);
239 unsafe {
241 _mm_storel_epi64(output.as_mut_ptr().add(offset).cast::<__m128i>(), packed);
242 }
243 } else {
244 resolve_scalar(
245 &symbols[offset..offset + 8],
246 &mut output[offset..offset + 8],
247 window,
248 )?;
249 }
250 }
251 resolve_scalar(&symbols[vectorized..], &mut output[vectorized..], window)
252}
253
254#[cfg(target_arch = "aarch64")]
255#[target_feature(enable = "neon")]
256unsafe fn resolve_neon(
257 symbols: &[Symbol],
258 output: &mut [u8],
259 window: &Window,
260) -> Result<(), MarkerError> {
261 use core::arch::aarch64::{
262 vandq_u16, vld1q_u16, vmaxvq_u16, vmovn_u16, vsetq_lane_u16, vst1_u8,
263 };
264
265 let vectorized = symbols.len() / 8 * 8;
266 let mut mask = unsafe { vld1q_u16([0xFF00_u16; 8].as_ptr()) };
269 mask = vsetq_lane_u16(0xFF00, mask, 0);
272 for offset in (0..vectorized).step_by(8) {
273 let values = unsafe { vld1q_u16(symbols.as_ptr().add(offset).cast::<u16>()) };
275 if vmaxvq_u16(vandq_u16(values, mask)) == 0 {
276 let packed = vmovn_u16(values);
277 unsafe { vst1_u8(output.as_mut_ptr().add(offset), packed) };
279 } else {
280 resolve_scalar(
281 &symbols[offset..offset + 8],
282 &mut output[offset..offset + 8],
283 window,
284 )?;
285 }
286 }
287 resolve_scalar(&symbols[vectorized..], &mut output[vectorized..], window)
288}
289
290#[derive(Clone, Debug, Eq, PartialEq)]
292pub enum MarkerError {
293 IndexOutOfRange(usize),
295 WindowTooLarge(usize),
297 WindowTooSmall {
299 required: usize,
301 actual: usize,
303 },
304}
305
306impl Display for MarkerError {
307 fn fmt(&self, formatter: &mut Formatter<'_>) -> fmt::Result {
308 match self {
309 Self::IndexOutOfRange(index) => {
310 write!(formatter, "marker index {index} is out of range")
311 }
312 Self::WindowTooLarge(size) => write!(formatter, "window size {size} exceeds 32768"),
313 Self::WindowTooSmall { required, actual } => write!(
314 formatter,
315 "marker requires {required} predecessor bytes, but only {actual} were supplied"
316 ),
317 }
318 }
319}
320
321impl Error for MarkerError {}
322
323#[cfg(test)]
324mod tests {
325 use super::{MarkerBuffer, Symbol, Window, resolve_scalar};
326 use proptest::prelude::*;
327
328 #[test]
329 fn resolves_full_window_markers() {
330 let window = Window::new((0..=255).cycle().take(32 * 1024).collect()).unwrap();
331 let buffer = MarkerBuffer::new(vec![
332 Symbol::literal(b'x'),
333 Symbol::marker(0).unwrap(),
334 Symbol::marker(32 * 1024 - 1).unwrap(),
335 ]);
336 assert_eq!(buffer.resolve(&window).unwrap(), [b'x', 0, 255]);
337 }
338
339 #[test]
340 fn partial_window_uses_newest_alignment() {
341 let window = Window::new(vec![10, 11, 12]).unwrap();
342 let buffer = MarkerBuffer::new(vec![Symbol::marker(32 * 1024 - 3).unwrap()]);
343 assert_eq!(buffer.resolve(&window).unwrap(), [10]);
344 }
345
346 #[test]
347 fn dispatched_resolution_matches_scalar_for_mixed_symbols() {
348 let window = Window::new(
349 (0..super::WINDOW_SIZE)
350 .map(|index| (index.wrapping_mul(37)) as u8)
351 .collect(),
352 )
353 .unwrap();
354 let symbols: Vec<_> = (0..65_537)
355 .map(|index| {
356 if index % 11 == 0 {
357 Symbol::marker(index % super::WINDOW_SIZE).unwrap()
358 } else {
359 Symbol::literal(index as u8)
360 }
361 })
362 .collect();
363 let mut scalar = vec![0; symbols.len()];
364 resolve_scalar(&symbols, &mut scalar, &window).unwrap();
365 let dispatched = MarkerBuffer::new(symbols).resolve(&window).unwrap();
366 assert_eq!(dispatched, scalar);
367 }
368
369 proptest! {
370 #[test]
371 fn dispatched_resolution_matches_scalar_for_arbitrary_valid_symbols(
372 encoded in prop::collection::vec(any::<u16>(), 0..4096)
373 ) {
374 let window = Window::new(
375 (0..super::WINDOW_SIZE)
376 .map(|index| (index.wrapping_mul(131)) as u8)
377 .collect(),
378 )
379 .unwrap();
380 let symbols: Vec<_> = encoded
381 .into_iter()
382 .map(|value| {
383 if value & 1 == 0 {
384 Symbol::literal((value >> 1) as u8)
385 } else {
386 Symbol::marker(usize::from(value) % super::WINDOW_SIZE).unwrap()
387 }
388 })
389 .collect();
390 let mut scalar = vec![0; symbols.len()];
391 resolve_scalar(&symbols, &mut scalar, &window).unwrap();
392 let dispatched = MarkerBuffer::new(symbols).resolve(&window).unwrap();
393 prop_assert_eq!(dispatched, scalar);
394 }
395 }
396}