use core::mem;
use super::fallback;
#[must_use]
#[inline]
pub fn contains_null_or_utf8_4_byte_char_header(value: &[u8]) -> bool {
test_word_any(
value,
fallback::contains_null_or_utf8_4_byte_char_header,
word_contains_null_or_utf8_4_byte_char_header,
)
}
#[must_use]
#[inline]
fn word_contains_null_or_utf8_4_byte_char_header(word: usize) -> bool {
word_contains_null_byte(word) || word_contains_utf8_4_byte_char_header(word)
}
#[must_use]
#[inline]
pub fn contains_utf8_4_byte_char_header(value: &[u8]) -> bool {
test_word_any(
value,
fallback::contains_utf8_4_byte_char_header,
word_contains_utf8_4_byte_char_header,
)
}
#[must_use]
#[inline]
fn word_contains_utf8_4_byte_char_header(word: usize) -> bool {
const MASK: usize = usize_repeat_u8(0b1111_1000);
const HEADER: usize = usize_repeat_u8(0b1111_0000);
word_contains_null_byte((word & MASK) ^ HEADER)
}
#[must_use]
#[inline]
fn word_contains_null_byte(word: usize) -> bool {
const LOW_MASK: usize = usize_repeat_u8(0x01);
const HIGH_MASK: usize = usize_repeat_u8(0x80);
(word.wrapping_sub(LOW_MASK) & !word & HIGH_MASK) != 0
}
#[must_use]
#[inline]
const fn usize_repeat_u8(byte: u8) -> usize {
usize::from_ne_bytes([byte; USIZE_SIZE])
}
#[must_use]
#[inline]
fn test_word_any<F, T>(value: &[u8], fallback: F, test: T) -> bool
where
F: Fn(&[u8]) -> bool,
T: Fn(usize) -> bool,
{
let len = value.len();
let start_ptr = value.as_ptr();
let align_offset = start_ptr.align_offset(USIZE_SIZE);
if len < USIZE_SIZE || len < align_offset || USIZE_SIZE < mem::align_of::<usize>() {
return fallback(value);
}
let offset_to_aligned = if align_offset == 0 {
USIZE_SIZE
} else {
align_offset
};
let first_word = unsafe { start_ptr.cast::<usize>().read_unaligned() };
if test(first_word) {
return true;
}
#[allow(clippy::cast_ptr_alignment)]
let mut word_ptr = unsafe { start_ptr.add(offset_to_aligned).cast::<usize>() };
let mut byte_position = offset_to_aligned;
while byte_position < len - USIZE_SIZE {
let word = unsafe { word_ptr.read() };
if test(word) {
return true;
}
byte_position += USIZE_SIZE;
word_ptr = unsafe { word_ptr.add(1) };
}
#[allow(clippy::cast_ptr_alignment)]
let last_word_ptr = unsafe { start_ptr.add(len - USIZE_SIZE).cast::<usize>() };
let last_word = unsafe { last_word_ptr.read_unaligned() };
test(last_word)
}
const USIZE_SIZE: usize = mem::size_of::<usize>();