use crate::integer_polynomial::arithmetic::coefficient::PolynomialCoefficient;
use crate::integer_polynomial::arithmetic::vec::small_values;
use crate::platform::{SignedDoubleLimb, SignedLimb};
use alloc::vec::Vec;
use core::cmp::min;
use core::ptr;
use malachite_base::num::arithmetic::traits::Parity;
use malachite_base::num::basic::signeds::PrimitiveSigned;
use malachite_base::num::conversion::traits::ExactFrom;
pub(crate) fn mul_middle_to_out_tiny<
T: PrimitiveSigned + From<SignedLimb>,
C: PolynomialCoefficient + ExactFrom<T>,
>(
out: &mut [C],
xs: &[C],
ys: &[C],
nlo: usize,
nhi: usize,
) {
let len1 = xs.len();
let len2 = ys.len();
if ptr::eq(xs, ys) {
let xs: Vec<T> = small_values(xs);
for (o, i) in out.iter_mut().zip(nlo..nhi) {
let start = (i + 1).saturating_sub(len1);
let stop = min(len1, (i + 1) >> 1);
let mut s = T::ZERO;
for (&x, &y) in xs[start..stop]
.iter()
.zip(xs[i + 1 - stop..=i - start].iter().rev())
{
s += x * y;
}
s <<= 1u64;
if i.even() {
s += xs[i >> 1] * xs[i >> 1];
}
*o = C::exact_from(s);
}
} else {
let xs: Vec<T> = small_values(xs);
let ys: Vec<T> = small_values(ys);
for (o, i) in out.iter_mut().zip(nlo..nhi) {
let top1 = min(len1 - 1, i);
let top2 = min(len2 - 1, i);
let n = top1 + top2 + 1 - i;
let mut s = T::ZERO;
for (&x, &y) in xs[i - top2..i - top2 + n]
.iter()
.zip(ys[i - top1..i - top1 + n].iter().rev())
{
s += x * y;
}
*o = C::exact_from(s);
}
}
}
crate_test_fn! {
#[inline]
mul_middle_to_out_tiny_1<C: PolynomialCoefficient>(
out: &mut [C],
xs: &[C],
ys: &[C],
nlo: usize,
nhi: usize,
) {
mul_middle_to_out_tiny::<SignedLimb, C>(out, xs, ys, nlo, nhi);
}}
crate_test_fn! {
#[inline]
mul_middle_to_out_tiny_2<C: PolynomialCoefficient>(
out: &mut [C],
xs: &[C],
ys: &[C],
nlo: usize,
nhi: usize,
) {
mul_middle_to_out_tiny::<SignedDoubleLimb, C>(out, xs, ys, nlo, nhi);
}}