#![allow(dead_code)]
use crate::*;
use super::radix::RadixPowerOfTen;
use super::endian::LittleEndian;
use crate::arithmetic::diff_usize;
type BigDigitVec<R> = super::digitvec::DigitVec<R, LittleEndian>;
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub(crate) enum AddAssignSliceAlignment {
RightOverlap {
count: usize,
},
RightDisjoint {
count: usize,
},
LeftOverlap {
count: usize,
},
LeftDisjoint {
count: usize,
},
}
impl AddAssignSliceAlignment {
pub fn from_lengths_and_scales(lhs: WithScale<usize>, rhs: WithScale<usize>) -> Self {
use cmp::Ordering::*;
match diff_usize(rhs.scale, lhs.scale) {
(Equal, _) => {
Self::RightOverlap {
count: 0,
}
}
(Less, count) => {
if count < lhs.value {
Self::RightOverlap {
count,
}
} else {
Self::RightDisjoint {
count,
}
}
}
(Greater, count) => {
if count < rhs.value {
Self::LeftOverlap {
count,
}
} else {
Self::LeftDisjoint {
count,
}
}
}
}
}
pub fn from_lengths_and_icount(lhs: WithIntCount<usize>, rhs: WithIntCount<usize>) -> Self {
Self::from_lengths_and_scales(
WithScale {
scale: lhs.value as i64 - lhs.count as i64,
value: lhs.value,
},
WithScale {
scale: rhs.value as i64 - rhs.count as i64,
value: rhs.value,
},
)
}
}
#[derive(Copy, Clone, Debug)]
pub(crate) struct BigDigitSplitterIter<R, I>
where
R: RadixPowerOfTen,
I: Iterator<Item = R::Base>,
{
shift: ShiftState<R>,
digits: I,
}
impl<R, I> BigDigitSplitterIter<R, I>
where
R: RadixPowerOfTen,
I: Iterator<Item = R::Base>,
{
pub fn new(iter: I) -> Self {
Self::from_shifter_and_iter(ShiftState::Zero, iter)
}
pub fn from_shifter_and_iter(shifter: ShiftState<R>, iter: I) -> Self {
Self {
shift: shifter,
digits: iter,
}
}
pub fn mask(&self) -> R::Base {
match self.shift {
ShiftState::Zero => Zero::zero(),
ShiftState::Shifted {
mask:
BigDigitSplitter {
mask,
..
},
..
} => mask,
}
}
pub fn shift_minus_one(&self) -> R::Base {
match self {
BigDigitSplitterIter {
shift: ShiftState::Zero,
..
} => R::max(),
BigDigitSplitterIter {
shift:
ShiftState::Shifted {
mask,
..
},
..
} => mask.shift - One::one(),
}
}
pub fn extend_vector(self, dest: &mut BigDigitVec<R>) {
if let Self {
shift: ShiftState::Zero,
digits,
..
} = self
{
dest.digits.extend(digits);
} else {
dest.digits.extend(self);
}
}
pub(crate) fn extend_vector_adding_carry(
mut self,
mut carry: R::Base,
dest: &mut BigDigitVec<R>,
) {
while !carry.is_zero() {
if let Some(mut next_digit) = self.next() {
R::addassign_carry(&mut next_digit, &mut carry);
dest.push_significant_digit(next_digit);
} else {
dest.push_significant_digit(carry);
return;
}
}
self.extend_vector(dest)
}
pub(crate) fn extend_vector_with_carry_borrow(
mut self,
carry: &mut R::Base,
borrow: &mut R::Base,
dest: &mut BigDigitVec<R>,
) {
use num_traits::WrappingSub;
if borrow.is_zero() && carry.is_zero() {
return self.extend_vector(dest);
}
if carry == borrow {
*borrow = Zero::zero();
*carry = Zero::zero();
return self.extend_vector(dest);
}
match self.next() {
Some(digit) => {
let d = R::sub_with_carry_borrow(digit, R::Base::zero(), carry, borrow);
dest.push_significant_digit(d);
self.extend_vector_with_carry_borrow(borrow, carry, dest);
}
None if carry == borrow => {}
None if carry > borrow => {
dest.push_significant_digit(carry.wrapping_sub(borrow));
*carry = Zero::zero();
*borrow = Zero::zero();
}
None => {
unreachable!("borrow underflow");
}
}
}
pub fn advance_by_n(&mut self, n: usize) {
for _ in 0..n {
if self.next().is_none() {
break;
}
}
}
fn on_next_digit(&mut self, digit: R::Base) -> R::Base {
if let ShiftState::Shifted {
ref mut prev,
ref mask,
} = self.shift
{
let (hi, mut lo) = mask.split_and_shift(digit);
lo += *prev;
*prev = hi;
lo
} else {
digit
}
}
fn on_last_digit(&mut self) -> Option<R::Base> {
match self.shift {
ShiftState::Shifted {
ref mut prev,
..
} if !prev.is_zero() => {
let result = *prev;
*prev = Zero::zero();
Some(result)
}
_ => None,
}
}
}
impl<R, I> Iterator for BigDigitSplitterIter<R, I>
where
R: RadixPowerOfTen,
I: Iterator<Item = R::Base>,
{
type Item = R::Base;
fn next(&mut self) -> Option<Self::Item> {
self.digits
.next()
.map(|digit| self.on_next_digit(digit))
.or_else(|| self.on_last_digit())
}
}
type CopiedDigitSlice<'a, R> =
stdlib::iter::Copied<stdlib::slice::Iter<'a, <R as super::radix::RadixType>::Base>>;
pub(crate) type BigDigitSliceSplitterIter<'a, R> = BigDigitSplitterIter<R, CopiedDigitSlice<'a, R>>;
impl<'a, R: RadixPowerOfTen> BigDigitSliceSplitterIter<'a, R> {
fn comp_n(n: usize) -> usize {
debug_assert!(n < R::DIGITS);
if n == 0 {
0
} else {
R::DIGITS - n
}
}
pub fn from_slice(slice: &'a [R::Base]) -> Self {
Self {
shift: ShiftState::Zero,
digits: slice.iter().copied(),
}
}
pub(crate) fn from_slice_shifting_left(slice: &'a [R::Base], n: usize) -> Self {
Self::from_slice_starting_bottom(slice, Self::comp_n(n))
}
pub(crate) fn from_slice_shifting_right(slice: &'a [R::Base], n: usize) -> Self {
Self::from_slice_starting_top(slice, Self::comp_n(n))
}
pub(crate) fn from_slice_starting_bottom(slice: &'a [R::Base], n: usize) -> Self {
Self::from_shifter_and_iter(ShiftState::starting_with_bottom(n), slice.iter().copied())
}
pub(crate) fn from_slice_starting_top(slice: &'a [R::Base], n: usize) -> Self {
let mut digits = slice.iter().copied();
let shifter = ShiftState::starting_with_top(n, &mut digits);
Self::from_shifter_and_iter(shifter, digits)
}
pub fn is_exhausted(&self) -> bool {
match self.shift {
ShiftState::Zero => self.digits.len() == 0,
_ => self.peek_next().is_none(),
}
}
pub fn peek_next(&self) -> Option<R::Base> {
self.clone().next()
}
}
#[derive(Copy, Clone, Debug)]
pub(crate) enum ShiftState<R: RadixPowerOfTen> {
Zero,
Shifted {
mask: BigDigitSplitter<R>,
prev: R::Base,
},
}
impl<R: RadixPowerOfTen> ShiftState<R> {
fn starting_with_bottom(n: usize) -> Self {
if n == 0 {
Self::Zero
} else {
Self::Shifted {
mask: BigDigitSplitter::mask_low(n as u8),
prev: R::Base::zero(),
}
}
}
fn starting_with_top<I: Iterator<Item = R::Base>>(n: usize, digits: &mut I) -> Self {
if n == 0 {
Self::Zero
} else {
let mask = BigDigitSplitter::mask_high(n);
let first_digit = digits.next().map(|d| d / mask.mask).unwrap_or(Zero::zero());
Self::Shifted {
mask: mask,
prev: first_digit,
}
}
}
}
#[derive(Copy, Clone, Debug)]
pub(crate) struct BigDigitSplitter<R: RadixPowerOfTen> {
mask: R::Base,
shift: R::Base,
}
impl<R: RadixPowerOfTen> BigDigitSplitter<R> {
pub fn mask_low(n: u8) -> Self {
use crate::arithmetic::ten_to_the_t;
debug_assert!((n as usize) < R::DIGITS);
let mask = ten_to_the_t(n);
let shift = ten_to_the_t(R::DIGITS as u8 - n);
Self {
shift,
mask,
}
}
pub fn mask_high(n: usize) -> Self {
Self::mask_low((R::DIGITS - n) as u8)
}
pub fn split(&self, n: R::Base) -> (R::Base, R::Base) {
let lo = n % self.mask;
(n - lo, lo)
}
pub fn split_and_shift(&self, n: R::Base) -> (R::Base, R::Base) {
let (hi, lo) = self.div_rem(n);
(hi, lo * self.shift)
}
pub fn div_rem(&self, n: R::Base) -> (R::Base, R::Base) {
n.div_rem(&self.mask)
}
pub fn div(&self, n: R::Base) -> R::Base {
n / self.mask
}
}
#[derive(Clone, Copy, Debug, Default)]
pub(crate) struct WithIntCount<T> {
count: i32,
value: T,
}
#[cfg(test)]
#[allow(clippy::zero_prefixed_literal)]
mod test {
use super::*;
include!("alignment.tests.rs");
}