#![allow(clippy::unwrap_used, reason = "allow in test files")]
#![allow(clippy::undocumented_unsafe_blocks, reason = "allow in test files")]
#![allow(clippy::indexing_slicing, reason = "allow in test files")]
#[cfg(all(target_arch = "x86_64", feature = "avx2"))]
use std::mem::size_of;
use std::num::NonZeroUsize;
fn nz(value: usize) -> NonZeroUsize {
NonZeroUsize::new(value).expect("test value must be non-zero")
}
#[test]
fn limit_changes_u8_clamps_to_src_range() {
let mut dest = [0_u8, 50, 120, 250];
let src = [10_u8, 40, 100, 240];
unsafe {
super::rust::limit_changes::<u8>(
dest.as_mut_ptr().cast(),
nz(4),
src.as_ptr().cast(),
nz(4),
nz(4),
nz(1),
8,
);
}
assert_eq!(dest, [2, 48, 108, 248]);
}
#[test]
fn limit_changes_u8_limit_zero_copies_src() {
let mut dest = [5_u8, 6, 7, 8, 9, 10];
let src = [100_u8, 90, 80, 70, 60, 50];
unsafe {
super::rust::limit_changes::<u8>(
dest.as_mut_ptr().cast(),
nz(6),
src.as_ptr().cast(),
nz(6),
nz(6),
nz(1),
0,
);
}
assert_eq!(dest, src);
}
#[test]
fn limit_changes_u16_limit_max_keeps_dest() {
let mut dest = [0_u16, 1, 1200, 32_000, 65_535];
let original_dest = dest;
let src = [65_535_u16, 22, 9, 7, 0];
unsafe {
super::rust::limit_changes::<u16>(
dest.as_mut_ptr().cast(),
nz(dest.len() * size_of::<u16>()),
src.as_ptr().cast(),
nz(src.len() * size_of::<u16>()),
nz(dest.len()),
nz(1),
u16::MAX,
);
}
assert_eq!(dest, original_dest);
}
#[test]
fn limit_changes_u16_respects_multirow_byte_strides() {
let width = 3;
let height = 3;
let stride = 5;
let mut dest = [
100_u16, 200, 300, 9999, 9999, 400, 500, 600, 9999, 9999, 700, 800, 900, 9999, 9999,
];
let src = [
150_u16, 150, 150, 77, 77, 500, 500, 500, 88, 88, 1000, 1000, 1000, 99, 99,
];
unsafe {
super::rust::limit_changes::<u16>(
dest.as_mut_ptr().cast(),
nz(stride * size_of::<u16>()),
src.as_ptr().cast(),
nz(stride * size_of::<u16>()),
nz(width),
nz(height),
50,
);
}
assert_eq!(dest[0], 100);
assert_eq!(dest[1], 200);
assert_eq!(dest[2], 200);
assert_eq!(dest[5], 450);
assert_eq!(dest[6], 500);
assert_eq!(dest[7], 550);
assert_eq!(dest[10], 950);
assert_eq!(dest[11], 950);
assert_eq!(dest[12], 950);
assert_eq!(dest[3], 9999);
assert_eq!(dest[4], 9999);
assert_eq!(dest[8], 9999);
assert_eq!(dest[9], 9999);
assert_eq!(dest[13], 9999);
assert_eq!(dest[14], 9999);
}
#[cfg(all(target_arch = "x86_64", feature = "avx2"))]
const LIMIT_WIDTHS: &[usize] = &[1, 2, 3, 4, 5, 7, 8, 9, 15, 16, 17, 31, 32, 33, 63, 64];
#[cfg(all(target_arch = "x86_64", feature = "avx2"))]
const LIMIT_HEIGHTS: &[usize] = &[1, 2, 3, 5, 8];
#[cfg(all(target_arch = "x86_64", feature = "avx2"))]
#[test]
fn limit_changes_u8_avx2_matches_rust_varied_shapes_and_limits() {
for &width in LIMIT_WIDTHS {
for &height in LIMIT_HEIGHTS {
for padding in [0, 3, 17] {
let stride = width + padding;
let mut src = vec![0_u8; stride * height];
let mut rust_dest = vec![0_u8; stride * height];
for y in 0..height {
for x in 0..width {
src[y * stride + x] = ((y * 37 + x * 11 + 13) & 0xff) as u8;
rust_dest[y * stride + x] = ((y * 19 + x * 23 + 251) & 0xff) as u8;
}
src[y * stride] = 0;
src[y * stride + width - 1] = u8::MAX;
rust_dest[y * stride] = u8::MAX;
rust_dest[y * stride + width - 1] = 0;
}
let avx_dest = rust_dest.clone();
for limit in [0_u16, 1, 2, 7, 15, 31, 127, 255] {
let mut rust_run = rust_dest.clone();
let mut avx_run = avx_dest.clone();
unsafe {
super::rust::limit_changes::<u8>(
rust_run.as_mut_ptr().cast(),
nz(stride),
src.as_ptr().cast(),
nz(stride),
nz(width),
nz(height),
limit,
);
super::avx2::limit_changes_u8(
avx_run.as_mut_ptr().cast(),
nz(stride),
src.as_ptr().cast(),
nz(stride),
nz(width),
nz(height),
limit,
);
}
assert_eq!(
avx_run, rust_run,
"u8 mismatch at {width}x{height}, stride={stride}, limit={limit}"
);
}
}
}
}
}
#[cfg(all(target_arch = "x86_64", feature = "avx2"))]
#[test]
fn limit_changes_u16_avx2_matches_rust_varied_shapes_and_limits() {
for &width in LIMIT_WIDTHS {
for &height in LIMIT_HEIGHTS {
for padding in [0, 2, 9] {
let stride = width + padding;
let mut src = vec![0_u16; stride * height];
let mut rust_dest = vec![0_u16; stride * height];
for y in 0..height {
for x in 0..width {
src[y * stride + x] = ((y * 541 + x * 173 + 19) % 65_536) as u16;
rust_dest[y * stride + x] = ((y * 997 + x * 431 + 7) % 65_536) as u16;
}
src[y * stride] = 0;
src[y * stride + width - 1] = u16::MAX;
rust_dest[y * stride] = u16::MAX;
rust_dest[y * stride + width - 1] = 0;
}
let avx_dest = rust_dest.clone();
for limit in [0_u16, 1, 2, 15, 255, 1023, 32_767, 65_535] {
let mut rust_run = rust_dest.clone();
let mut avx_run = avx_dest.clone();
unsafe {
super::rust::limit_changes::<u16>(
rust_run.as_mut_ptr().cast(),
nz(stride * size_of::<u16>()),
src.as_ptr().cast(),
nz(stride * size_of::<u16>()),
nz(width),
nz(height),
limit,
);
super::avx2::limit_changes_u16(
avx_run.as_mut_ptr().cast(),
nz(stride * size_of::<u16>()),
src.as_ptr().cast(),
nz(stride * size_of::<u16>()),
nz(width),
nz(height),
limit,
);
}
assert_eq!(
avx_run, rust_run,
"u16 mismatch at {width}x{height}, stride={stride}, limit={limit}"
);
}
}
}
}
}