use crate::num::arithmetic::traits::{DivRound, SaturatingSubAssign};
use crate::num::basic::unsigneds::PrimitiveUnsigned;
use crate::num::conversion::traits::{
ExactFrom, PowerOf2DigitIterable, PowerOf2DigitIterator, WrappingFrom,
};
use crate::num::logic::traits::BitBlockAccess;
use crate::rounding_modes::RoundingMode::*;
use core::marker::PhantomData;
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub struct PrimitivePowerOf2DigitIterator<T: PrimitiveUnsigned, U: PrimitiveUnsigned> {
pub(crate) value: T,
pub(crate) log_base: u64,
pub(crate) remaining: usize,
pub(crate) i: u64,
pub(crate) j: u64,
phantom: PhantomData<*const U>,
}
impl<T: PrimitiveUnsigned, U: PrimitiveUnsigned + WrappingFrom<<T as BitBlockAccess>::Bits>>
Iterator for PrimitivePowerOf2DigitIterator<T, U>
{
type Item = U;
fn next(&mut self) -> Option<U> {
if self.remaining != 0 {
let digit = U::wrapping_from(self.value.get_bits(self.i, self.i + self.log_base));
self.i += self.log_base;
self.remaining -= 1;
Some(digit)
} else {
None
}
}
fn size_hint(&self) -> (usize, Option<usize>) {
(self.remaining, Some(self.remaining))
}
}
impl<T: PrimitiveUnsigned, U: PrimitiveUnsigned + WrappingFrom<<T as BitBlockAccess>::Bits>>
DoubleEndedIterator for PrimitivePowerOf2DigitIterator<T, U>
{
fn next_back(&mut self) -> Option<U> {
if self.remaining != 0 {
let digit = U::wrapping_from(self.value.get_bits(self.j, self.j + self.log_base));
self.j.saturating_sub_assign(self.log_base);
self.remaining -= 1;
Some(digit)
} else {
None
}
}
}
impl<T: PrimitiveUnsigned, U: PrimitiveUnsigned + WrappingFrom<<T as BitBlockAccess>::Bits>>
ExactSizeIterator for PrimitivePowerOf2DigitIterator<T, U>
{
}
impl<T: PrimitiveUnsigned, U: PrimitiveUnsigned + WrappingFrom<<T as BitBlockAccess>::Bits>>
PowerOf2DigitIterator<U> for PrimitivePowerOf2DigitIterator<T, U>
{
fn get_digit(&self, index: u64) -> U {
let i = index * self.log_base;
U::wrapping_from(self.value.get_bits(i, i + self.log_base))
}
}
fn power_of_2_digits<T: PrimitiveUnsigned, U: PrimitiveUnsigned>(
x: T,
log_base: u64,
) -> PrimitivePowerOf2DigitIterator<T, U> {
assert_ne!(log_base, 0);
assert!(
log_base <= U::WIDTH,
"type {:?} is too small for a digit of width {}",
U::NAME,
log_base
);
let significant_digits = x.significant_bits().div_round(log_base, Ceiling).0;
PrimitivePowerOf2DigitIterator {
value: x,
log_base,
remaining: usize::exact_from(significant_digits),
i: 0,
j: significant_digits.saturating_sub(1) * log_base,
phantom: PhantomData,
}
}
macro_rules! impl_power_of_2_digit_iterable {
($t:ident) => {
macro_rules! impl_power_of_2_digit_iterable_inner {
($u:ident) => {
impl PowerOf2DigitIterable<$u> for $t {
type PowerOf2DigitIterator = PrimitivePowerOf2DigitIterator<$t, $u>;
#[inline]
fn power_of_2_digits(
self,
log_base: u64,
) -> PrimitivePowerOf2DigitIterator<$t, $u> {
power_of_2_digits(self, log_base)
}
}
};
}
apply_to_unsigneds!(impl_power_of_2_digit_iterable_inner);
};
}
apply_to_unsigneds!(impl_power_of_2_digit_iterable);