use crate::decoding::buffer_backend::BufferBackend;
use crate::decoding::decode_buffer::DecodeBuffer;
use crate::decoding::user_slice_buf::UserSliceBackend;
extern crate std;
use alloc::vec;
use alloc::vec::Vec;
fn literals(len: usize) -> Vec<u8> {
(0..len).map(|i| (i % 251) as u8 + 1).collect()
}
fn dictionary(len: usize) -> Vec<u8> {
(0..len).map(|i| 255 - (i % 251) as u8).collect()
}
fn expected(lits: &[u8], lit_length: usize, dict: &[u8], match_length: usize) -> Vec<u8> {
let mut want = Vec::with_capacity(lit_length + match_length);
want.extend_from_slice(&lits[..lit_length]);
want.extend_from_slice(&dict[..match_length]);
want
}
fn run_default(
lit_length: usize,
match_length: usize,
dict_room: usize,
tail_slack: usize,
) -> Vec<u8> {
let lits = literals(lit_length.max(16) + 64);
let dict = dictionary(match_length + dict_room);
let mut out = vec![0u8; lit_length + match_length + tail_slack];
let backend = UserSliceBackend::from_slice(out.as_mut_slice());
let mut buf = DecodeBuffer::from_backend(backend, 1 << 20);
unsafe {
buf.buffer_mut()
.exec_sequence_inline_dict(lits.as_ptr(), lit_length, &dict, match_length)
.expect("the output was sized for this sequence");
}
let written = buf.buffer_mut().tail();
assert_eq!(
written,
lit_length + match_length,
"the copier must advance the cursor by exactly the sequence"
);
out[..written].to_vec()
}
#[test]
fn dictionary_copy_writes_the_sequence_in_every_shape() {
for &(lit_length, match_length, dict_room, tail_slack, what) in &[
(20usize, 40usize, 64usize, 64usize, "room to over-read"),
(20, 40, 0, 64, "dictionary ends at the match"),
(20, 40, 64, 0, "no room past the output"),
(20, 40, 0, 0, "neither has room"),
(0, 3, 64, 64, "no literals, shortest legal match"),
(17, 17, 1, 64, "both lengths just past one stride"),
(
64,
200,
3,
64,
"long match, dictionary ends inside the stride",
),
] {
let lits = literals(lit_length.max(16) + 64);
let dict = dictionary(match_length + dict_room);
assert_eq!(
run_default(lit_length, match_length, dict_room, tail_slack),
expected(&lits, lit_length, &dict, match_length),
"dictionary copy wrote the wrong bytes with {what}"
);
}
}
#[cfg(all(target_arch = "x86_64", feature = "kernel-avx2"))]
#[test]
fn avx2_dictionary_copy_matches_the_tier_neutral_body() {
if !std::arch::is_x86_feature_detected!("avx2") {
return;
}
for &(lit_length, match_length, dict_room, tail_slack) in &[
(20usize, 40usize, 64usize, 64usize),
(20, 40, 0, 64),
(20, 40, 64, 0),
(20, 40, 0, 0),
(0, 3, 64, 64),
(17, 17, 1, 64),
(64, 200, 3, 64),
(33, 48, 20, 64),
] {
let lits = literals(lit_length.max(16) + 64);
let dict = dictionary(match_length + dict_room);
let mut out = vec![0u8; lit_length + match_length + tail_slack];
let backend = UserSliceBackend::from_slice(out.as_mut_slice());
let mut buf = DecodeBuffer::from_backend(backend, 1 << 20);
let result =
exec_sequence_avx2_dict_inline!(buf, lits.as_ptr(), lit_length, &dict, match_length);
result.expect("the output was sized for this sequence");
let written = buf.buffer_mut().tail();
assert_eq!(written, lit_length + match_length);
assert_eq!(
out[..written].to_vec(),
run_default(lit_length, match_length, dict_room, tail_slack),
"the AVX2 dictionary copy diverged from the tier-neutral one at \
lit={lit_length} ml={match_length} room={dict_room} slack={tail_slack}"
);
}
}