use crate::types::Hash;
#[inline]
pub fn hash_eq(hash1: &Hash, hash2: &Hash) -> bool {
#[cfg(all(target_arch = "x86_64", feature = "production"))]
{
if is_avx2_available() {
unsafe { hash_eq_avx2(hash1, hash2) }
} else {
hash_eq_fallback(hash1, hash2)
}
}
#[cfg(not(all(target_arch = "x86_64", feature = "production")))]
{
hash_eq_fallback(hash1, hash2)
}
}
#[inline(always)]
fn hash_eq_fallback(hash1: &Hash, hash2: &Hash) -> bool {
hash1 == hash2
}
#[cfg(all(target_arch = "x86_64", feature = "production"))]
#[target_feature(enable = "avx2")]
unsafe fn hash_eq_avx2(hash1: &Hash, hash2: &Hash) -> bool {
use std::arch::x86_64::*;
let h1 = _mm256_loadu_si256(hash1.as_ptr() as *const __m256i);
let h2 = _mm256_loadu_si256(hash2.as_ptr() as *const __m256i);
let cmp = _mm256_cmpeq_epi8(h1, h2);
let mask = _mm256_movemask_epi8(cmp);
mask == -1i32
}
#[cfg(all(target_arch = "x86_64", feature = "production"))]
fn is_avx2_available() -> bool {
std::arch::is_x86_feature_detected!("avx2")
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_hash_eq_identical() {
let hash1 = [0u8; 32];
let hash2 = [0u8; 32];
assert!(hash_eq(&hash1, &hash2));
}
#[test]
fn test_hash_eq_different() {
let hash1 = [0u8; 32];
let mut hash2 = [0u8; 32];
hash2[0] = 1;
assert!(!hash_eq(&hash1, &hash2));
}
#[test]
fn test_hash_eq_different_last_byte() {
let mut hash1 = [0u8; 32];
let mut hash2 = [0u8; 32];
hash1[31] = 0;
hash2[31] = 1;
assert!(!hash_eq(&hash1, &hash2));
}
#[test]
fn test_hash_eq_random() {
let hash1: Hash = [
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
25, 26, 27, 28, 29, 30, 31, 32,
];
let hash2: Hash = [
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
25, 26, 27, 28, 29, 30, 31, 33,
];
assert_eq!(hash_eq(&hash1, &hash1), hash1 == hash1);
assert_eq!(hash_eq(&hash1, &hash2), hash1 == hash2);
}
}