use core::{mem, ops, u64};
pub trait Bytes: Sized {
fn splat(byte: u8) -> Self;
fn bytes_eq(self, other: Self) -> Self;
fn increment(self, incr: Self) -> Self;
fn sum(self) -> usize;
fn contains_zero_byte(self) -> bool;
#[inline]
fn contains_byte(self, byte: u8) -> bool
where Self: ops::BitXor, Self::Output: Bytes
{
(self ^ Self::splat(byte)).contains_zero_byte()
}
}
const LO: u64 = u64::MAX / 0xFF;
const HI: u64 = LO << 7;
macro_rules! impl_bytes {
($($t:ty),+) => { $(
impl Bytes for $t {
#[inline]
fn splat(byte: u8) -> Self {
LO as Self * byte as Self
}
#[inline]
fn bytes_eq(self, other: Self) -> Self {
const H: $t = HI as $t;
const L: $t = LO as $t;
let x = self ^ other;
!(((x & !H).wrapping_add(!H) | x) >> 7) & L
}
#[inline]
fn increment(self, incr: Self) -> Self {
self + incr
}
#[inline]
fn sum(self) -> usize {
const EVERY_OTHER_LO: $t = u64::MAX as $t / 0xFFFF;
const EVERY_OTHER: $t = EVERY_OTHER_LO * 0xFF;
let pair = (self & EVERY_OTHER) + ((self >> 8) & EVERY_OTHER);
let size = mem::size_of::<$t>();
(pair.wrapping_mul(EVERY_OTHER_LO) >> ((size - 2) * 8)) as usize
}
#[inline]
fn contains_zero_byte(self) -> bool {
self.wrapping_sub(LO as Self) & !self & HI as Self != 0
}
}
)+ }
}
impl_bytes! { usize, u64, u32 }