macro_rules! branchless_min {
($x:expr, $y:expr, $u:ty, $zero:expr) => {
$y ^ (($x ^ $y) & ($zero.wrapping_sub(($x < $y) as $u)))
};
}
macro_rules! branchless_max {
($x:expr, $y:expr, $u:ty, $zero:expr) => {
$x ^ (($x ^ $y) & ($zero.wrapping_sub(($x < $y) as $u)))
};
}
#[test]
fn test_branchless_min_and_max() {
for x in core::u8::MIN..=core::u8::MAX {
for y in core::u8::MIN..=core::u8::MAX {
assert_eq!(branchless_min!(x, y, u8, 0u8), x.min(y));
assert_eq!(branchless_max!(x, y, u8, 0u8), x.max(y));
}
}
}
pub trait RandomRange<T> {
fn convert(&self, x: T) -> Option<T>;
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct DebiasedIntMulRange<T> {
base: T,
range: T,
threshold: T,
}
macro_rules! impl_DebiasedIntMulRange {
($u:ty, $zero:expr, $u_bits:expr, $big_u:ty) => {
impl DebiasedIntMulRange<$u> {
#[inline]
pub const fn new(a: $u, b: $u) -> Self {
let (low, high) = (branchless_min!(a, b, $u, $zero), branchless_max!(a, b, $u, $zero));
let base = low;
let range = high.wrapping_sub(low).wrapping_add(1);
let threshold = $zero.wrapping_sub(range) % range;
Self { base, range, threshold }
}
#[inline]
pub const fn low(&self) -> $u {
self.base
}
#[inline]
pub const fn high(&self) -> $u {
self.base.wrapping_add(self.range).wrapping_sub(1)
}
}
impl RandomRange<$u> for DebiasedIntMulRange<$u> {
#[inline]
fn convert(&self, x: $u) -> Option<$u> {
let m: $big_u = (x as $big_u).wrapping_mul(self.range as $big_u);
let l: $u = m as $u;
if l < self.threshold {
None
} else {
Some((m >> $u_bits) as $u + self.base)
}
}
}
};
}
impl_DebiasedIntMulRange! {u8, 0u8, 8, u16}
impl_DebiasedIntMulRange! {u16, 0u16, 16, u32}
impl_DebiasedIntMulRange! {u32, 0u32, 32, u64}
impl_DebiasedIntMulRange! {u64, 0u64, 64, u128}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct BitmaskRange<T> {
base: T,
range_minus_one: T,
mask: T,
}
macro_rules! impl_BitmaskRange {
($u:ty, $zero:expr, $max_val:expr) => {
impl BitmaskRange<$u> {
#[inline]
pub const fn new(a: $u, b: $u) -> Self {
let (low, high) = (branchless_min!(a, b, $u, $zero), branchless_max!(a, b, $u, $zero));
let base = low;
let range_minus_one = high.wrapping_sub(low);
let mask = $max_val >> (range_minus_one | 1).leading_zeros();
Self { base, range_minus_one, mask }
}
#[inline]
pub const fn low(&self) -> $u {
self.base
}
#[inline]
pub const fn high(&self) -> $u {
self.base.wrapping_add(self.range_minus_one)
}
}
impl RandomRange<$u> for BitmaskRange<$u> {
#[inline]
fn convert(&self, x: $u) -> Option<$u> {
let out = x & self.mask;
if out > self.range_minus_one {
None
} else {
Some(self.base + out)
}
}
}
};
}
impl_BitmaskRange! {u8, 0u8, core::u8::MAX}
impl_BitmaskRange! {u16, 0u16, core::u16::MAX}
impl_BitmaskRange! {u32, 0u32, core::u32::MAX}
impl_BitmaskRange! {u64, 0u64, core::u64::MAX}
impl_BitmaskRange! {u128, 0u128, core::u128::MAX}