use crate::natural::InnerNatural::{Large, Small};
use crate::natural::Natural;
use crate::platform::{DoubleLimb, Limb};
use alloc::vec::Vec;
use malachite_base::num::arithmetic::traits::XMulYToZZ;
use malachite_base::num::basic::traits::{One, Zero};
use malachite_base::num::basic::unsigneds::PrimitiveUnsigned;
use malachite_base::num::conversion::traits::{HasHalf, SplitInHalf};
pub_test! {limbs_mul_limb(xs: &[Limb], y: Limb) -> Vec<Limb> {
let mut carry = 0;
let y = DoubleLimb::from(y);
let mut out = Vec::with_capacity(xs.len());
for &x in xs {
let product = DoubleLimb::from(x) * y + DoubleLimb::from(carry);
out.push(product.lower_half());
carry = product.upper_half();
}
if carry != 0 {
out.push(carry);
}
out
}}
pub_crate_test! {limbs_mul_limb_with_carry_to_out<
DT: From<T> + HasHalf<Half = T> + PrimitiveUnsigned + SplitInHalf,
T: PrimitiveUnsigned,
>(
out: &mut [T],
xs: &[T],
y: T,
mut carry: T,
) -> T {
let y = DT::from(y);
for (out, x) in out[..xs.len()].iter_mut().zip(xs.iter()) {
let product = DT::from(*x) * y + DT::from(carry);
(carry, *out) = product.split_in_half();
}
carry
}}
pub_crate_test! {limbs_mul_limb_to_out<
DT: From<T> + HasHalf<Half = T> + PrimitiveUnsigned + SplitInHalf,
T: PrimitiveUnsigned,
>(
out: &mut [T],
xs: &[T],
y: T,
) -> T {
limbs_mul_limb_with_carry_to_out::<DT, T>(out, xs, y, T::ZERO)
}}
pub_crate_test! {limbs_slice_mul_limb_with_carry_in_place(
xs: &mut [Limb],
y: Limb,
mut carry: Limb
) -> Limb {
let y = DoubleLimb::from(y);
for x in &mut *xs {
let product = DoubleLimb::from(*x) * y + DoubleLimb::from(carry);
*x = product.lower_half();
carry = product.upper_half();
}
carry
}}
pub_crate_test! {limbs_slice_mul_limb_in_place(xs: &mut [Limb], y: Limb) -> Limb {
limbs_slice_mul_limb_with_carry_in_place(xs, y, 0)
}}
pub_test! {limbs_vec_mul_limb_in_place(xs: &mut Vec<Limb>, y: Limb) {
let carry = limbs_slice_mul_limb_in_place(xs, y);
if carry != 0 {
xs.push(carry);
}
}}
impl Natural {
pub(crate) fn mul_assign_limb(&mut self, other: Limb) {
match (&mut *self, other) {
(_, 0) => *self = Self::ZERO,
(_, 1) | (&mut Self::ZERO, _) => {}
(&mut Self::ONE, _) => *self = Self::from(other),
(Self(Small(small)), other) => {
let (upper, lower) = Limb::x_mul_y_to_zz(*small, other);
if upper == 0 {
*small = lower;
} else {
*self = Self(Large(vec![lower, upper]));
}
}
(Self(Large(limbs)), other) => {
limbs_vec_mul_limb_in_place(limbs, other);
}
}
}
pub(crate) fn mul_limb_ref(&self, other: Limb) -> Self {
match (self, other) {
(_, 0) => Self::ZERO,
(_, 1) | (&Self::ZERO, _) => self.clone(),
(&Self::ONE, _) => Self::from(other),
(Self(Small(small)), other) => Self({
let (upper, lower) = Limb::x_mul_y_to_zz(*small, other);
if upper == 0 {
Small(lower)
} else {
Large(vec![lower, upper])
}
}),
(Self(Large(limbs)), other) => Self(Large(limbs_mul_limb(limbs, other))),
}
}
}