use core::hash::{BuildHasher, Hasher};
#[allow(unused_variables)]
unsafe fn hash_long_simd(ptr: *const u8, len: usize, acc: u64) -> u64 {
#[cfg(target_arch = "aarch64")]
{
if std::arch::is_aarch64_feature_detected!("neon") {
return unsafe { crate::backend::aarch64::hash_bytes_long(ptr, len, acc) };
}
}
#[cfg(target_arch = "x86_64")]
{
if std::arch::is_x86_feature_detected!("avx2") {
return unsafe { crate::backend::x86_64::hash_bytes_long(ptr, len, acc) };
}
}
unsafe { crate::backend::scalar::hash_bytes_long(ptr, len, acc) }
}
#[test]
fn backend_parity_short_inputs() {
let seed = 0x1234_5678_9abc_def0u64;
let data = vec![0xABu8; 128];
for len in [0usize, 1, 8, 16, 17, 32, 33, 64, 65, 96, 128] {
let slice = &data[..len];
let h1 = crate::axhash_seeded(slice, seed);
let h2 = crate::axhash_seeded(slice, seed);
assert_eq!(h1, h2, "non-deterministic at len={}", len);
}
}
#[test]
fn backend_parity_scalar_vs_simd_long_all_lengths() {
let seed = 0x1234_5678_9abc_def0u64;
let data: Vec<u8> = (0..2048u32).map(|i| (i as u8).wrapping_mul(7)).collect();
for len in 129..=2048usize {
let slice = &data[..len];
let acc = crate::math::seed_lane(seed, 0).rotate_right(len as u32);
let scalar = unsafe { crate::backend::scalar::hash_bytes_long(slice.as_ptr(), len, acc) };
let simd = unsafe { hash_long_simd(slice.as_ptr(), len, acc) };
assert_eq!(
scalar, simd,
"scalar != simd at len={} (scalar=0x{:016x}, simd=0x{:016x})",
len, scalar, simd,
);
}
}
#[test]
fn backend_parity_scalar_vs_simd_long_diverse_seeds() {
let seeds = [
0u64,
1,
0xFFFF_FFFF_FFFF_FFFF,
0xDEAD_BEEF_CAFE_BABE,
0x0123_4567_89AB_CDEF,
0x9999_AAAA_BBBB_CCCC,
];
let lens = [129usize, 130, 191, 192, 193, 255, 256, 257, 511, 512, 1023, 1024, 1025, 2048];
let data: Vec<u8> = (0..2048u32).map(|i| (i as u8).wrapping_mul(13)).collect();
for &seed in &seeds {
for &len in &lens {
let slice = &data[..len];
let acc = crate::math::seed_lane(seed, 0).rotate_right(len as u32);
let scalar = unsafe {
crate::backend::scalar::hash_bytes_long(slice.as_ptr(), len, acc)
};
let simd = unsafe { hash_long_simd(slice.as_ptr(), len, acc) };
assert_eq!(
scalar, simd,
"scalar != simd at seed=0x{:016x} len={}",
seed, len
);
}
}
}
#[test]
fn backend_parity_scalar_vs_simd_long_diverse_patterns() {
let seed = 0x7777_8888_9999_AAAAu64;
let lens = [200usize, 256, 333, 500, 777, 1024];
let patterns: Vec<(&str, Box<dyn Fn(usize) -> Vec<u8>>)> = vec![
("zeros", Box::new(|n| vec![0x00; n])),
("ones", Box::new(|n| vec![0xFF; n])),
("a5", Box::new(|n| vec![0xA5; n])),
("ascending", Box::new(|n| (0..n).map(|i| i as u8).collect())),
(
"descending",
Box::new(|n| (0..n).map(|i| 255u8.wrapping_sub(i as u8)).collect()),
),
("xor55", Box::new(|n| (0..n).map(|i| (i as u8) ^ 0x55).collect())),
];
for (label, make) in &patterns {
for &len in &lens {
let data = make(len);
let acc = crate::math::seed_lane(seed, 0).rotate_right(len as u32);
let scalar = unsafe {
crate::backend::scalar::hash_bytes_long(data.as_ptr(), len, acc)
};
let simd = unsafe { hash_long_simd(data.as_ptr(), len, acc) };
assert_eq!(
scalar, simd,
"scalar != simd pattern={} len={}",
label, len
);
}
}
}
#[test]
fn backend_api_paths_consistent_all_lengths() {
let seed = 0xDEAD_BEEF_CAFE_BABEu64;
let data: Vec<u8> = (0..1024u32).map(|i| (i as u8).wrapping_mul(11)).collect();
for len in [
0usize, 1, 7, 8, 15, 16, 17, 31, 32, 33, 63, 64, 65, 96, 128, 129, 200, 256, 500, 1024,
] {
let slice = &data[..len];
let one_shot = crate::axhash_seeded(slice, seed);
let mut stream = crate::AxHasher::new_with_seed(seed);
stream.write(slice);
let streaming = stream.finish();
let builder = crate::AxBuildHasher::with_seed(seed);
let mut from_builder = builder.build_hasher();
from_builder.write(slice);
let built = from_builder.finish();
assert_eq!(one_shot, streaming, "one_shot != streaming at len={}", len);
assert_eq!(one_shot, built, "one_shot != built at len={}", len);
}
}