use crate::set::{Positions, Subsets};
use crate::word::Word;
pub trait Bits: Word {
#[must_use]
#[inline]
fn run_starts(self, k: u32) -> Self {
if k == 0 {
return Self::ONES;
}
if k > Self::BITS {
return Self::ZERO;
}
let mut x = self;
let mut n = k;
while n > 1 {
let s = n >> 1;
x = x.and(x.shr(s));
n -= s;
}
x
}
#[inline]
#[must_use]
fn has_run(self, k: u32) -> bool {
!self.run_starts(k).is_zero()
}
#[must_use]
#[inline]
fn longest_run(self) -> u32 {
let (mut lo, mut hi) = (0, Self::BITS);
while lo < hi {
let mid = lo + (hi - lo).div_ceil(2);
if self.has_run(mid) {
lo = mid;
} else {
hi = mid - 1;
}
}
lo
}
#[inline]
#[must_use]
#[doc(alias("rank1"))]
fn rank(self, i: u32) -> u32 {
self.and(Self::low_ones(i)).count_ones()
}
#[inline]
#[must_use]
#[doc(alias("select1"))]
fn select(self, k: u32) -> Option<u32> {
if k >= self.count_ones() {
None
} else {
Some(self.select_lowest(k))
}
}
#[inline]
#[must_use]
fn first_set(self) -> Option<u32> {
if self.is_zero() {
None
} else {
Some(self.trailing_zeros())
}
}
#[inline]
#[must_use]
fn last_set(self) -> Option<u32> {
if self.is_zero() {
None
} else {
Some(Self::BITS - 1 - self.leading_zeros())
}
}
#[inline]
fn positions(self) -> Positions<Self> {
Positions(self)
}
#[inline]
fn subsets(self) -> Subsets<Self> {
Subsets::new(self)
}
#[inline]
#[must_use]
fn prefix_or(self) -> Self {
self.or(Self::ZERO.wrapping_sub(self))
}
#[inline]
#[must_use]
#[doc(alias("clmul", "prefix parity"))]
fn prefix_xor(self) -> Self {
self.xor_scan()
}
#[inline]
#[must_use]
fn prefix_xor_carry(self, carry: bool) -> (Self, bool) {
let x = self
.prefix_xor()
.xor(if carry { Self::ONES } else { Self::ZERO });
(x, x.bit(Self::BITS - 1))
}
#[inline]
#[must_use]
fn delta_xor(self) -> Self {
self.xor(self.shl(1))
}
#[inline]
#[must_use]
#[doc(alias("gray code"))]
fn gray_encode(self) -> Self {
self.xor(self.shr(1))
}
#[inline]
#[must_use]
fn suffix_xor(self) -> Self {
self.xor_scan_down()
}
#[inline]
#[must_use]
fn gray_decode(self) -> Self {
self.suffix_xor()
}
#[must_use]
#[inline]
fn find_escaped(self, prev_ends_odd: bool) -> (Self, bool) {
let even = Self::splat_byte(0x55);
let odd = even.not();
let flip = if prev_ends_odd { Self::ONE } else { Self::ZERO };
let start_edges = self.and(self.shl(1).not());
let even_start_mask = even.xor(flip);
let even_starts = start_edges.and(even_start_mask);
let odd_starts = start_edges.and(even_start_mask.not());
let even_carries = self.wrapping_add(even_starts);
let odd_carries = self.wrapping_add(odd_starts).or(flip);
let overflow = self
.and(odd_starts)
.or(self.or(odd_starts).and(odd_carries.not()));
let carry = overflow.bit(Self::BITS - 1);
let even_carry_ends = even_carries.and(self.not());
let odd_carry_ends = odd_carries.and(self.not());
let even_start_odd_end = even_carry_ends.and(odd);
let odd_start_even_end = odd_carry_ends.and(even);
(even_start_odd_end.or(odd_start_even_end), carry)
}
#[inline]
#[must_use]
fn fill_up(self, propagate: Self, stride: u32) -> Self {
if stride == 0 || stride >= Self::BITS {
return self;
}
let mut reach = self;
let mut prop = propagate;
let mut s = stride;
while s < Self::BITS {
reach = reach.or(prop.and(reach.shl(s)));
prop = prop.and(prop.shl(s));
s <<= 1;
}
reach
}
#[inline]
#[must_use]
fn fill_down(self, propagate: Self, stride: u32) -> Self {
if stride == 0 || stride >= Self::BITS {
return self;
}
let mut reach = self;
let mut prop = propagate;
let mut s = stride;
while s < Self::BITS {
reach = reach.or(prop.and(reach.shr(s)));
prop = prop.and(prop.shr(s));
s <<= 1;
}
reach
}
#[inline]
#[must_use]
#[doc(alias("pext", "compress"))]
fn compact(self, mask: Self) -> Self {
self.pext(mask)
}
#[inline]
#[must_use]
#[doc(alias("pdep", "deposit"))]
fn expand(self, mask: Self) -> Self {
self.pdep(mask)
}
#[inline]
#[must_use]
fn gather(self, mask: Self, factor: Self, target: u32) -> Self {
if target >= Self::BITS {
return Self::ZERO;
}
self.and(mask)
.wrapping_mul(factor)
.shr(target)
.and(Self::low_ones(mask.count_ones()))
}
#[must_use]
#[inline]
fn gather_factor_by(mask: Self, place: impl Fn(u32) -> u32) -> Option<Self> {
let mut factor = Self::ZERO;
for (i, q) in (0..).zip(mask.positions()) {
let t = place(i);
if t < q || t >= Self::BITS {
return None;
}
factor = factor.or(Self::ONE.shl(t - q));
}
Some(factor)
}
#[inline]
#[must_use]
fn gather_factor(mask: Self, target: u32) -> Option<Self> {
Self::gather_factor_by(mask, |i| target + i)
}
#[inline]
#[must_use]
#[doc(alias("blsi"))]
fn lowest_set_mask(self) -> Self {
self.and(Self::ZERO.wrapping_sub(self))
}
#[inline]
#[must_use]
fn below_lowest_set(self) -> Self {
self.not().and(self.wrapping_sub(Self::ONE))
}
#[inline]
#[must_use]
#[doc(alias("blsmsk"))]
fn up_to_lowest_set(self) -> Self {
self.xor(self.wrapping_sub(Self::ONE))
}
#[inline]
#[must_use]
fn set_lowest_zero(self) -> Self {
self.or(self.wrapping_add(Self::ONE))
}
#[inline]
#[must_use]
fn clear_lowest_run(self) -> Self {
self.or(self.wrapping_sub(Self::ONE))
.wrapping_add(Self::ONE)
.and(self)
}
#[inline]
#[must_use]
fn blend(self, other: Self, mask: Self) -> Self {
self.xor(self.xor(other).and(mask))
}
#[inline]
#[must_use]
#[doc(alias("vpternlog", "ternlog"))]
fn ternary(self, b: Self, c: Self, table: u8) -> Self {
let leaf = |t: u8| match t & 3 {
0 => Self::ZERO,
1 => c.not(),
2 => c,
_ => Self::ONES,
};
let on_b = |t: u8| b.and(leaf(t >> 2)).or(b.not().and(leaf(t)));
self.and(on_b(table >> 4)).or(self.not().and(on_b(table)))
}
#[inline]
#[must_use]
fn signed_add_overflows(self, other: Self) -> bool {
self.xor(other)
.not()
.and(self.xor(self.wrapping_add(other)))
.bit(Self::BITS - 1)
}
#[inline]
#[must_use]
fn signed_sub_overflows(self, other: Self) -> bool {
self.xor(other)
.and(self.xor(self.wrapping_sub(other)))
.bit(Self::BITS - 1)
}
#[inline]
#[must_use]
fn next_same_popcount(self) -> Option<Self> {
let s = self.lowest_set_mask();
let r = self.wrapping_add(s);
if r.is_zero() {
return None;
}
let ones = self.xor(r).shr(self.trailing_zeros()).shr(2);
Some(r.or(ones))
}
#[inline]
#[must_use]
fn next_subset(self, mask: Self) -> Option<Self> {
let s = self.and(mask);
if s == mask {
None
} else {
Some(s.wrapping_sub(mask).and(mask))
}
}
#[inline]
#[must_use]
fn is_pow2(self) -> bool {
!self.is_zero() && self.clear_lowest_set().is_zero()
}
#[inline]
#[must_use]
fn round_down_pow2(self) -> Option<Self> {
self.last_set().map(|p| Self::ONE.shl(p))
}
#[inline]
#[must_use]
#[doc(alias("next_power_of_two"))]
fn round_up_pow2(self) -> Option<Self> {
if self.shr(1).is_zero() {
return Some(Self::ONE);
}
let lz = self.wrapping_sub(Self::ONE).leading_zeros();
if lz == 0 {
None
} else {
Some(Self::ONE.shl(Self::BITS - lz))
}
}
#[inline]
#[must_use]
#[doc(alias("ilog2"))]
fn log2_floor(self) -> Option<u32> {
self.last_set()
}
#[inline]
#[must_use]
fn log2_ceil(self) -> Option<u32> {
if self.is_zero() {
None
} else {
Some(Self::BITS - self.wrapping_sub(Self::ONE).leading_zeros())
}
}
#[inline]
#[must_use]
fn lanes_lo() -> Self {
Self::splat_byte(0x01)
}
#[inline]
#[must_use]
fn lanes_hi() -> Self {
Self::splat_byte(0x80)
}
#[inline]
#[must_use]
fn zero_bytes(self) -> Self {
let low7 = Self::splat_byte(0x7F);
let y = self.and(low7).wrapping_add(low7).or(self).or(low7);
y.not()
}
#[inline]
#[must_use]
fn has_zero_byte(self) -> bool {
!self.zero_bytes().is_zero()
}
#[inline]
#[must_use]
fn first_zero_byte(self) -> Option<u32> {
let z = self.zero_bytes();
if z.is_zero() {
None
} else {
Some(z.trailing_zeros() / 8)
}
}
#[inline]
#[must_use]
fn bytes_eq(self, b: u8) -> Self {
self.xor(Self::splat_byte(b)).zero_bytes()
}
#[inline]
#[must_use]
fn bytes_ge(self, n: u8) -> Self {
debug_assert!((1..=128).contains(&n), "bytes_ge: n={n} outside 1..=128");
let low7 = Self::splat_byte(0x7F);
self.and(low7)
.wrapping_add(Self::splat_byte(0x80 - n))
.or(self)
.and(Self::lanes_hi())
}
#[inline]
#[must_use]
fn bytes_lt(self, n: u8) -> Self {
self.bytes_ge(n).xor(Self::lanes_hi())
}
#[inline]
#[must_use]
fn count_bytes_eq(self, b: u8) -> u32 {
self.bytes_eq(b).count_ones()
}
#[inline]
#[must_use]
fn sum_bytes(self) -> u32 {
u32::from(
self.wrapping_mul(Self::lanes_lo())
.shr(Self::BITS - 8)
.low_byte(),
)
}
#[inline]
#[must_use]
fn delta_swap(self, mask: Self, shift: u32) -> Self {
debug_assert!(
mask.and(mask.shl(shift)).is_zero() && mask.shl(shift).shr(shift) == mask,
"delta_swap: mask and mask << shift must be disjoint and in range"
);
let t = self.xor(self.shr(shift)).and(mask);
self.xor(t).xor(t.shl(shift))
}
}
impl<W: Word> Bits for W {}
#[inline]
#[must_use]
pub fn truth_table(f: impl Fn(u8, u8, u8) -> u8) -> u8 {
f(0xF0, 0xCC, 0xAA)
}