use std::{
mem::size_of,
ops::{
BitAnd, BitAndAssign, BitOr, BitOrAssign, BitXor, BitXorAssign, Not, Shl, ShlAssign, Shr,
ShrAssign,
},
};
pub trait Binary:
Sized
+ Copy
+ PartialEq
+ Eq
+ BitOr<Output = Self>
+ BitAnd<Output = Self>
+ BitXor<Output = Self>
+ Not<Output = Self>
+ Shl<u32, Output = Self>
+ Shr<u32, Output = Self>
+ BitOrAssign
+ BitAndAssign
+ BitXorAssign
+ ShlAssign<u32>
+ ShrAssign<u32>
{
const MAX_BIT_IDX: u32;
const ZERO: Self;
const FULL: Self;
const ONE: Self;
const TOP: Self;
fn has_zero(self) -> bool {
self != Self::FULL
}
fn has_one(self) -> bool {
self != Self::ZERO
}
fn trailing_zeros(self) -> u32;
fn trailing_ones(self) -> u32;
fn leading_zeros(self) -> u32;
fn leading_ones(self) -> u32;
fn lowest_zero(self) -> Self;
fn lowest_one(self) -> Self;
fn highest_zero(self) -> Self;
fn highest_one(self) -> Self;
}
macro_rules! impl_binary {
($($t:ident),*) => {
$(
impl Binary for $t {
const MAX_BIT_IDX: u32 = (size_of::<Self>() as u32 * 8) - 1;
const ZERO: Self = 0 as _;
const FULL: Self = !Self::ZERO;
const ONE: Self = 1 as _;
const TOP: Self = Self::ONE << Self::MAX_BIT_IDX;
#[inline(always)]
fn trailing_zeros(self) -> u32 {
self.trailing_zeros()
}
#[inline(always)]
fn trailing_ones(self) -> u32 {
self.trailing_ones()
}
#[inline(always)]
fn leading_zeros(self) -> u32 {
self.leading_zeros()
}
#[inline(always)]
fn leading_ones(self) -> u32 {
self.leading_ones()
}
#[inline(always)]
fn lowest_zero(self) -> Self {
Self::ONE.unbounded_shl(self.trailing_ones())
}
#[inline(always)]
fn lowest_one(self) -> Self {
Self::ONE.unbounded_shl(self.trailing_zeros())
}
#[inline(always)]
fn highest_zero(self) -> Self {
Self::TOP.unbounded_shr(self.leading_ones())
}
#[inline(always)]
fn highest_one(self) -> Self {
Self::TOP.unbounded_shr(self.leading_zeros())
}
}
)*
};
}
impl_binary!(u8, u16, u32, u64, u128, i8, i16, i32, i64, i128, usize, isize);