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::{BitOr, BitOrAssign};
pub fn limbs_or_limb(xs: &[Limb], y: Limb) -> Vec<Limb> {
let mut result = xs.to_vec();
limbs_or_limb_in_place(&mut result, y);
result
}
pub_test! {limbs_or_limb_to_out(out: &mut [Limb], xs: &[Limb], y: Limb) {
out[..xs.len()].copy_from_slice(xs);
limbs_or_limb_in_place(out, y);
}}
pub_test! {limbs_or_limb_in_place(xs: &mut [Limb], y: Limb) {
xs[0] |= y;
}}
pub_test! {limbs_or_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_or(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_or_same_length(&xs[..ys_len], ys);
result.extend_from_slice(&xs[ys_len..]);
} else {
result = limbs_or_same_length(xs, &ys[..xs_len]);
result.extend_from_slice(&ys[xs_len..]);
}
result
}}
pub_test! {limbs_or_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 (out_x, (x, y)) in out.iter_mut().zip(xs.iter().zip(ys.iter())) {
*out_x = x | y;
}
}}
pub_test! {limbs_or_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_or_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_or_same_length_to_out(out, xs, &ys[..xs_len]);
out[xs_len..ys_len].copy_from_slice(&ys[xs_len..]);
}
}}
pub_test! {limbs_or_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;
}
}}
pub_test! {limbs_or_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_or_same_length_in_place_left(&mut xs[..ys_len], ys);
} else {
limbs_or_same_length_in_place_left(xs, &ys[..xs_len]);
xs.extend_from_slice(&ys[xs_len..]);
}
}}
pub_test! {limbs_or_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_or_same_length_in_place_left(&mut ys[..xs_len], xs);
} else {
limbs_or_same_length_in_place_left(&mut xs[..ys_len], ys);
}
right
}}
impl Natural {
#[inline]
fn or_limb(mut self, other: Limb) -> Self {
self.or_assign_limb(other);
self
}
fn or_limb_ref(&self, other: Limb) -> Self {
Self(match self {
Self(Small(small)) => Small(small | other),
Self(Large(limbs)) => Large(limbs_or_limb(limbs, other)),
})
}
fn or_assign_limb(&mut self, other: Limb) {
match self {
Self(Small(small)) => *small |= other,
Self(Large(limbs)) => limbs_or_limb_in_place(limbs, other),
}
}
}
impl BitOr<Self> for Natural {
type Output = Self;
#[inline]
fn bitor(mut self, other: Self) -> Self {
self |= other;
self
}
}
impl<'a> BitOr<&'a Self> for Natural {
type Output = Self;
#[inline]
fn bitor(mut self, other: &'a Self) -> Self {
self |= other;
self
}
}
impl BitOr<Natural> for &Natural {
type Output = Natural;
#[inline]
fn bitor(self, mut other: Natural) -> Natural {
other |= self;
other
}
}
impl BitOr<&Natural> for &Natural {
type Output = Natural;
fn bitor(self, other: &Natural) -> Natural {
match (self, other) {
(x, &Natural(Small(y))) => x.or_limb_ref(y),
(&Natural(Small(x)), y) => y.or_limb_ref(x),
(Natural(Large(xs)), Natural(Large(ys))) => Natural(Large(limbs_or(xs, ys))),
}
}
}
impl BitOrAssign<Self> for Natural {
fn bitor_assign(&mut self, mut other: Self) {
match (&mut *self, &mut other) {
(_, Self(Small(y))) => self.or_assign_limb(*y),
(Self(Small(x)), _) => *self = other.or_limb(*x),
(Self(Large(xs)), Self(Large(ys))) => {
if limbs_or_in_place_either(xs, ys) {
swap(xs, ys);
}
}
}
}
}
impl<'a> BitOrAssign<&'a Self> for Natural {
fn bitor_assign(&mut self, other: &'a Self) {
match (&mut *self, other) {
(_, Self(Small(y))) => self.or_assign_limb(*y),
(Self(Small(x)), _) => *self = other.or_limb_ref(*x),
(Self(Large(xs)), Self(Large(ys))) => {
limbs_or_in_place_left(xs, ys);
}
}
}
}