use std::arch::aarch64::*;
pub unsafe fn search_non_ident_neon(haystack: &[u8]) -> Option<usize> {
let len = haystack.len();
if len < 16 {
return super::fallback::search_non_ident(haystack);
}
let ptr = haystack.as_ptr();
let mut offset = 0;
while offset + 16 <= len {
let chunk = vld1q_u8(ptr.add(offset));
let is_ident = is_ident_chunk(chunk);
if has_zero_byte(is_ident) {
let mask = movemask_zero_bytes(is_ident);
let pos = (mask.trailing_zeros() as usize) >> 2;
return Some(offset + pos);
}
offset += 16;
}
if offset < len {
super::fallback::search_non_ident(&haystack[offset..]).map(|x| offset + x)
} else {
None
}
}
#[inline(always)]
unsafe fn is_ident_chunk(chunk: uint8x16_t) -> uint8x16_t {
let lower = vorrq_u8(chunk, vdupq_n_u8(0x20));
let letter_offset = vsubq_u8(lower, vdupq_n_u8(b'a'));
let is_letter = vcltq_u8(letter_offset, vdupq_n_u8(26));
let digit_offset = vsubq_u8(chunk, vdupq_n_u8(b'0'));
let is_digit = vcltq_u8(digit_offset, vdupq_n_u8(10));
let is_hyphen = vceqq_u8(chunk, vdupq_n_u8(b'-'));
let is_underscore = vceqq_u8(chunk, vdupq_n_u8(b'_'));
let is_slash = vceqq_u8(chunk, vdupq_n_u8(b'/'));
let is_colon = vceqq_u8(chunk, vdupq_n_u8(b':'));
let is_plus = vceqq_u8(chunk, vdupq_n_u8(b'+'));
let is_alnum = vorrq_u8(is_letter, is_digit);
let is_special1 = vorrq_u8(is_hyphen, is_underscore);
let is_special2 = vorrq_u8(is_slash, is_colon);
let is_special3 = vorrq_u8(is_special2, is_plus);
let is_special = vorrq_u8(is_special1, is_special3);
vorrq_u8(is_alnum, is_special)
}
#[inline(always)]
unsafe fn has_zero_byte(v: uint8x16_t) -> bool {
vminvq_u8(v) != 0xFF
}
#[inline(always)]
unsafe fn movemask_zero_bytes(v: uint8x16_t) -> u64 {
let zero_mask = vceqzq_u8(v);
let as_u16 = vreinterpretq_u16_u8(zero_mask);
let narrowed = vshrn_n_u16(as_u16, 4);
let as_u64 = vreinterpret_u64_u8(narrowed);
vget_lane_u64(as_u64, 0)
}