Skip to content

Commit

Permalink
Move iterators to a separate module
Browse files Browse the repository at this point in the history
  • Loading branch information
cuviper committed Feb 25, 2021
1 parent f58cef3 commit a6e88c5
Show file tree
Hide file tree
Showing 2 changed files with 286 additions and 281 deletions.
296 changes: 15 additions & 281 deletions src/biguint.rs
Original file line number Diff line number Diff line change
@@ -1,26 +1,26 @@
use crate::big_digit::{self, BigDigit};
use crate::std_alloc::{String, Vec};

use core::cmp;
use core::cmp::Ordering;
use core::default::Default;
use core::fmt;
use core::hash;
use core::iter::FusedIterator;
use core::mem;
use core::str;
use core::{u32, u64, u8};

use num_integer::{Integer, Roots};
use num_traits::{Num, One, Pow, ToPrimitive, Unsigned, Zero};

use crate::big_digit::{self, BigDigit};

mod addition;
mod division;
mod multiplication;
mod subtraction;

mod bits;
mod convert;
mod iter;
mod monty;
mod power;
mod shift;
Expand All @@ -32,6 +32,7 @@ mod arbitrary;
mod serde;

pub(crate) use self::convert::to_str_radix_reversed;
pub use self::iter::{U32Digits, U64Digits};

/// A big unsigned integer type.
#[derive(Debug)]
Expand Down Expand Up @@ -137,17 +138,6 @@ impl fmt::Octal for BigUint {
}
}

/// Convert a u32 chunk (len is either 1 or 2) to a single u64 digit
#[inline]
fn u32_chunk_to_u64(chunk: &[u32]) -> u64 {
// raw could have odd length
let mut digit = chunk[0] as u64;
if let Some(&hi) = chunk.get(1) {
digit |= (hi as u64) << 32;
}
digit
}

impl Zero for BigUint {
#[inline]
fn zero() -> BigUint {
Expand Down Expand Up @@ -512,231 +502,6 @@ pub trait ToBigUint {
fn to_biguint(&self) -> Option<BigUint>;
}

/// An iterator of `u32` digits representation of a `BigUint` or `BigInt`,
/// ordered least significant digit first.
pub struct U32Digits<'a> {
#[cfg(u64_digit)]
data: &'a [u64],
#[cfg(u64_digit)]
next_is_lo: bool,
#[cfg(u64_digit)]
last_hi_is_zero: bool,

#[cfg(not(u64_digit))]
it: core::slice::Iter<'a, u32>,
}

#[cfg(u64_digit)]
impl<'a> U32Digits<'a> {
#[inline]
fn new(data: &'a [u64]) -> Self {
let last_hi_is_zero = data
.last()
.map(|&last| {
let last_hi = (last >> 32) as u32;
last_hi == 0
})
.unwrap_or(false);
U32Digits {
data,
next_is_lo: true,
last_hi_is_zero,
}
}
}

#[cfg(u64_digit)]
impl Iterator for U32Digits<'_> {
type Item = u32;
#[inline]
fn next(&mut self) -> Option<u32> {
match self.data.split_first() {
Some((&first, data)) => {
let next_is_lo = self.next_is_lo;
self.next_is_lo = !next_is_lo;
if next_is_lo {
Some(first as u32)
} else {
self.data = data;
if data.is_empty() && self.last_hi_is_zero {
self.last_hi_is_zero = false;
None
} else {
Some((first >> 32) as u32)
}
}
}
None => None,
}
}

#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
let len = self.len();
(len, Some(len))
}

#[inline]
fn last(self) -> Option<u32> {
self.data.last().map(|&last| {
if self.last_hi_is_zero {
last as u32
} else {
(last >> 32) as u32
}
})
}

#[inline]
fn count(self) -> usize {
self.len()
}
}

#[cfg(u64_digit)]
impl ExactSizeIterator for U32Digits<'_> {
#[inline]
fn len(&self) -> usize {
self.data.len() * 2 - usize::from(self.last_hi_is_zero) - usize::from(!self.next_is_lo)
}
}

#[cfg(not(u64_digit))]
impl<'a> U32Digits<'a> {
#[inline]
fn new(data: &'a [u32]) -> Self {
Self { it: data.iter() }
}
}

#[cfg(not(u64_digit))]
impl Iterator for U32Digits<'_> {
type Item = u32;
#[inline]
fn next(&mut self) -> Option<u32> {
self.it.next().cloned()
}

#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
self.it.size_hint()
}

#[inline]
fn nth(&mut self, n: usize) -> Option<u32> {
self.it.nth(n).cloned()
}

