#[cfg(feature = "_docs_examples")]
define_divisor! {
#[doc = crate::_tags!(example num)]
#[doc = crate::_doc_location!("num/dom/int")]
pub struct DivisorExample:<> impl (i32, u32)
}
#[doc(hidden)]
#[derive(Clone, Copy)]
pub enum DivisorInner<T> {
Shift(T, u8),
MultiplyShift(T, T, u8),
MultiplyAddShift(T, T, u8),
#[allow(dead_code, reason = "only used for signed integers")]
ShiftAndNegate(T, u8),
#[allow(dead_code, reason = "only used for signed integers")]
MultiplyAddShiftNegate(T, T, u8),
}
#[doc = crate::_tags!(construction code num)]
#[doc = crate::_doc_location!("num/dom/int")]
#[doc = crate::_doc!(vendor: "quickdiv")]
#[macro_export]
#[cfg_attr(cargo_primary_package, doc(hidden))]
macro_rules! define_divisor {
(
/* public macro arms */
// new individual definition + impl
$(#[$attr:meta])* $vis:vis struct $Name:ident : ($T:ident) impl) => {
$(#[$attr])* #[must_use] #[derive(Clone, Copy)]
$vis struct $Name { inner: $crate::DivisorInner<$T> }
$crate::define_divisor!(impl $Name : ($T));
};
(
$(#[$attr:meta])* $vis:vis struct $Name:ident : <> impl ($($T:ident),+)) => {
$(#[$attr])* #[must_use] #[derive(Clone, Copy)]
$vis struct $Name<T> { inner: $crate::DivisorInner<T> }
$( $crate::define_divisor!(%impl $Name<$T>, $Name; $T); )+
};
(
$(#[$attr:meta])* $vis:vis struct $Name:ident : ($T:ident)) => {
$(#[$attr])* #[must_use] #[derive(Clone, Copy)]
$vis struct $Name { inner: $crate::DivisorInner<$T> }
};
(
$(#[$attr:meta])* $vis:vis struct $Name:ident : <>) => {
$(#[$attr])* #[must_use] #[derive(Clone, Copy)]
$vis struct $Name<T> { inner: $crate::DivisorInner<T> }
};
(
impl $Name:ident : ($T:ident)) => {
$crate::define_divisor!(%impl $Name, $Name; $T);
};
(
impl $Name:ident : <> ($($T:ident),+)) => {
$( $crate::define_divisor!(%impl $Name<$T>, $Name; $T); )+
};
(
%impl $Type:ty, $Name:ident; u8) => {
$crate::define_divisor!(%impl_u $Type,$Name; u8|u16:Y); };
(%impl $Type:ty,$Name:ident; u16) => {
$crate::define_divisor!(%impl_u $Type,$Name; u16|u32:Y); };
(%impl $Type:ty,$Name:ident; u32) => {
$crate::define_divisor!(%impl_u $Type,$Name; u32|u64:Y); };
(%impl $Type:ty,$Name:ident; u64) => {
$crate::define_divisor!(%impl_u $Type,$Name; u64|u128:PW); };
(%impl $Type:ty,$Name:ident; u128) => {
$crate::define_divisor!(%impl_u $Type,$Name; u128|u128:N); };
(%impl $Type:ty,$Name:ident; usize) => {
$crate::define_divisor!(%impl_u $Type,$Name; usize|$crate::usize_up:Y); };
(%impl $Type:ty,$Name:ident; i8) => {
$crate::define_divisor!(%impl_i $Type,$Name; i8|u8|i16|u16:Y); };
(%impl $Type:ty,$Name:ident; i16) => {
$crate::define_divisor!(%impl_i $Type,$Name; i16|u16|i32|u32:Y); };
(%impl $Type:ty,$Name:ident; i32) => {
$crate::define_divisor!(%impl_i $Type,$Name; i32|u32|i64|u64:Y); };
(%impl $Type:ty,$Name:ident; i64) => {
$crate::define_divisor!(%impl_i $Type,$Name; i64|u64|i128|u128:PW); };
(%impl $Type:ty,$Name:ident; i128) => {
$crate::define_divisor!(%impl_i $Type,$Name; i128|u128|i128|u128:N); };
(%impl $Type:ty,$Name:ident; isize) => {
$crate::define_divisor!(%impl_i $Type,$Name;
isize|usize|$crate::isize_up|$crate::usize_up:Y); };
( %impl_i $Type:ty, $Name:ident; $t:ty | $un:ty | $up:ty | $unup:ty : $is_up:ident) => {
define_divisor![%traits $Type, $Name; $t];
impl $Type {
define_divisor![%shared $Type,$Name; $t|$un|$up|$unup:$is_up];
#[must_use]
const fn abs(n: $t) -> $un {
$crate::is![n < 0, ((-1i8) as $un).wrapping_mul(n as $un), n as $un]
}
#[doc = concat!["let d = DivisorExample::<", stringify![$t], ">::new(-21).unwrap();"]]
#[must_use]
pub const fn new(d: $t) -> Option<$Type> {
if d == 0 {
Self::cold_0_divisor()
} else {
let ud = Self::abs(d);
let shift = ud.ilog2() as u8;
let inner = if ud.is_power_of_two() {
if d > 0 { $crate::DivisorInner::Shift(d, shift) }
else { $crate::DivisorInner::ShiftAndNegate(d, shift) }
} else {
let (mut magic, rem) = Self::div_rem_wide_by_base(1 << (shift - 1), ud);
let e = ud - rem;
if e < 1 << shift {
$crate::DivisorInner::MultiplyShift(d, d.signum()
* (magic as $t + 1), shift - 1)
} else {
magic *= 2;
let (doubled_rem, overflowed) = rem.overflowing_mul(2);
$crate::is![doubled_rem >= ud || overflowed, magic += 1];
magic += 1;
if d > 0 {
$crate::DivisorInner::MultiplyAddShift(d, magic as $t, shift)
} else {
$crate::DivisorInner::MultiplyAddShiftNegate(d, -(magic as $t), shift)
}
}
};
Some(Self { inner })
}
}
#[doc = concat!["let d = DivisorExample::<", stringify![$t], ">::new(-15).unwrap();"]]
#[must_use]
pub const fn get(&self) -> $t {
match self.inner {
$crate::DivisorInner::Shift(d, _) => d,
$crate::DivisorInner::ShiftAndNegate(d, _) => d,
$crate::DivisorInner::MultiplyShift(d, _, _) => d,
$crate::DivisorInner::MultiplyAddShift(d, _, _) => d,
$crate::DivisorInner::MultiplyAddShiftNegate(d, _, _) => d,
}
}
#[doc = concat!["let d = DivisorExample::<", stringify![$t], ">::new(-9).unwrap();"]]
#[must_use]
pub const fn divides(&self, n: $t) -> bool {
self.rem_of(n) == 0
}
#[doc = concat!["let d = DivisorExample::<", stringify![$t], ">::new(21).unwrap();"]]
#[must_use]
pub const fn rem_of(&self, n: $t) -> $t {
n.wrapping_add((self.get().wrapping_mul(self.div_of(n))).wrapping_mul(-1))
}
#[doc = concat!("`DivisorExample::<", stringify!($t), ">::new(-1).unwrap().div_of(",
stringify!($t) ,"::MIN)`")]
#[doc = concat!("`", stringify!($t) ,"::MIN`")]
#[doc = concat!["let d = DivisorExample::<", stringify![$t], ">::new(13).unwrap();"]]
#[must_use]
pub const fn div_of(&self, n: $t) -> $t {
match self.inner {
$crate::DivisorInner::Shift(_, shift) => {
let mask = (1 as $t << shift).wrapping_sub(1);
let b = (n >> (<$t>::BITS - 1)) & mask;
n.wrapping_add(b) >> shift
},
$crate::DivisorInner::ShiftAndNegate(_, shift) => {
let mask = (1 as $t << shift).wrapping_sub(1);
let b = (n >> (<$t>::BITS - 1)) & mask;
let t = n.wrapping_add(b) >> shift;
t.wrapping_mul(-1)
},
$crate::DivisorInner::MultiplyShift(_, magic, shift) => {
let q = Self::mulh(magic, n) >> shift;
$crate::is![q < 0, q + 1, q]
},
$crate::DivisorInner::MultiplyAddShift(_, magic, shift) => {
let q = Self::mulh(magic, n);
let t = q.wrapping_add(n) >> shift;
$crate::is![t < 0, t + 1, t]
},
$crate::DivisorInner::MultiplyAddShiftNegate(_, magic, shift) => {
let q = Self::mulh(magic, n);
let t = q.wrapping_add(n.wrapping_mul(-1)) >> shift;
$crate::is![t < 0, t + 1, t]
}
}
}
}
};
(%impl_u $Type:ty, $Name:ident; $t:ty | $up:ty : $is_up:ident) => {
define_divisor![%traits $Type, $Name; $t];
impl $Type {
define_divisor![%shared $Type, $Name; $t|$t|$up|$up:$is_up];
#[doc = concat!["let _d = DivisorExample::<", stringify![$t], ">::new(5);"]]
#[must_use]
pub const fn new(d: $t) -> Option<$Type> {
if d == 0 {
Self::cold_0_divisor()
} else {
let shift = d.ilog2() as u8;
let inner = if d.is_power_of_two() {
$crate::DivisorInner::Shift(d, shift)
} else {
let (mut magic, rem) = Self::div_rem_wide_by_base(1 << shift, d);
let e = d - rem;
if e < 1 << shift {
$crate::DivisorInner::MultiplyShift(d, magic + 1, shift)
} else {
magic = magic.wrapping_mul(2);
let (doubled_rem, overflowed) = rem.overflowing_mul(2);
if doubled_rem >= d || overflowed { magic += 1; }
$crate::DivisorInner::MultiplyAddShift(d, magic + 1, shift)
}
};
Some(Self { inner })
}
}
#[doc = concat!["let d = DivisorExample::<", stringify![$t], ">::new(7).unwrap();"]]
#[must_use]
pub const fn get(&self) -> $t {
match self.inner {
$crate::DivisorInner::Shift(d, _) => d,
$crate::DivisorInner::MultiplyShift(d, _, _) => d,
$crate::DivisorInner::MultiplyAddShift(d, _, _) => d,
_ => unreachable![],
}
}
#[doc = concat!["let d = DivisorExample::<", stringify![$t], ">::new(17).unwrap();"]]
#[must_use]
pub const fn divides(&self, n: $t) -> bool {
self.rem_of(n) == 0
}
#[doc = concat!["let d = DivisorExample::<", stringify![$t], ">::new(11).unwrap();"]]
#[must_use]
pub const fn rem_of(&self, n: $t) -> $t {
n - self.get() * self.div_of(n)
}
#[doc = concat!["let d = DivisorExample::<", stringify![$t], ">::new(17).unwrap();"]]
#[must_use]
pub const fn div_of(&self, n: $t) -> $t {
match self.inner {
$crate::DivisorInner::Shift(_, shift) => n >> shift,
$crate::DivisorInner::MultiplyShift(_, magic, shift)
=> Self::mulh(magic, n) >> shift,
$crate::DivisorInner::MultiplyAddShift(_, magic, shift) => {
let q = Self::mulh(magic, n);
let t = ((n - q) >> 1) + q;
t >> shift
},
_ => unreachable![], }
}
}
};
(%shared $Type:ty, $Name:ident; $t:ty | $un:ty | $up:ty | $unup:ty : $is_up:ident) => {
$crate::paste!{
pub const fn [<new_ $t>](d: $t) -> Option<$Type> { Self::new(d) }
}
#[cold] #[inline(never)]
const fn cold_0_divisor() -> Option<Self> { None }
#[$crate::compile(any(same($is_up, Y), all(same($is_up, PW), pointer_width_eq(64))))]
const fn mulh(x: $t, y: $t) -> $t {
(((x as $up) * (y as $up)) >> <$t>::BITS) as $t
}
#[$crate::compile(any(same($is_up, N), all(same($is_up, PW), not(pointer_width_eq(64)))))]
const fn mulh(x: $t, y: $t) -> $t {
const HALF_WIDTH_BITS: u32 = <$t>::BITS / 2;
const LOWER_HALF_MASK: $t = (1 << HALF_WIDTH_BITS) - 1;
let x_low = x & LOWER_HALF_MASK;
let y_low = y & LOWER_HALF_MASK;
let t = x_low.wrapping_mul(y_low);
let k = t >> HALF_WIDTH_BITS;
let x_high = x >> HALF_WIDTH_BITS;
let t = x_high.wrapping_mul(y_low) + k;
let k = t & LOWER_HALF_MASK;
let w1 = t >> HALF_WIDTH_BITS;
let y_high = y >> HALF_WIDTH_BITS;
let t = x_low.wrapping_mul(y_high) + k;
let k = t >> HALF_WIDTH_BITS;
x_high.wrapping_mul(y_high) + w1 + k
}
#[$crate::compile(any(same($is_up, Y), all(same($is_up, PW), pointer_width_eq(64))))]
const fn div_rem_wide_by_base(top_half: $un, d: $un) -> ($un, $un) {
let n = (top_half as $unup) << <$un>::BITS;
let quot = (n / (d as $unup)) as $un;
let rem = (n % (d as $unup)) as $un;
(quot, rem)
}
#[$crate::compile(any(same($is_up, N), all(same($is_up, PW), not(pointer_width_eq(64)))))]
const fn div_rem_wide_by_base(top_half: $un, d: $un) -> ($un, $un) {
const HALF_WORD_BITS: u32 = <$un>::BITS / 2;
const BASE: $un = 1 << HALF_WORD_BITS;
let s = d.leading_zeros();
let v = d << s;
let vn1 = v >> HALF_WORD_BITS;
let vn0 = v & (BASE - 1);
let un32 = top_half << s;
let mut q1 = un32 / vn1;
let mut rhat = un32 - q1 * vn1;
loop {
if q1 >= BASE || q1 * vn0 > (rhat << HALF_WORD_BITS) {
q1 -= 1;
rhat += vn1;
if rhat < BASE { continue }
}
break;
}
let un21 = (un32 << HALF_WORD_BITS).wrapping_sub(q1.wrapping_mul(v));
let mut q0 = un21 / vn1;
rhat = un21 - q0 * vn1;
loop {
if q0 >= BASE || q0 * vn0 > (rhat << HALF_WORD_BITS) {
q0 -= 1;
rhat += vn1;
if rhat < BASE { continue }
}
break;
}
let r = ((un21 << HALF_WORD_BITS).wrapping_sub(q0.wrapping_mul(v))) >> s;
((q1 << HALF_WORD_BITS) + q0, r)
}
};
(%traits $Type:ty, $Name:ident; $t:ty) => {
impl PartialEq for $Type {
fn eq(&self, other: &Self) -> bool { self.get() == other.get() }
}
impl Eq for $Type {}
impl $crate::Debug for $Type {
fn fmt(&self, f: &mut $crate::Formatter<'_>) -> $crate::FmtResult<()> { write!(f, "{}", self.get()) }
}
impl $crate::Display for $Type {
fn fmt(&self, f: &mut $crate::Formatter<'_>) -> $crate::FmtResult<()> { write!(f, "{}", self.get()) }
}
impl $crate::Hash for $Type {
fn hash<H: $crate::Hasher>(&self, state: &mut H) { self.get().hash(state); }
}
impl $crate::Div<$Type> for $t {
type Output = $t;
fn div(self, rhs: $Type) -> Self::Output { rhs.div_of(self) }
}
impl $crate::DivAssign<$Type> for $t {
fn div_assign(&mut self, rhs: $Type) { *self = rhs.div_of(*self) }
}
impl $crate::Rem<$Type> for $t {
type Output = $t;
fn rem(self, rhs: $Type) -> Self::Output { rhs.rem_of(self) }
}
impl $crate::RemAssign<$Type> for $t {
fn rem_assign(&mut self, rhs: $Type) { *self = rhs.rem_of(*self) }
}
};
}
#[doc(inline)]
pub use define_divisor;
#[cfg(test)]
mod tests {
#![allow(unused)]
#[test]
fn define_divisor() {
define_divisor![pub struct DivI8: (i8)];
define_divisor![impl DivI8: (i8)];
define_divisor![pub struct DivU8: (u8) impl];
define_divisor![pub struct DivA:<>];
define_divisor![impl DivA:<> (i8, u32, u128, usize, isize)];
define_divisor![pub struct DivB:<> impl (i8, u32, u128, usize, isize)];
}
}