use crate::Integer;
pub trait FastRange: Integer + Sized {
type MaskType: Integer + Copy;
fn fast_range(&self, d: Self) -> Self;
fn fast_div_mask(&self, mask: Self::MaskType) -> Self;
fn fast_mod_mask(&self, d: Self, mask: Self::MaskType) -> Self;
#[inline(always)]
fn fast_div(&self, d: Self) -> Self {
let mask = d.compute_mask_fast();
self.fast_div_mask(mask)
}
#[inline(always)]
fn fast_mod(&self, d: Self) -> Self {
let mask = d.compute_mask_fast();
self.fast_mod_mask(d, mask)
}
#[inline(always)]
fn fast_is_divisible(&self, d: Self) -> bool {
let mask = d.compute_mask_fast();
self.fast_is_divisible_mask(mask)
}
fn compute_mask_fast(&self) -> Self::MaskType;
fn fast_is_divisible_mask(&self, mask: Self::MaskType) -> bool;
}
impl FastRange for u8 {
type MaskType = u16;
#[inline(always)]
fn fast_range(&self, d: Self) -> Self {
((*self as u16 * d as u16) >> 8) as u8
}
#[inline(always)]
fn fast_div_mask(&self, mask: Self::MaskType) -> Self {
((*self as u32).wrapping_mul(mask as u32) >> 16) as u8
}
#[inline(always)]
fn fast_mod_mask(&self, d: Self, mask: Self::MaskType) -> Self {
debug_assert_eq!(mask, d.compute_mask_fast());
let low_bits = (*self as u16).wrapping_mul(mask);
((low_bits as u32).wrapping_mul(d as u32) >> 16) as u8
}
#[inline(always)]
fn compute_mask_fast(&self) -> Self::MaskType {
(u16::MAX / *self as u16).wrapping_add(1)
}
#[inline(always)]
fn fast_is_divisible_mask(&self, mask: Self::MaskType) -> bool {
(*self as u16).wrapping_mul(mask) <= mask.wrapping_sub(1)
}
}
impl FastRange for u16 {
type MaskType = u32;
#[inline(always)]
fn fast_range(&self, d: Self) -> Self {
((*self as u32 * d as u32) >> 16) as u16
}
#[inline(always)]
fn fast_div_mask(&self, mask: Self::MaskType) -> Self {
((*self as u64).wrapping_mul(mask as u64) >> 32) as u16
}
#[inline(always)]
fn fast_mod_mask(&self, d: Self, mask: Self::MaskType) -> Self {
debug_assert_eq!(mask, d.compute_mask_fast());
let low_bits = (*self as u32).wrapping_mul(mask);
((low_bits as u64).wrapping_mul(d as u64) >> 32) as u16
}
#[inline(always)]
fn compute_mask_fast(&self) -> Self::MaskType {
(u32::MAX / *self as u32).wrapping_add(1)
}
#[inline(always)]
fn fast_is_divisible_mask(&self, mask: Self::MaskType) -> bool {
(*self as u32).wrapping_mul(mask) <= mask.wrapping_sub(1)
}
}
impl FastRange for u32 {
type MaskType = u64;
#[inline(always)]
fn fast_range(&self, d: Self) -> Self {
((*self as u64).wrapping_mul(d as u64) >> 32) as u32
}
#[inline(always)]
fn fast_div_mask(&self, mask: Self::MaskType) -> Self {
((*self as u128).wrapping_mul(mask as u128) >> 64) as u32
}
#[inline(always)]
fn fast_mod_mask(&self, d: Self, mask: Self::MaskType) -> Self {
debug_assert_eq!(mask, d.compute_mask_fast());
let low_bits = (*self as u64).wrapping_mul(mask);
((low_bits as u128).wrapping_mul(d as u128) >> 64) as u32
}
#[inline(always)]
fn compute_mask_fast(&self) -> Self::MaskType {
(u64::MAX / *self as u64).wrapping_add(1)
}
#[inline(always)]
fn fast_is_divisible_mask(&self, mask: Self::MaskType) -> bool {
(*self as u64).wrapping_mul(mask) <= mask.wrapping_sub(1)
}
}
#[inline(always)]
fn mul128_u64(low_bits: u128, d: u64) -> u64 {
let mut bottom_half = (low_bits & (u64::MAX as u128)).wrapping_mul(d as u128); bottom_half >>= 64; let top_half = (low_bits >> 64).wrapping_mul(d as u128);
let mut both_halves = bottom_half + top_half; both_halves >>= 64; both_halves as u64
}
impl FastRange for u64 {
type MaskType = u128;
#[inline(always)]
fn fast_range(&self, d: Self) -> Self {
((*self as u128).wrapping_mul(d as u128) >> 64) as u64
}
#[inline(always)]
fn fast_div_mask(&self, mask: Self::MaskType) -> Self {
mul128_u64(mask, *self)
}
#[inline(always)]
fn fast_mod_mask(&self, d: Self, mask: Self::MaskType) -> Self {
debug_assert_eq!(mask, d.compute_mask_fast());
let low_bits = (*self as u128).wrapping_mul(mask);
mul128_u64(low_bits, d)
}
#[inline(always)]
fn compute_mask_fast(&self) -> Self::MaskType {
let mut mask: u128 = u64::MAX as u128;
mask <<= 64;
mask |= u64::MAX as u128;
mask /= *self as u128;
mask = mask.wrapping_add(1);
mask
}
#[inline(always)]
fn fast_is_divisible_mask(&self, mask: Self::MaskType) -> bool {
(*self as u128).wrapping_mul(mask) <= mask.wrapping_sub(1)
}
}
macro_rules! impl_usize {
($ty:ty, $pw:literal, $mask:ty) => {
#[cfg(target_pointer_width = $pw)]
impl FastRange for usize {
type MaskType = $mask;
#[inline(always)]
fn fast_range(&self, d: Self) -> Self {
(*self as $ty).fast_range(d as $ty) as usize
}
#[inline(always)]
fn fast_div_mask(&self, mask: Self::MaskType) -> Self {
(*self as $ty).fast_div_mask(mask) as usize
}
#[inline(always)]
fn fast_mod_mask(&self, d: Self, mask: Self::MaskType) -> Self {
(*self as $ty).fast_mod_mask(d as $ty, mask) as usize
}
#[inline(always)]
fn compute_mask_fast(&self) -> Self::MaskType {
(*self as $ty).compute_mask_fast() as Self::MaskType
}
#[inline(always)]
fn fast_is_divisible_mask(&self, mask: Self::MaskType) -> bool {
(*self as $ty).fast_is_divisible_mask(mask)
}
}
};
}
impl_usize!(u64, "64", u128);
impl_usize!(u32, "32", u64);
impl_usize!(u16, "16", u32);