/*!
Wrapper routines for `memchr` and friends.

These routines choose the best implementation at compile time. (This is
different from `x86_64` because it is expected that `neon` is almost always
available for `aarch64` targets.)
*/

macro_rules! defraw {
    ($ty:ident, $find:ident, $start:ident, $end:ident, $($needles:ident),+) => {{
        #[cfg(target_feature = "neon")]
        {
            use crate::arch::aarch64::neon::memchr::$ty;

            debug!("chose neon for {}", stringify!($ty));
            debug_assert!($ty::is_available());
            // SAFETY: We know that wasm memchr is always available whenever
            // code is compiled for `aarch64` with the `neon` target feature
            // enabled.
            $ty::new_unchecked($($needles),+).$find($start, $end)
        }
        #[cfg(not(target_feature = "neon"))]
        {
            use crate::arch::all::memchr::$ty;

            debug!(
                "no neon feature available, using fallback for {}",
                stringify!($ty),
            );
            $ty::new($($needles),+).$find($start, $end)
        }
    }}
}

/// memchr, but using raw pointers to represent the haystack.
///
/// # Safety
///
/// Pointers must be valid. See `One::find_raw`.
#[inline(always)]
pub(crate) unsafe fn memchr_raw(
    n1: u8,
    start: *const u8,
    end: *const u8,
) -> Option<*const u8> {
    defraw!(One, find_raw, start, end, n1)
}

/// memrchr, but using raw pointers to represent the haystack.
///
/// # Safety
///
/// Pointers must be valid. See `One::rfind_raw`.
#[inline(always)]
pub(crate) unsafe fn memrchr_raw(
    n1: u8,
    start: *const u8,
    end: *const u8,
) -> Option<*const u8> {
    defraw!(One, rfind_raw, start, end, n1)
}

/// memchr2, but using raw pointers to represent the haystack.
///
/// # Safety
///
/// Pointers must be valid. See `Two::find_raw`.
#[inline(always)]
pub(crate) unsafe fn memchr2_raw(
    n1: u8,
    n2: u8,
    start: *const u8,
    end: *const u8,
) -> Option<*const u8> {
    defraw!(Two, find_raw, start, end, n1, n2)
}

/// memrchr2, but using raw pointers to represent the haystack.
///
/// # Safety
///
/// Pointers must be valid. See `Two::rfind_raw`.
#[inline(always)]
pub(crate) unsafe fn memrchr2_raw(
    n1: u8,
    n2: u8,
    start: *const u8,
    end: *const u8,
) -> Option<*const u8> {
    defraw!(Two, rfind_raw, start, end, n1, n2)
}

/// memchr3, but using raw pointers to represent the haystack.
///
/// # Safety
///
/// Pointers must be valid. See `Three::find_raw`.
#[inline(always)]
pub(crate) unsafe fn memchr3_raw(
    n1: u8,
    n2: u8,
    n3: u8,
    start: *const u8,
    end: *const u8,
) -> Option<*const u8> {
    defraw!(Three, find_raw, start, end, n1, n2, n3)
}

/// memrchr3, but using raw pointers to represent the haystack.
///
/// # Safety
///
/// Pointers must be valid. See `Three::rfind_raw`.
#[inline(always)]
pub(crate) unsafe fn memrchr3_raw(
    n1: u8,
    n2: u8,
    n3: u8,
    start: *const u8,
    end: *const u8,
) -> Option<*const u8> {
    defraw!(Three, rfind_raw, start, end, n1, n2, n3)
}

/// Count all matching bytes, but using raw pointers to represent the haystack.
///
/// # Safety
///
/// Pointers must be valid. See `One::count_raw`.
#[inline(always)]
pub(crate) unsafe fn count_raw(
    n1: u8,
    start: *const u8,
    end: *const u8,
) -> usize {
    defraw!(One, count_raw, start, end, n1)
}
