use crate::iterators::bit_distributor::{BitDistributor, BitDistributorOutputType};
use crate::num::arithmetic::traits::{DivMod, DivisibleBy};
use crate::num::basic::unsigneds::PrimitiveUnsigned;
use crate::num::conversion::traits::{ExactFrom, WrappingFrom};
use core::cmp::Ordering::*;
use core::marker::PhantomData;
#[doc(hidden)]
#[derive(Clone, Debug)]
pub struct SameWidthIteratorToBitChunks<
I: Iterator<Item = T>,
T: PrimitiveUnsigned,
U: PrimitiveUnsigned,
> {
xs: I,
width: u64,
phantom: PhantomData<*const U>,
}
impl<I: Iterator<Item = T>, T: PrimitiveUnsigned, U: PrimitiveUnsigned>
SameWidthIteratorToBitChunks<I, T, U>
{
fn next_with_wrapping<F: Fn(T) -> U>(&mut self, wrap: F) -> Option<Option<U>> {
self.xs.next().map(|x| {
if x.significant_bits() <= self.width {
Some(wrap(x))
} else {
None
}
})
}
}
const fn same_width_iterator_to_bit_chunks<
I: Iterator<Item = T>,
T: PrimitiveUnsigned,
U: PrimitiveUnsigned,
>(
xs: I,
width: u64,
) -> SameWidthIteratorToBitChunks<I, T, U> {
SameWidthIteratorToBitChunks {
xs,
width,
phantom: PhantomData,
}
}
#[doc(hidden)]
#[derive(Clone, Debug)]
pub struct EvenFractionIteratorToBitChunks<
I: Iterator<Item = T>,
T: PrimitiveUnsigned,
U: PrimitiveUnsigned,
> {
xs: I,
x: T,
multiple: u64,
x_width: u64,
y_width: u64,
counter: u64,
phantom: PhantomData<*const U>,
}
impl<I: Iterator<Item = T>, T: PrimitiveUnsigned, U: PrimitiveUnsigned>
EvenFractionIteratorToBitChunks<I, T, U>
{
fn next_with_wrapping<F: Fn(T) -> U>(&mut self, wrap: F) -> Option<Option<U>> {
if self.counter == 0 {
if let Some(x) = self.xs.next() {
if x.significant_bits() > self.x_width {
return Some(None);
}
self.x = x;
self.counter = self.multiple;
} else {
return None;
}
} else {
self.x >>= self.y_width;
}
let y = wrap(self.x.mod_power_of_2(self.y_width));
self.counter -= 1;
Some(Some(y))
}
}
const fn even_fraction_iterator_to_bit_chunks<
I: Iterator<Item = T>,
T: PrimitiveUnsigned,
U: PrimitiveUnsigned,
>(
xs: I,
multiple: u64,
out_chunk_size: u64,
) -> EvenFractionIteratorToBitChunks<I, T, U> {
EvenFractionIteratorToBitChunks {
xs,
x: T::ZERO,
multiple,
x_width: multiple * out_chunk_size,
y_width: out_chunk_size,
counter: 0,
phantom: PhantomData,
}
}
#[doc(hidden)]
#[derive(Clone, Debug)]
pub struct EvenMultipleIteratorToBitChunks<
I: Iterator<Item = T>,
T: PrimitiveUnsigned,
U: PrimitiveUnsigned,
> {
xs: I,
x_width: u64,
y_width: u64,
done: bool,
phantom: PhantomData<*const U>,
}
impl<I: Iterator<Item = T>, T: PrimitiveUnsigned, U: PrimitiveUnsigned>
EvenMultipleIteratorToBitChunks<I, T, U>
{
fn next_with_wrapping<F: Fn(T) -> U>(&mut self, wrap: F) -> Option<Option<U>> {
if self.done {
return None;
}
let mut y = U::ZERO;
let mut shift = 0;
while shift < self.y_width {
if let Some(x) = self.xs.next() {
if x.significant_bits() > self.x_width {
return Some(None);
}
y |= wrap(x) << shift;
shift += self.x_width;
} else {
self.done = true;
break;
}
}
if shift == 0 { None } else { Some(Some(y)) }
}
}
const fn even_multiple_iterator_to_bit_chunks<
I: Iterator<Item = T>,
T: PrimitiveUnsigned,
U: PrimitiveUnsigned,
>(
xs: I,
in_chunk_size: u64,
out_chunk_size: u64,
) -> EvenMultipleIteratorToBitChunks<I, T, U> {
EvenMultipleIteratorToBitChunks {
xs,
x_width: in_chunk_size,
y_width: out_chunk_size,
done: false,
phantom: PhantomData,
}
}
#[doc(hidden)]
#[derive(Clone, Debug)]
pub struct IrregularIteratorToBitChunks<
I: Iterator<Item = T>,
T: PrimitiveUnsigned,
U: PrimitiveUnsigned,
> {
xs: I,
x: T,
x_width: u64,
y_width: u64,
remaining_x_bits: u64,
in_inner_loop: bool,
phantom: PhantomData<*const U>,
}
impl<I: Iterator<Item = T>, T: PrimitiveUnsigned, U: PrimitiveUnsigned>
IrregularIteratorToBitChunks<I, T, U>
{
fn next_with_wrapping<F: Fn(T) -> U>(&mut self, wrap: F) -> Option<Option<U>> {
let mut y = U::ZERO;
let mut remaining_y_bits = self.y_width;
loop {
if !self.in_inner_loop {
if let Some(x) = self.xs.next() {
if x.significant_bits() > self.x_width {
return Some(None);
}
self.x = x;
} else {
break;
}
self.remaining_x_bits = self.x_width;
self.in_inner_loop = true;
}
while self.remaining_x_bits != 0 {
let y_index = self.y_width - remaining_y_bits;
if self.remaining_x_bits <= remaining_y_bits {
y |= wrap(self.x) << y_index;
remaining_y_bits -= self.remaining_x_bits;
self.remaining_x_bits = 0;
} else {
y |= wrap(self.x).mod_power_of_2(remaining_y_bits) << y_index;
self.x >>= remaining_y_bits;
self.remaining_x_bits -= remaining_y_bits;
remaining_y_bits = 0;
}
if remaining_y_bits == 0 {
return Some(Some(y));
}
}
self.in_inner_loop = false;
}
if y == U::ZERO { None } else { Some(Some(y)) }
}
}
const fn irregular_iterator_to_bit_chunks<
I: Iterator<Item = T>,
T: PrimitiveUnsigned,
U: PrimitiveUnsigned,
>(
xs: I,
in_chunk_size: u64,
out_chunk_size: u64,
) -> IrregularIteratorToBitChunks<I, T, U> {
IrregularIteratorToBitChunks {
xs,
x: T::ZERO,
x_width: in_chunk_size,
y_width: out_chunk_size,
remaining_x_bits: 0,
in_inner_loop: false,
phantom: PhantomData,
}
}
#[derive(Clone, Debug)]
pub enum IteratorToBitChunks<I: Iterator<Item = T>, T: PrimitiveUnsigned, U: PrimitiveUnsigned> {
SameWidth(SameWidthIteratorToBitChunks<I, T, U>),
EvenFraction(EvenFractionIteratorToBitChunks<I, T, U>),
EvenMultiple(EvenMultipleIteratorToBitChunks<I, T, U>),
Irregular(IrregularIteratorToBitChunks<I, T, U>),
}
impl<I: Iterator<Item = T>, T: PrimitiveUnsigned, U: PrimitiveUnsigned>
IteratorToBitChunks<I, T, U>
{
pub(crate) fn next_with_wrapping<F: Fn(T) -> U>(&mut self, wrap: F) -> Option<Option<U>> {
match self {
Self::SameWidth(xs) => xs.next_with_wrapping(wrap),
Self::EvenFraction(xs) => xs.next_with_wrapping(wrap),
Self::EvenMultiple(xs) => xs.next_with_wrapping(wrap),
Self::Irregular(xs) => xs.next_with_wrapping(wrap),
}
}
}
impl<I: Iterator<Item = T>, T: PrimitiveUnsigned, U: PrimitiveUnsigned + WrappingFrom<T>> Iterator
for IteratorToBitChunks<I, T, U>
{
type Item = Option<U>;
#[inline]
fn next(&mut self) -> Option<Option<U>> {
self.next_with_wrapping(U::wrapping_from)
}
}
pub fn iterator_to_bit_chunks<I: Iterator<Item = T>, T: PrimitiveUnsigned, U: PrimitiveUnsigned>(
xs: I,
in_chunk_size: u64,
out_chunk_size: u64,
) -> IteratorToBitChunks<I, T, U> {
assert_ne!(in_chunk_size, 0);
assert_ne!(out_chunk_size, 0);
assert!(in_chunk_size <= T::WIDTH);
assert!(out_chunk_size <= U::WIDTH);
match in_chunk_size.cmp(&out_chunk_size) {
Equal => {
return IteratorToBitChunks::SameWidth(same_width_iterator_to_bit_chunks(
xs,
in_chunk_size,
));
}
Less => {
if out_chunk_size.divisible_by(in_chunk_size) {
return IteratorToBitChunks::EvenMultiple(even_multiple_iterator_to_bit_chunks(
xs,
in_chunk_size,
out_chunk_size,
));
}
}
Greater => {
let (multiple, remainder) = in_chunk_size.div_mod(out_chunk_size);
if remainder == 0 {
return IteratorToBitChunks::EvenFraction(even_fraction_iterator_to_bit_chunks(
xs,
multiple,
out_chunk_size,
));
}
}
}
IteratorToBitChunks::Irregular(irregular_iterator_to_bit_chunks(
xs,
in_chunk_size,
out_chunk_size,
))
}
#[derive(Clone, Debug, Eq, Hash, PartialEq)]
pub struct RulerSequence<T: ExactFrom<u32>> {
i: u64,
phantom: PhantomData<*const T>,
}
impl<T: ExactFrom<u32>> Iterator for RulerSequence<T> {
type Item = T;
fn next(&mut self) -> Option<T> {
self.i += 1;
Some(T::exact_from(self.i.trailing_zeros()))
}
}
pub const fn ruler_sequence<T: ExactFrom<u32>>() -> RulerSequence<T> {
RulerSequence {
i: 0,
phantom: PhantomData,
}
}
#[derive(Clone, Debug)]
pub struct BitDistributorSequence {
bit_distributor: BitDistributor,
}
impl Iterator for BitDistributorSequence {
type Item = usize;
fn next(&mut self) -> Option<usize> {
let i = self.bit_distributor.get_output(1);
self.bit_distributor.increment_counter();
Some(i)
}
}
pub fn bit_distributor_sequence(
x_output_type: BitDistributorOutputType,
y_output_type: BitDistributorOutputType,
) -> BitDistributorSequence {
BitDistributorSequence {
bit_distributor: BitDistributor::new(&[y_output_type, x_output_type]),
}
}