#![allow(dead_code)]
#![allow(non_camel_case_types)]
use crate::*;
use crate::stdlib::fmt;
use num_traits::{WrappingAdd, WrappingSub, AsPrimitive};
pub trait RadixType: Copy + Clone + Default + fmt::Debug {
type Base
: 'static
+ Copy
+ fmt::Debug
+ num_integer::Integer
+ num_traits::PrimInt
+ num_traits::FromPrimitive
+ num_traits::AsPrimitive<Self::BaseDouble>
+ num_traits::Zero
+ num_traits::One
+ num_traits::WrappingSub
+ num_traits::Pow<u8, Output = Self::Base>
+ AddAssign
+ From<bool>
+ From<u8>;
type BaseDouble
: 'static
+ Copy
+ num_integer::Integer
+ num_traits::PrimInt
+ num_traits::FromPrimitive
+ num_traits::AsPrimitive<Self::Base>
+ num_traits::Zero
+ num_traits::One
+ num_traits::WrappingAdd
+ num_traits::WrappingSub
+ AddAssign
+ From<u8>
+ From<Self::Base>;
type SignedBase
: 'static
+ Copy
+ num_integer::Integer
+ num_traits::PrimInt
+ num_traits::FromPrimitive
+ num_traits::Zero
+ num_traits::One
+ num_traits::Signed;
const RADIX: Self::BaseDouble;
fn validate_digits<'a, I: IntoIterator<Item = &'a Self::Base>>(i: I) -> bool {
i.into_iter().map(|&d| d.into()).all(|d| Self::BaseDouble::zero() <= d && d < Self::RADIX)
}
fn max() -> Self::Base {
(Self::RADIX - One::one()).as_()
}
fn is_max(n: Self::Base) -> bool {
n == Self::max()
}
fn split_single(n: Self::Base) -> (Self::Base, Self::Base) {
let (hi, lo) = num_integer::div_rem(n.as_(), Self::RADIX);
return (hi.as_(), lo.as_());
}
fn split_doublewide(n: Self::BaseDouble) -> (Self::BaseDouble, Self::Base) {
let (hi, lo) = num_integer::div_rem(n, Self::RADIX);
return (hi, lo.as_());
}
fn split_wide_digit(n: Self::BaseDouble) -> (Self::Base, Self::Base) {
let (hi, lo) = num_integer::div_rem(n, Self::RADIX);
debug_assert!(hi < Self::RADIX);
return (hi.as_(), lo.as_());
}
fn add_carry(n: Self::Base, carry: &mut Self::Base) -> Self::Base {
let (hi, lo) = Self::expanding_add(n, *carry);
*carry = hi;
lo
}
fn addassign_carry(n: &mut Self::Base, carry: &mut Self::Base) {
let (hi, lo) = Self::expanding_add(*n, *carry);
*carry = hi;
*n = lo;
}
fn addassign_with_carry(n: &mut Self::Base, a: Self::Base, carry: &mut Self::Base) {
let sum = n.as_() + a.as_() + carry.as_();
let (hi, lo) = Self::split_wide_digit(sum);
*carry = hi;
*n = lo;
}
fn add_expand_doublewide(a: Self::Base, b: Self::BaseDouble) -> (Self::Base, Self::Base) {
let a: Self::BaseDouble = a.into();
Self::split_wide_digit(a + b)
}
fn expanding_add(a: Self::Base, b: Self::Base) -> (Self::Base, Self::Base) {
let a: Self::BaseDouble = a.into();
let b: Self::BaseDouble = b.into();
Self::split_wide_digit(a + b)
}
fn expanding_mul(a: Self::Base, b: Self::Base) -> (Self::Base, Self::Base) {
let a: Self::BaseDouble = a.into();
let b: Self::BaseDouble = b.into();
Self::split_wide_digit(a * b)
}
fn fused_mul_add(a: Self::Base, b: Self::Base, c: Self::Base) -> (Self::Base, Self::Base) {
let a: Self::BaseDouble = a.into();
let b: Self::BaseDouble = b.into();
let c: Self::BaseDouble = c.into();
Self::split_wide_digit(a * b + c)
}
fn carrying_mul_add(
a: Self::Base,
b: Self::Base,
c: Self::Base,
d: Self::Base,
) -> (Self::Base, Self::Base) {
let a: Self::BaseDouble = a.into();
let b: Self::BaseDouble = b.into();
let c: Self::BaseDouble = c.into();
let d: Self::BaseDouble = d.into();
Self::split_wide_digit(a * b + c + d)
}
fn carrying_mul_add_inplace(
a: Self::Base,
b: Self::Base,
c: &mut Self::Base,
carry: &mut Self::Base,
) {
let a: Self::BaseDouble = a.into();
let b: Self::BaseDouble = b.into();
let (hi, lo) = Self::split_wide_digit(a * b + (*c).into() + (*carry).into());
*c = lo;
*carry = hi;
}
fn add_carry_into_slice(dest: &mut [Self::Base], c: &mut Self::Base) {
Self::add_carry_into(dest.iter_mut(), c)
}
fn add_carry_into<'a, I: Iterator<Item=&'a mut Self::Base>>(dest: I, c: &mut Self::Base) {
for d in dest {
if c.is_zero() {
return;
}
let (overflow, sum) = Self::expanding_add(*c, *d);
*d = sum;
*c = overflow;
}
}
fn mulassign_add_carry(
a: &mut Self::Base,
b: Self::Base,
carry: &mut Self::Base,
) {
let (hi, lo) = Self::expanding_mul(*a, b);
*a = Self::add_carry(lo, carry);
*carry += hi;
}
fn sub_with_carry_borrow(
lhs: Self::Base,
rhs: Self::Base,
carry: &mut Self::Base,
borrow: &mut Self::Base,
) -> Self::Base {
let mut result = Self::BaseDouble::from(lhs);
result = result
.wrapping_sub(&Self::BaseDouble::from(rhs))
.wrapping_add(&(*carry).as_())
.wrapping_sub(&(*borrow).as_());
*borrow = Self::Base::from(result >= (Self::RADIX << 1));
result = result.wrapping_add(&(borrow.as_() * Self::RADIX));
debug_assert!(result < (Self::RADIX << 1));
*carry = Self::Base::from(result >= Self::RADIX);
result = result - carry.as_() * Self::RADIX;
return result.as_();
}
}
#[derive(Copy, Clone, Debug, Default)]
pub struct RADIX_10_u8;
#[derive(Copy, Clone, Debug, Default)]
pub struct RADIX_10p4_i16;
#[derive(Copy, Clone, Debug, Default)]
pub struct RADIX_10p9_u32;
#[derive(Copy, Clone, Debug, Default)]
pub struct RADIX_10p19_u64;
#[derive(Copy, Clone, Debug, Default)]
pub struct RADIX_u32;
#[derive(Copy, Clone, Debug, Default)]
pub struct RADIX_u64;
pub(crate) trait RadixPowerOfTen: RadixType {
const DIGITS: usize;
fn divceil_digit_count(digit_count: usize) -> usize {
use num_integer::Integer;
Integer::div_ceil(&digit_count, &Self::DIGITS)
}
fn divmod_digit_count(digit_count: usize) -> (usize, usize) {
use num_integer::Integer;
Integer::div_rem(&digit_count, &Self::DIGITS)
}
}
impl RadixPowerOfTen for RADIX_10p19_u64 {
const DIGITS: usize = 19;
}
impl RadixPowerOfTen for RADIX_10p9_u32 {
const DIGITS: usize = 9;
}
impl RadixPowerOfTen for RADIX_10_u8 {
const DIGITS: usize = 1;
}
impl RadixPowerOfTen for RADIX_10p4_i16 {
const DIGITS: usize = 4;
}
impl RADIX_10p19_u64 {
pub(crate) fn rotating_div_u64_radix(hi: u64, lo: &mut u64) -> <Self as RadixType>::Base {
use num_integer::div_rem;
type BaseDouble = <RADIX_10p19_u64 as RadixType>::BaseDouble;
let num = BaseDouble::from(*lo) + (BaseDouble::from(hi) << 64);
let (q, r) = div_rem(num, Self::RADIX);
*lo = q.as_();
r.as_()
}
}
#[cfg(test)]
mod test_validate {
use super::*;
macro_rules! impl_case {
(valid $name:ident : $radix:ident ~ $values:expr) => {
#[test]
fn $name() {
assert!($radix::validate_digits($values.iter()));
}
};
(invalid $name:ident : $radix:ident ~ $values:expr) => {
#[test]
fn $name() {
assert!(!$radix::validate_digits($values.iter()));
}
};
}
impl_case!(valid case_valid: RADIX_10p4_i16 ~ [1, 2, 3, 4, 5, 600]);
impl_case!(invalid case_invalid_too_big: RADIX_10p4_i16 ~ [10000, 1, 2, 3, 4, 5, 600]);
impl_case!(invalid case_invalid_negative: RADIX_10p4_i16 ~ [1, 2, -3, 4, 5, 600]);
impl_case!(invalid case_invalid_leading_zeros: RADIX_10p4_i16 ~ [0, 1, 2, -3, 4, 5, 600]);
impl_case!(invalid case_p9_toobig: RADIX_10p9_u32 ~ [3330199352]);
}
impl RadixType for RADIX_u32 {
type Base = u32;
type BaseDouble = u64;
type SignedBase = i32;
const RADIX: Self::BaseDouble = 1u64 << 32;
fn validate_digits<'a, I: IntoIterator<Item = &'a Self::Base>>(_: I) -> bool {
true
}
fn expanding_add(a: u32, b: u32) -> (u32, u32) {
let (sum, overflow) = a.overflowing_add(b);
(u32::from(overflow), sum)
}
}
impl RadixType for RADIX_u64 {
type Base = u64;
type BaseDouble = u128;
type SignedBase = i64;
const RADIX: Self::BaseDouble = 1u128 << 64;
fn validate_digits<'a, I: IntoIterator<Item = &'a Self::Base>>(_: I) -> bool {
true
}
fn expanding_add(a: u64, b: u64) -> (u64, u64) {
let (sum, overflow) = a.overflowing_add(b);
(u64::from(overflow), sum)
}
}
impl RadixType for RADIX_10p4_i16 {
type Base = i16;
type BaseDouble = i32;
type SignedBase = i64;
const RADIX: Self::BaseDouble = 10_000;
}
impl RadixType for RADIX_10p9_u32 {
type Base = u32;
type BaseDouble = u64;
type SignedBase = i32;
const RADIX: Self::BaseDouble = 1_000_000_000;
}
impl RadixType for RADIX_10p19_u64 {
type Base = u64;
type BaseDouble = u128;
type SignedBase = i64;
const RADIX: Self::BaseDouble = 10_000_000_000_000_000_000;
}
impl RadixType for RADIX_10_u8 {
type Base = u8;
type BaseDouble = u8;
type SignedBase = i8;
const RADIX: Self::BaseDouble = 10;
}
#[cfg(test)]
mod tests {
use super::*;
include!("radix.tests.rs");
}