#[inline]
fn last(self) -> Option<u32> {
self.it.last().cloned()
}

#[inline]
fn count(self) -> usize {
self.it.count()
}
}

#[cfg(not(u64_digit))]
impl ExactSizeIterator for U32Digits<'_> {
#[inline]
fn len(&self) -> usize {
self.it.len()
}
}

impl FusedIterator for U32Digits<'_> {}

/// An iterator of `u64` digits representation of a `BigUint` or `BigInt`,
/// ordered least significant digit first.
pub struct U64Digits<'a> {
#[cfg(not(u64_digit))]
it: core::slice::Chunks<'a, u32>,

#[cfg(u64_digit)]
it: core::slice::Iter<'a, u64>,
}

#[cfg(not(u64_digit))]
impl<'a> U64Digits<'a> {
#[inline]
fn new(data: &'a [u32]) -> Self {
U64Digits { it: data.chunks(2) }
}
}

#[cfg(not(u64_digit))]
impl Iterator for U64Digits<'_> {
type Item = u64;
#[inline]
fn next(&mut self) -> Option<u64> {
self.it.next().map(u32_chunk_to_u64)
}

#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
let len = self.len();
(len, Some(len))
}

#[inline]
fn last(self) -> Option<u64> {
self.it.last().map(u32_chunk_to_u64)
}

#[inline]
fn count(self) -> usize {
self.len()
}
}

#[cfg(u64_digit)]
impl<'a> U64Digits<'a> {
#[inline]
fn new(data: &'a [u64]) -> Self {
Self { it: data.iter() }
}
}

#[cfg(u64_digit)]
impl Iterator for U64Digits<'_> {
type Item = u64;
#[inline]
fn next(&mut self) -> Option<u64> {
self.it.next().cloned()
}

#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
self.it.size_hint()
}

#[inline]
fn nth(&mut self, n: usize) -> Option<u64> {
self.it.nth(n).cloned()
}

#[inline]
fn last(self) -> Option<u64> {
self.it.last().cloned()
}

#[inline]
fn count(self) -> usize {
self.it.count()
}
}

impl ExactSizeIterator for U64Digits<'_> {
#[inline]
fn len(&self) -> usize {
self.it.len()
}
}

impl FusedIterator for U64Digits<'_> {}

/// Creates and initializes a `BigUint`.
///
/// The digits are in little-endian base matching `BigDigit`.
Expand Down Expand Up @@ -1216,6 +981,17 @@ impl IntDigits for BigUint {
}
}

/// Convert a u32 chunk (len is either 1 or 2) to a single u64 digit
#[inline]
fn u32_chunk_to_u64(chunk: &[u32]) -> u64 {
// raw could have odd length
let mut digit = chunk[0] as u64;
if let Some(&hi) = chunk.get(1) {
digit |= (hi as u64) << 32;
}
digit
}

/// Combine four `u32`s into a single `u128`.
#[cfg(any(test, not(u64_digit)))]
#[inline]
Expand Down Expand Up @@ -1319,45 +1095,3 @@ fn test_u128_u32_roundtrip() {
assert_eq!(u32_to_u128(a, b, c, d), *val);
}
}

#[test]
fn test_iter_u32_digits() {
let n = BigUint::from(5u8);
let mut it = n.iter_u32_digits();
assert_eq!(it.len(), 1);
assert_eq!(it.next(), Some(5));
assert_eq!(it.len(), 0);
assert_eq!(it.next(), None);
assert_eq!(it.len(), 0);
assert_eq!(it.next(), None);

let n = BigUint::from(112500000000u64);
let mut it = n.iter_u32_digits();
assert_eq!(it.len(), 2);
assert_eq!(it.next(), Some(830850304));
assert_eq!(it.len(), 1);
assert_eq!(it.next(), Some(26));
assert_eq!(it.len(), 0);
assert_eq!(it.next(), None);
}

#[test]
fn test_iter_u64_digits() {
let n = BigUint::from(5u8);
let mut it = n.iter_u64_digits();
assert_eq!(it.len(), 1);
assert_eq!(it.next(), Some(5));
assert_eq!(it.len(), 0);
assert_eq!(it.next(), None);
assert_eq!(it.len(), 0);
assert_eq!(it.next(), None);

let n = BigUint::from(18_446_744_073_709_551_616u128);
let mut it = n.iter_u64_digits();
assert_eq!(it.len(), 2);
assert_eq!(it.next(), Some(0));
assert_eq!(it.len(), 1);
assert_eq!(it.next(), Some(1));
assert_eq!(it.len(), 0);
assert_eq!(it.next(), None);
}

0 comments on commit a6e88c5

Please sign in to comment.