use crate::{
arch::word::Word,
buffer::Buffer,
ibig::IBig,
memory::MemoryAllocation,
mul,
primitive::extend_word,
sign::Sign::{self, *},
ubig::{Repr::*, UBig},
};
use core::{
mem,
ops::{Mul, MulAssign},
};
impl Mul<UBig> for UBig {
type Output = UBig;
fn mul(self, rhs: UBig) -> UBig {
match (self.into_repr(), rhs.into_repr()) {
(Small(word0), Small(word1)) => UBig::mul_word(word0, word1),
(Small(word0), Large(buffer1)) => UBig::mul_large_word(buffer1, word0),
(Large(buffer0), Small(word1)) => UBig::mul_large_word(buffer0, word1),
(Large(buffer0), Large(buffer1)) => UBig::mul_large(&buffer0, &buffer1),
}
}
}
impl Mul<&UBig> for UBig {
type Output = UBig;
fn mul(self, rhs: &UBig) -> UBig {
match self.into_repr() {
Small(word0) => match rhs.repr() {
Small(word1) => UBig::mul_word(word0, *word1),
Large(buffer1) => UBig::mul_large_word(buffer1.clone(), word0),
},
Large(buffer0) => match rhs.repr() {
Small(word1) => UBig::mul_large_word(buffer0, *word1),
Large(buffer1) => UBig::mul_large(&buffer0, buffer1),
},
}
}
}
impl Mul<UBig> for &UBig {
type Output = UBig;
fn mul(self, rhs: UBig) -> UBig {
rhs.mul(self)
}
}
impl Mul<&UBig> for &UBig {
type Output = UBig;
fn mul(self, rhs: &UBig) -> UBig {
match (self.repr(), rhs.repr()) {
(Small(word0), Small(word1)) => UBig::mul_word(*word0, *word1),
(Small(word0), Large(buffer1)) => UBig::mul_large_word(buffer1.clone(), *word0),
(Large(buffer0), Small(word1)) => UBig::mul_large_word(buffer0.clone(), *word1),
(Large(buffer0), Large(buffer1)) => UBig::mul_large(buffer0, buffer1),
}
}
}
impl MulAssign<UBig> for UBig {
fn mul_assign(&mut self, rhs: UBig) {
*self = mem::take(self) * rhs;
}
}
impl MulAssign<&UBig> for UBig {
fn mul_assign(&mut self, rhs: &UBig) {
*self = mem::take(self) * rhs;
}
}
impl Mul<IBig> for IBig {
type Output = IBig;
fn mul(self, rhs: IBig) -> IBig {
let (sign0, mag0) = self.into_sign_magnitude();
let (sign1, mag1) = rhs.into_sign_magnitude();
IBig::from_sign_magnitude(sign0 * sign1, mag0 * mag1)
}
}
impl Mul<&IBig> for IBig {
type Output = IBig;
fn mul(self, rhs: &IBig) -> IBig {
let (sign0, mag0) = self.into_sign_magnitude();
let (sign1, mag1) = (rhs.sign(), rhs.magnitude());
IBig::from_sign_magnitude(sign0 * sign1, mag0 * mag1)
}
}
impl Mul<IBig> for &IBig {
type Output = IBig;
fn mul(self, rhs: IBig) -> IBig {
rhs.mul(self)
}
}
impl Mul<&IBig> for &IBig {
type Output = IBig;
fn mul(self, rhs: &IBig) -> IBig {
let (sign0, mag0) = (self.sign(), self.magnitude());
let (sign1, mag1) = (rhs.sign(), rhs.magnitude());
IBig::from_sign_magnitude(sign0 * sign1, mag0 * mag1)
}
}
impl MulAssign<IBig> for IBig {
fn mul_assign(&mut self, rhs: IBig) {
*self = mem::take(self) * rhs;
}
}
impl MulAssign<&IBig> for IBig {
fn mul_assign(&mut self, rhs: &IBig) {
*self = mem::take(self) * rhs;
}
}
impl Mul<Sign> for Sign {
type Output = Sign;
fn mul(self, rhs: Sign) -> Sign {
match (self, rhs) {
(Positive, Positive) => Positive,
(Positive, Negative) => Negative,
(Negative, Positive) => Negative,
(Negative, Negative) => Positive,
}
}
}
impl MulAssign<Sign> for Sign {
fn mul_assign(&mut self, rhs: Sign) {
*self = *self * rhs;
}
}
impl UBig {
fn mul_word(a: Word, b: Word) -> UBig {
UBig::from(extend_word(a) * extend_word(b))
}
fn mul_large_word(mut buffer: Buffer, a: Word) -> UBig {
match a {
0 => UBig::from_word(0),
1 => buffer.into(),
_ => {
let carry = mul::mul_word_in_place(&mut buffer, a);
if carry != 0 {
buffer.push_may_reallocate(carry);
}
buffer.into()
}
}
}
fn mul_large(lhs: &[Word], rhs: &[Word]) -> UBig {
debug_assert!(lhs.len() >= 2 && rhs.len() >= 2);
let res_len = lhs.len() + rhs.len();
let mut buffer = Buffer::allocate(res_len);
buffer.push_zeros(res_len);
let mut allocation = MemoryAllocation::new(mul::memory_requirement_exact(
res_len,
lhs.len().min(rhs.len()),
));
let mut memory = allocation.memory();
let overflow = mul::add_signed_mul(&mut buffer, Positive, lhs, rhs, &mut memory);
assert!(overflow == 0);
buffer.into()
}
}