use std::sync::OnceLock;
use crate::{AllMasks, DelimiterResult};
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
pub enum SimdLevel {
Scalar,
Sse42,
Avx2,
Neon,
}
pub fn detect() -> SimdLevel {
#[cfg(target_arch = "x86_64")]
{
if is_x86_feature_detected!("avx2") {
return SimdLevel::Avx2;
}
if is_x86_feature_detected!("sse4.2") {
return SimdLevel::Sse42;
}
}
#[cfg(target_arch = "aarch64")]
{
return SimdLevel::Neon;
}
#[allow(unreachable_code)]
SimdLevel::Scalar
}
pub struct SimdOps {
pub find_delimiters: unsafe fn(&[u8]) -> DelimiterResult,
pub classify_bytes: unsafe fn(&[u8]) -> Vec<u8>,
pub skip_whitespace: unsafe fn(&[u8]) -> usize,
pub compute_byte_mask: unsafe fn(&[u8], u8) -> u64,
pub compute_all_masks: unsafe fn(&[u8]) -> AllMasks,
pub level: SimdLevel,
}
static SIMD_OPS: OnceLock<SimdOps> = OnceLock::new();
pub fn ops() -> &'static SimdOps {
SIMD_OPS.get_or_init(|| {
let level = detect();
match level {
#[cfg(target_arch = "x86_64")]
SimdLevel::Avx2 => SimdOps {
find_delimiters: crate::avx2::find_delimiters,
classify_bytes: crate::avx2::classify_bytes,
skip_whitespace: crate::avx2::skip_whitespace,
compute_byte_mask: crate::avx2::compute_byte_mask,
compute_all_masks: crate::scalar::compute_all_masks,
level,
},
#[cfg(target_arch = "x86_64")]
SimdLevel::Sse42 => SimdOps {
find_delimiters: crate::sse42::find_delimiters,
classify_bytes: crate::sse42::classify_bytes,
skip_whitespace: crate::sse42::skip_whitespace,
compute_byte_mask: crate::sse42::compute_byte_mask,
compute_all_masks: crate::scalar::compute_all_masks,
level,
},
#[cfg(target_arch = "aarch64")]
SimdLevel::Neon => SimdOps {
find_delimiters: crate::neon::find_delimiters,
classify_bytes: crate::neon::classify_bytes,
skip_whitespace: crate::neon::skip_whitespace,
compute_byte_mask: crate::neon::compute_byte_mask,
compute_all_masks: crate::neon::compute_all_masks,
level,
},
_ => SimdOps {
find_delimiters: crate::scalar::find_delimiters,
classify_bytes: crate::scalar::classify_bytes,
skip_whitespace: crate::scalar::skip_whitespace,
compute_byte_mask: crate::scalar::compute_byte_mask,
compute_all_masks: crate::scalar::compute_all_masks,
level: SimdLevel::Scalar,
},
}
})
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn detect_returns_valid_level() {
let level = detect();
assert!(level >= SimdLevel::Scalar);
}
#[test]
fn ops_singleton_is_consistent() {
let a = ops();
let b = ops();
assert!(std::ptr::eq(a, b));
}
#[test]
fn ops_level_matches_detect() {
let o = ops();
let detected = detect();
assert_eq!(o.level, detected);
}
#[test]
fn dispatch_find_delimiters() {
let o = ops();
let input = b"hello <world>";
let result = unsafe { (o.find_delimiters)(input) };
assert_eq!(result, crate::DelimiterResult::Found { pos: 6, byte: b'<' });
}
#[test]
fn dispatch_classify_bytes() {
let o = ops();
let input = b"a1 <";
let result = unsafe { (o.classify_bytes)(input) };
assert_eq!(result[0], crate::class::ALPHA);
assert_eq!(result[1], crate::class::DIGIT);
assert_eq!(result[2], crate::class::WHITESPACE);
assert_eq!(result[3], crate::class::DELIMITER);
}
#[test]
fn dispatch_skip_whitespace() {
let o = ops();
let input = b" hello";
let result = unsafe { (o.skip_whitespace)(input) };
assert_eq!(result, 3);
}
#[test]
fn dispatch_compute_byte_mask() {
let o = ops();
let input = b"hello <world> & end";
let mask = unsafe { (o.compute_byte_mask)(input, b'<') };
assert_eq!(mask, 1 << 6);
}
#[test]
fn dispatch_compute_byte_mask_over_64_bytes_does_not_overflow() {
let o = ops();
let input = vec![b'<'; 80];
let mask = unsafe { (o.compute_byte_mask)(&input, b'<') };
assert_eq!(mask, u64::MAX);
let masks = unsafe { (o.compute_all_masks)(&input) };
assert_eq!(masks.lt, u64::MAX);
}
#[test]
fn dispatch_compute_byte_mask_matches_scalar() {
let o = ops();
let input = b"Hello <World> & \"test\" = 'value' / 123\n\r\t end!!";
for &byte in b"<>&\"'=/" {
let dispatched = unsafe { (o.compute_byte_mask)(input, byte) };
let scalar = unsafe { crate::scalar::compute_byte_mask(input, byte) };
assert_eq!(dispatched, scalar, "mismatch for byte 0x{byte:02X}");
}
}
#[test]
fn dispatch_matches_scalar() {
let o = ops();
let input = b"Hello <World> & \"test\" = 'value' / 123\n\r\t end";
let dispatched = unsafe { (o.classify_bytes)(input) };
let scalar = unsafe { crate::scalar::classify_bytes(input) };
assert_eq!(dispatched, scalar);
}
#[test]
fn dispatch_compute_all_masks() {
let o = ops();
let input = b"Hello <World> & \"test\" = 'value' / 123\n\r\t end!!";
let dispatched = unsafe { (o.compute_all_masks)(input) };
let scalar = crate::scalar::compute_all_masks_safe(input);
assert_eq!(dispatched.lt, scalar.lt, "lt mismatch");
assert_eq!(dispatched.gt, scalar.gt, "gt mismatch");
assert_eq!(dispatched.quot, scalar.quot, "quot mismatch");
assert_eq!(dispatched.apos, scalar.apos, "apos mismatch");
}
}