#![cfg(all(feature = "simd-portable", feature = "opt-simd-body-comparison"))]
use core::simd::num::SimdUint;
use core::simd::{LaneCount, Simd, SupportedLaneCount, ToBytes};
static_assertions::const_assert_eq!(super::BODY_OUTLIER_VALUE, 6);
#[inline(always)]
fn distance<const N_8: usize, const N_32: usize>(body1: &[u8; N_8], body2: &[u8; N_8]) -> u32
where
LaneCount<N_8>: SupportedLaneCount,
LaneCount<N_32>: SupportedLaneCount,
Simd<u32, N_32>: ToBytes<Bytes = Simd<u8, N_8>>,
{
let x = Simd::<u32, N_32>::from_ne_bytes(Simd::<u8, N_8>::from_array(*body1));
let y = Simd::<u32, N_32>::from_ne_bytes(Simd::<u8, N_8>::from_array(*body2));
let z = x ^ y;
let mask_dibit_01 = Simd::<u32, N_32>::splat(0x55555555);
let mask_dibit_10 = Simd::<u32, N_32>::splat(0xaaaaaaaa);
let mask_nibble_0011 = Simd::<u32, N_32>::splat(0x33333333);
let mask_byte_00001111 = Simd::<u32, N_32>::splat(0x0f0f0f0f);
let value_dword_0x01010101 = Simd::<u32, N_32>::splat(0x01010101);
let ta = y & mask_dibit_01;
let tb = x & mask_dibit_01;
let ta = ta | (ta << 1); let tb = mask_dibit_10 - tb;
let ta = ta ^ x;
let tb = tb ^ x;
let sa = ta & z; let tb = tb & z;
let ta = sa >> 2;
let sa = sa & mask_nibble_0011;
let tb = tb >> 1;
let ta = ta & mask_nibble_0011;
let tb = tb | (tb << 1); let sa = sa + ta; let sb = tb & z; let tb = sb >> 2;
let sb = sb & mask_nibble_0011;
let tb = tb & mask_nibble_0011;
let sb = sb + tb;
let s = sb + sa; let t = s >> 4;
let s = s & mask_byte_00001111;
let t = t & mask_byte_00001111;
let s = s + t; let s = (s * value_dword_0x01010101) >> 24; s.reduce_sum()
}
#[inline]
pub fn distance_32(body1: &[u8; 32], body2: &[u8; 32]) -> u32 {
distance::<32, 8>(body1, body2)
}
#[inline]
pub fn distance_64(body1: &[u8; 64], body2: &[u8; 64]) -> u32 {
distance::<64, 16>(body1, body2)
}