use crate::natural::InnerNatural::{Large, Small};
use crate::natural::Natural;
use crate::platform::Limb;
use alloc::vec::Vec;
use core::mem::swap;
use core::ops::{BitXor, BitXorAssign};
pub_test! {limbs_xor_limb(xs: &[Limb], y: Limb) -> Vec<Limb> {
let mut result = xs.to_vec();
limbs_xor_limb_in_place(&mut result, y);
result
}}
pub_test! {limbs_xor_limb_to_out(out: &mut [Limb], xs: &[Limb], y: Limb) {
out[..xs.len()].copy_from_slice(xs);
limbs_xor_limb_in_place(out, y);
}}
pub_test! {limbs_xor_limb_in_place(xs: &mut [Limb], y: Limb) {
xs[0] ^= y;
}}
pub_test! {limbs_xor_same_length(xs: &[Limb], ys: &[Limb]) -> Vec<Limb> {
assert_eq!(xs.len(), ys.len());
xs.iter().zip(ys.iter()).map(|(x, y)| x ^ y).collect()
}}
pub_test! {limbs_xor(xs: &[Limb], ys: &[Limb]) -> Vec<Limb> {
let xs_len = xs.len();
let ys_len = ys.len();
let mut result;
if xs_len >= ys_len {
result = limbs_xor_same_length(&xs[..ys_len], ys);
result.extend_from_slice(&xs[ys_len..]);
} else {
result = limbs_xor_same_length(xs, &ys[..xs_len]);
result.extend_from_slice(&ys[xs_len..]);
}
result
}}
pub_test! {limbs_xor_same_length_to_out(out: &mut [Limb], xs: &[Limb], ys: &[Limb]) {
let len = xs.len();
assert_eq!(len, ys.len());
assert!(out.len() >= len);
for (z, (x, y)) in out.iter_mut().zip(xs.iter().zip(ys.iter())) {
*z = x ^ y;
}
}}
pub_test! {limbs_xor_to_out(out: &mut [Limb], xs: &[Limb], ys: &[Limb]) {
let xs_len = xs.len();
let ys_len = ys.len();
if xs_len >= ys_len {
assert!(out.len() >= xs_len);
limbs_xor_same_length_to_out(out, &xs[..ys_len], ys);
out[ys_len..xs_len].copy_from_slice(&xs[ys_len..]);
} else {
assert!(out.len() >= ys_len);
limbs_xor_same_length_to_out(out, xs, &ys[..xs_len]);
out[xs_len..ys_len].copy_from_slice(&ys[xs_len..]);
}
}}
pub_test! {limbs_xor_same_length_in_place_left(xs: &mut [Limb], ys: &[Limb]) {
assert_eq!(xs.len(), ys.len());
for (x, y) in xs.iter_mut().zip(ys.iter()) {
*x ^= y;
}
}}
#[doc(hidden)]
pub fn limbs_xor_in_place_left(xs: &mut Vec<Limb>, ys: &[Limb]) {
let xs_len = xs.len();
let ys_len = ys.len();
if xs_len >= ys_len {
limbs_xor_same_length_in_place_left(&mut xs[..ys_len], ys);
} else {
limbs_xor_same_length_in_place_left(xs, &ys[..xs_len]);
xs.extend_from_slice(&ys[xs_len..]);
}
}
#[doc(hidden)]
pub fn limbs_xor_in_place_either(xs: &mut [Limb], ys: &mut [Limb]) -> bool {
let xs_len = xs.len();
let ys_len = ys.len();
let right = xs_len < ys_len;
if right {
limbs_xor_same_length_in_place_left(&mut ys[..xs_len], xs);
} else {
limbs_xor_same_length_in_place_left(&mut xs[..ys_len], ys);
}
right
}
impl Natural {
#[inline]
fn xor_limb(mut self, other: Limb) -> Self {
self.xor_assign_limb(other);
self
}
fn xor_limb_ref(&self, other: Limb) -> Self {
Self(match self {
Self(Small(small)) => Small(small ^ other),
Self(Large(limbs)) => Large(limbs_xor_limb(limbs, other)),
})
}
fn xor_assign_limb(&mut self, other: Limb) {
match self {
Self(Small(small)) => *small ^= other,
Self(Large(limbs)) => limbs_xor_limb_in_place(limbs, other),
}
}
}
impl BitXor<Self> for Natural {
type Output = Self;
#[inline]
fn bitxor(mut self, other: Self) -> Self {
self ^= other;
self
}
}
impl<'a> BitXor<&'a Self> for Natural {
type Output = Self;
#[inline]
fn bitxor(mut self, other: &'a Self) -> Self {
self ^= other;
self
}
}
impl BitXor<Natural> for &Natural {
type Output = Natural;
#[inline]
fn bitxor(self, mut other: Natural) -> Natural {
other ^= self;
other
}
}
impl BitXor<&Natural> for &Natural {
type Output = Natural;
fn bitxor(self, other: &Natural) -> Natural {
match (self, other) {
(x, &Natural(Small(y))) => x.xor_limb_ref(y),
(&Natural(Small(x)), y) => y.xor_limb_ref(x),
(Natural(Large(xs)), Natural(Large(ys))) => {
Natural::from_owned_limbs_asc(limbs_xor(xs, ys))
}
}
}
}
impl BitXorAssign<Self> for Natural {
fn bitxor_assign(&mut self, mut other: Self) {
match (&mut *self, &mut other) {
(_, Self(Small(y))) => self.xor_assign_limb(*y),
(Self(Small(x)), _) => *self = other.xor_limb(*x),
(Self(Large(xs)), Self(Large(ys))) => {
if limbs_xor_in_place_either(xs, ys) {
swap(xs, ys);
}
self.trim();
}
}
}
}
impl<'a> BitXorAssign<&'a Self> for Natural {
fn bitxor_assign(&mut self, other: &'a Self) {
match (&mut *self, other) {
(_, Self(Small(y))) => self.xor_assign_limb(*y),
(Self(Small(x)), _) => *self = other.xor_limb_ref(*x),
(Self(Large(xs)), Self(Large(ys))) => {
limbs_xor_in_place_left(xs, ys);
self.trim();
}
}
}
}