use crate::char::{KernelFn, Wide};
mod avx2;
#[cfg(feature = "unstable")]
mod evex;
mod sse2;
#[inline(always)]
pub fn wmemchr<T: Wide>(needle: T, haystack: &[T]) -> Option<usize> {
T::wmemchr_x86_64(needle, haystack)
}
macro_rules! unsafe_ifuncs {
($(
fn $ty:ident::$name:ident($($arg:ident: $arg_ty:ty),* $(,)?) $(-> $ret_ty:ty)?;
)*) => {
$(
unsafe_ifuncs! {
@__item
[$ty]
[$name]
[$($arg: $arg_ty),*]
[$($ret_ty)?]
[fn($($arg_ty),*) $(-> $ret_ty)?]
}
)*
};
(@__item [$ty:ident] [$name:ident] [$($arg:ident: $arg_ty:ty),*] [$($ret_ty:ty)?] [$fn_ty:ty]) => {
mod $ty {
use core::mem;
use core::sync::atomic::{AtomicPtr, Ordering};
type FnRaw = *mut ();
static FN: AtomicPtr<()> = AtomicPtr::new(detect as FnRaw);
fn detect($($arg: $arg_ty),*) $(-> $ret_ty)? {
#[inline(always)]
fn select() -> FnRaw {
if is_x86_feature_detected!("avx2") {
#[cfg(feature = "unstable")]
{
if is_x86_feature_detected!("avx512vl") && is_x86_feature_detected!("avx512bw") {
return super::evex::$ty::$name as FnRaw;
}
}
super::avx2::$ty::$name as FnRaw
} else {
super::sse2::$ty::$name as FnRaw
}
}
let f = select();
FN.store(f, Ordering::Relaxed);
unsafe {
(mem::transmute::<FnRaw, $fn_ty>(f))($($arg),*)
}
}
#[inline(always)]
pub unsafe fn $name($($arg: $arg_ty),*) $(-> $ret_ty)? {
let f = FN.load(Ordering::Relaxed);
(mem::transmute::<FnRaw, $fn_ty>(f))($($arg),*)
}
}
}
}
unsafe_ifuncs! {
fn i16::wmemchr(needle: i16, haystack: *const i16, len: usize) -> Option<usize>;
fn i32::wmemchr(needle: i32, haystack: *const i32, len: usize) -> Option<usize>;
}
pub(crate) struct Kernel;
impl KernelFn<u16> for Kernel {
fn kernel(needle: u16, haystack: &[u16]) -> Option<usize> {
unsafe {
i16::wmemchr(
needle as i16,
haystack.as_ptr() as *const i16,
haystack.len(),
)
}
}
}
impl KernelFn<i16> for Kernel {
fn kernel(needle: i16, haystack: &[i16]) -> Option<usize> {
unsafe { i16::wmemchr(needle, haystack.as_ptr(), haystack.len()) }
}
}
impl KernelFn<u32> for Kernel {
fn kernel(needle: u32, haystack: &[u32]) -> Option<usize> {
unsafe {
i32::wmemchr(
needle as i32,
haystack.as_ptr() as *const i32,
haystack.len(),
)
}
}
}
impl KernelFn<i32> for Kernel {
fn kernel(needle: i32, haystack: &[i32]) -> Option<usize> {
unsafe { i32::wmemchr(needle, haystack.as_ptr(), haystack.len()) }
}
}