use super::super::mul::limbs::{mul, mul_itch, sqr, sqr_itch};
use super::super::root::mul_1;
use super::Limbs;
const SEQUENTIAL: usize = 16;
pub(super) struct Packer {
pub(super) limbs: Limbs,
product: u64,
limit: u64,
}
impl Packer {
pub(super) fn new(max: u64, capacity: usize) -> Packer {
Packer {
limbs: Vec::with_capacity(capacity),
product: 1,
limit: u64::MAX / max.max(1),
}
}
#[inline(always)]
pub(super) fn push(&mut self, f: u64) {
if self.product > self.limit {
self.limbs.push(self.product);
self.product = f;
} else {
self.product *= f;
}
}
pub(super) fn finish(mut self) -> Limbs {
if self.product != 1 || self.limbs.is_empty() {
self.limbs.push(self.product);
}
self.limbs
}
}
pub(super) fn product(f: &[u64]) -> Limbs {
let n = f.len();
if n == 0 {
return vec![1];
}
let mut r: Limbs = Vec::with_capacity(n + 1);
let mut scratch = Vec::new();
let halves = 2 * n + 64;
unsafe {
let len = if halves <= LOCAL {
let mut local = [0u64; LOCAL];
product_into(f, r.as_mut_ptr(), local.as_mut_ptr(), &mut scratch)
} else {
let mut h = Vec::<u64>::with_capacity(halves);
product_into(f, r.as_mut_ptr(), h.as_mut_ptr(), &mut scratch)
};
r.set_len(len);
}
r
}
const LOCAL: usize = 128;
pub(super) unsafe fn product_into(
f: &[u64],
out: *mut u64,
halves: *mut u64,
scratch: &mut Vec<u64>,
) -> usize {
let n = f.len();
unsafe {
if n <= SEQUENTIAL {
*out = f[0];
let mut len = 1;
for &x in &f[1..] {
let carry = mul_1(out, out, len, x);
if carry != 0 {
*out.add(len) = carry;
len += 1;
}
}
return len;
}
let h = n / 2;
let (a, b) = (halves, halves.add(h));
let rest = halves.add(n);
let an = product_into(&f[..h], a, rest, scratch);
let bn = product_into(&f[h..], b, rest, scratch);
let ((x, xn), (y, yn)) = if an >= bn {
((a, an), (b, bn))
} else {
((b, bn), (a, an))
};
let itch = mul_itch(xn, yn);
if scratch.len() < itch {
scratch.resize(itch, 0);
}
mul(out, x, xn, y, yn, scratch.as_mut_ptr());
xn + yn - usize::from(*out.add(xn + yn - 1) == 0)
}
}
pub(super) fn times(x: &[u64], y: &[u64]) -> Limbs {
let (a, b) = if x.len() >= y.len() { (x, y) } else { (y, x) };
let mut r = Vec::with_capacity(a.len() + b.len() + 1);
let mut s = vec![0u64; mul_itch(a.len(), b.len())];
unsafe {
mul(
r.as_mut_ptr(),
a.as_ptr(),
a.len(),
b.as_ptr(),
b.len(),
s.as_mut_ptr(),
);
r.set_len(a.len() + b.len());
}
if r.last() == Some(&0) {
r.pop();
}
r
}
pub(super) fn squared(x: &[u64]) -> Limbs {
let mut r = Vec::with_capacity(2 * x.len() + 1);
let mut s = vec![0u64; sqr_itch(x.len())];
unsafe {
sqr(r.as_mut_ptr(), x.as_ptr(), x.len(), s.as_mut_ptr());
r.set_len(2 * x.len());
}
if r.last() == Some(&0) {
r.pop();
}
r
}