use crate::integer::Integer;
use crate::natural::InnerNatural::{Large, Small};
use crate::natural::Natural;
use crate::natural::logic::not::{limbs_not_in_place, limbs_not_to_out};
use crate::platform::Limb;
use alloc::vec::Vec;
use core::cmp::{Ordering::*, max};
use core::ops::{BitOr, BitOrAssign};
use itertools::repeat_n;
use malachite_base::num::arithmetic::traits::WrappingNegAssign;
use malachite_base::slices::{slice_leading_zeros, slice_set_zero};
pub_test! {limbs_neg_or_limb(xs: &[Limb], y: Limb) -> Vec<Limb> {
if y == 0 {
return xs.to_vec();
}
let mut out = vec![0; xs.len()];
let i = slice_leading_zeros(xs);
if i == 0 {
out[0] = (xs[0].wrapping_neg() | y).wrapping_neg();
out[1..].copy_from_slice(&xs[1..]);
} else {
out[0] = y.wrapping_neg();
for x in &mut out[1..i] {
*x = Limb::MAX;
}
out[i] = xs[i] - 1;
out[i + 1..].copy_from_slice(&xs[i + 1..]);
}
out
}}
pub_test! {limbs_neg_or_limb_to_out(out: &mut [Limb], xs: &[Limb], y: Limb) {
let len = xs.len();
assert!(out.len() >= len);
if y == 0 {
out[..len].copy_from_slice(xs);
return;
}
let i = slice_leading_zeros(xs);
if i == 0 {
out[0] = (xs[0].wrapping_neg() | y).wrapping_neg();
out[1..len].copy_from_slice(&xs[1..]);
} else {
out[0] = y.wrapping_neg();
for x in &mut out[1..i] {
*x = Limb::MAX;
}
out[i] = xs[i] - 1;
out[i + 1..len].copy_from_slice(&xs[i + 1..]);
}
}}
pub_test! {limbs_neg_or_limb_in_place(xs: &mut [Limb], y: Limb) {
if y == 0 {
return;
}
let i = slice_leading_zeros(xs);
if i == 0 {
xs[0] = (xs[0].wrapping_neg() | y).wrapping_neg();
} else {
xs[0] = y.wrapping_neg();
for x in &mut xs[1..i] {
*x = Limb::MAX;
}
xs[i] -= 1;
}
}}
pub_const_test! {limbs_pos_or_neg_limb(xs: &[Limb], y: Limb) -> Limb {
(xs[0] | y).wrapping_neg()
}}
pub_const_test! {limbs_neg_or_neg_limb(xs: &[Limb], y: Limb) -> Limb {
(xs[0].wrapping_neg() | y).wrapping_neg()
}}
pub_test! {limbs_or_pos_neg(xs: &[Limb], ys: &[Limb]) -> Vec<Limb> {
let xs_len = xs.len();
let ys_len = ys.len();
let x_i = slice_leading_zeros(xs);
let y_i = slice_leading_zeros(ys);
assert!(x_i < xs_len);
assert!(y_i < ys_len);
if y_i >= xs_len {
let mut out = vec![0; x_i];
out.push(xs[x_i].wrapping_neg());
out.extend(xs[x_i + 1..].iter().map(|x| !x));
out.extend(repeat_n(Limb::MAX, y_i - xs_len));
out.push(ys[y_i] - 1);
out.extend_from_slice(&ys[y_i + 1..]);
out
} else if x_i >= ys_len {
ys.to_vec()
} else {
let (min_i, max_i) = if x_i <= y_i { (x_i, y_i) } else { (y_i, x_i) };
let mut out = vec![0; min_i];
match x_i.cmp(&y_i) {
Equal => {
out.push((!xs[x_i] & (ys[y_i] - 1)) + 1);
}
Less => {
out.push(xs[x_i].wrapping_neg());
out.extend(xs[x_i + 1..y_i].iter().map(|x| !x));
out.push(!xs[y_i] & (ys[y_i] - 1));
}
Greater => {
out.extend_from_slice(&ys[y_i..x_i]);
out.push(!xs[x_i] & ys[x_i]);
}
}
out.extend(
xs[max_i + 1..]
.iter()
.zip(ys[max_i + 1..].iter())
.map(|(x, y)| !x & y),
);
if xs_len < ys_len {
out.extend_from_slice(&ys[xs_len..]);
}
out
}
}}
pub_test! {limbs_or_pos_neg_to_out(out: &mut [Limb], xs: &[Limb], ys: &[Limb]) {
let xs_len = xs.len();
let ys_len = ys.len();
assert!(out.len() >= ys_len);
let x_i = slice_leading_zeros(xs);
let y_i = slice_leading_zeros(ys);
assert!(x_i < xs_len);
assert!(y_i < ys_len);
if y_i >= xs_len {
slice_set_zero(&mut out[..x_i]);
out[x_i] = xs[x_i].wrapping_neg();
limbs_not_to_out(&mut out[x_i + 1..xs_len], &xs[x_i + 1..]);
for x in &mut out[xs_len..y_i] {
*x = Limb::MAX;
}
out[y_i] = ys[y_i] - 1;
out[y_i + 1..ys_len].copy_from_slice(&ys[y_i + 1..]);
} else if x_i >= ys_len {
out[..ys_len].copy_from_slice(ys);
} else {
let (min_i, max_i) = if x_i <= y_i { (x_i, y_i) } else { (y_i, x_i) };
slice_set_zero(&mut out[..min_i]);
match x_i.cmp(&y_i) {
Equal => {
out[x_i] = (!xs[x_i] & (ys[y_i] - 1)) + 1;
}
Less => {
out[x_i] = xs[x_i].wrapping_neg();
limbs_not_to_out(&mut out[x_i + 1..y_i], &xs[x_i + 1..y_i]);
out[y_i] = !xs[y_i] & (ys[y_i] - 1);
}
Greater => {
out[y_i..x_i].copy_from_slice(&ys[y_i..x_i]);
out[x_i] = !xs[x_i] & ys[x_i];
}
}
for (out, (x, y)) in out[max_i + 1..]
.iter_mut()
.zip(xs[max_i + 1..].iter().zip(ys[max_i + 1..].iter()))
{
*out = !x & y;
}
if xs_len < ys_len {
out[xs_len..ys_len].copy_from_slice(&ys[xs_len..]);
}
}
}}
pub_test! {limbs_slice_or_pos_neg_in_place_left(xs: &mut [Limb], ys: &[Limb]) -> bool {
let xs_len = xs.len();
let ys_len = ys.len();
let x_i = slice_leading_zeros(xs);
let y_i = slice_leading_zeros(ys);
assert!(x_i < xs_len);
assert!(y_i < ys_len);
if y_i >= xs_len {
xs[x_i].wrapping_neg_assign();
limbs_not_in_place(&mut xs[x_i + 1..]);
true
} else if x_i >= ys_len {
xs[..ys_len].copy_from_slice(ys);
slice_set_zero(&mut xs[ys_len..]);
false
} else {
let max_i = max(x_i, y_i);
match x_i.cmp(&y_i) {
Equal => {
xs[x_i] = (!xs[x_i] & (ys[y_i] - 1)) + 1;
}
Less => {
xs[x_i].wrapping_neg_assign();
limbs_not_in_place(&mut xs[x_i + 1..y_i]);
xs[y_i] = !xs[y_i] & (ys[y_i] - 1);
}
Greater => {
xs[y_i..x_i].copy_from_slice(&ys[y_i..x_i]);
xs[x_i] = !xs[x_i] & ys[x_i];
}
}
if xs_len < ys_len {
for (x, y) in xs[max_i + 1..].iter_mut().zip(ys[max_i + 1..xs_len].iter()) {
*x = !*x & y;
}
true
} else {
for (x, y) in xs[max_i + 1..ys_len].iter_mut().zip(ys[max_i + 1..].iter()) {
*x = !*x & y;
}
slice_set_zero(&mut xs[ys_len..]);
false
}
}
}}
pub_test! {limbs_vec_or_pos_neg_in_place_left(xs: &mut Vec<Limb>, ys: &[Limb]) {
let xs_len = xs.len();
let ys_len = ys.len();
let x_i = slice_leading_zeros(xs);
let y_i = slice_leading_zeros(ys);
assert!(x_i < xs_len);
assert!(y_i < ys_len);
if y_i >= xs_len {
xs[x_i].wrapping_neg_assign();
limbs_not_in_place(&mut xs[x_i + 1..]);
xs.extend(repeat_n(Limb::MAX, y_i - xs_len));
xs.push(ys[y_i] - 1);
xs.extend_from_slice(&ys[y_i + 1..]);
} else if x_i >= ys_len {
*xs = ys.to_vec();
} else {
let max_i = max(x_i, y_i);
match x_i.cmp(&y_i) {
Equal => {
xs[x_i] = (!xs[x_i] & (ys[y_i] - 1)) + 1;
}
Less => {
xs[x_i].wrapping_neg_assign();
limbs_not_in_place(&mut xs[x_i + 1..y_i]);
xs[y_i] = !xs[y_i] & (ys[y_i] - 1);
}
Greater => {
xs[y_i..x_i].copy_from_slice(&ys[y_i..x_i]);
xs[x_i] = !xs[x_i] & ys[x_i];
}
}
if xs_len < ys_len {
for (x, y) in xs[max_i + 1..].iter_mut().zip(ys[max_i + 1..xs_len].iter()) {
*x = !*x & y;
}
xs.extend_from_slice(&ys[xs_len..]);
} else {
for (x, y) in xs[max_i + 1..ys_len].iter_mut().zip(ys[max_i + 1..].iter()) {
*x = !*x & y;
}
xs.truncate(ys_len);
}
}
}}
pub_test! {limbs_or_pos_neg_in_place_right(xs: &[Limb], ys: &mut [Limb]) {
let xs_len = xs.len();
let ys_len = ys.len();
let x_i = slice_leading_zeros(xs);
let y_i = slice_leading_zeros(ys);
assert!(x_i < xs_len);
assert!(y_i < ys_len);
if y_i >= xs_len {
ys[x_i] = xs[x_i].wrapping_neg();
limbs_not_to_out(&mut ys[x_i + 1..xs_len], &xs[x_i + 1..]);
for y in &mut ys[xs_len..y_i] {
*y = Limb::MAX;
}
ys[y_i] -= 1;
} else if x_i < ys_len {
let max_i = max(x_i, y_i);
match x_i.cmp(&y_i) {
Equal => {
ys[y_i] = (!xs[x_i] & (ys[y_i] - 1)) + 1;
}
Less => {
ys[x_i] = xs[x_i].wrapping_neg();
limbs_not_to_out(&mut ys[x_i + 1..y_i], &xs[x_i + 1..y_i]);
ys[y_i] = !xs[y_i] & (ys[y_i] - 1);
}
Greater => {
ys[x_i] &= !xs[x_i];
}
}
if xs_len < ys_len {
for (x, y) in xs[max_i + 1..].iter().zip(ys[max_i + 1..xs_len].iter_mut()) {
*y &= !x;
}
} else {
for (x, y) in xs[max_i + 1..ys_len].iter().zip(ys[max_i + 1..].iter_mut()) {
*y &= !x;
}
}
}
}}
pub_test! {limbs_or_neg_neg(xs: &[Limb], ys: &[Limb]) -> Vec<Limb> {
let xs_len = xs.len();
let ys_len = ys.len();
let x_i = slice_leading_zeros(xs);
let y_i = slice_leading_zeros(ys);
assert!(x_i < xs_len);
assert!(y_i < ys_len);
if y_i >= xs_len {
xs.to_vec()
} else if x_i >= ys_len {
ys.to_vec()
} else {
let (min_i, max_i) = if x_i <= y_i { (x_i, y_i) } else { (y_i, x_i) };
let mut out = vec![0; min_i];
let x = match x_i.cmp(&y_i) {
Equal => ((xs[x_i] - 1) & (ys[y_i] - 1)) + 1,
Less => {
out.extend_from_slice(&xs[x_i..y_i]);
xs[y_i] & (ys[y_i] - 1)
}
Greater => {
out.extend_from_slice(&ys[y_i..x_i]);
(xs[x_i] - 1) & ys[x_i]
}
};
out.push(x);
out.extend(
xs[max_i + 1..]
.iter()
.zip(ys[max_i + 1..].iter())
.map(|(x, y)| x & y),
);
out
}
}}
pub_test! {limbs_or_neg_neg_to_out(out: &mut [Limb], xs: &[Limb], ys: &[Limb]) {
let xs_len = xs.len();
let ys_len = ys.len();
assert!(out.len() >= xs_len || out.len() >= ys_len);
let x_i = slice_leading_zeros(xs);
let y_i = slice_leading_zeros(ys);
assert!(x_i < xs_len);
assert!(y_i < ys_len);
if y_i >= xs_len {
out[..xs_len].copy_from_slice(xs);
} else if x_i >= ys_len {
out[..ys_len].copy_from_slice(ys);
} else {
let (min_i, max_i) = if x_i <= y_i { (x_i, y_i) } else { (y_i, x_i) };
slice_set_zero(&mut out[..min_i]);
let x = match x_i.cmp(&y_i) {
Equal => ((xs[x_i] - 1) & (ys[y_i] - 1)) + 1,
Less => {
out[x_i..y_i].copy_from_slice(&xs[x_i..y_i]);
xs[y_i] & (ys[y_i] - 1)
}
Greater => {
out[y_i..x_i].copy_from_slice(&ys[y_i..x_i]);
(xs[x_i] - 1) & ys[x_i]
}
};
out[max_i] = x;
for (out, (x, y)) in out[max_i + 1..]
.iter_mut()
.zip(xs[max_i + 1..].iter().zip(ys[max_i + 1..].iter()))
{
*out = x & y;
}
}
}}
pub_test! {limbs_slice_or_neg_neg_in_place_left(xs: &mut [Limb], ys: &[Limb]) {
let xs_len = xs.len();
let ys_len = ys.len();
let x_i = slice_leading_zeros(xs);
let y_i = slice_leading_zeros(ys);
assert!(x_i < xs_len);
assert!(y_i < ys_len);
if y_i >= xs_len {
} else if x_i >= ys_len {
xs[..ys_len].copy_from_slice(ys);
slice_set_zero(&mut xs[ys_len..]);
} else {
let max_i = max(x_i, y_i);
if x_i > y_i {
xs[y_i..x_i].copy_from_slice(&ys[y_i..x_i]);
}
xs[max_i] = match x_i.cmp(&y_i) {
Equal => ((xs[x_i] - 1) & (ys[y_i] - 1)) + 1,
Less => xs[y_i] & (ys[y_i] - 1),
Greater => (xs[x_i] - 1) & ys[x_i],
};
for (x, y) in xs[max_i + 1..].iter_mut().zip(ys[max_i + 1..].iter()) {
*x &= y;
}
if xs_len > ys_len {
slice_set_zero(&mut xs[ys_len..]);
}
}
}}
pub_test! {limbs_vec_or_neg_neg_in_place_left(xs: &mut Vec<Limb>, ys: &[Limb]) {
let xs_len = xs.len();
let ys_len = ys.len();
let x_i = slice_leading_zeros(xs);
let y_i = slice_leading_zeros(ys);
assert!(x_i < xs_len);
assert!(y_i < ys_len);
if y_i >= xs_len {
} else if x_i >= ys_len {
xs.truncate(ys_len);
xs.copy_from_slice(ys);
} else {
let max_i = max(x_i, y_i);
if x_i > y_i {
xs[y_i..x_i].copy_from_slice(&ys[y_i..x_i]);
}
xs[max_i] = match x_i.cmp(&y_i) {
Equal => ((xs[x_i] - 1) & (ys[y_i] - 1)) + 1,
Less => xs[y_i] & (ys[y_i] - 1),
Greater => (xs[x_i] - 1) & ys[x_i],
};
for (x, y) in xs[max_i + 1..].iter_mut().zip(ys[max_i + 1..].iter()) {
*x &= y;
}
xs.truncate(ys_len);
}
}}
pub_test! {limbs_or_neg_neg_in_place_either(xs: &mut [Limb], ys: &mut [Limb]) -> bool {
let xs_len = xs.len();
let ys_len = ys.len();
let x_i = slice_leading_zeros(xs);
let y_i = slice_leading_zeros(ys);
assert!(x_i < xs_len);
assert!(y_i < ys_len);
if y_i >= xs_len {
false
} else if x_i >= ys_len {
true
} else {
let max_i = max(x_i, y_i);
let boundary = match x_i.cmp(&y_i) {
Equal => ((xs[x_i] - 1) & (ys[y_i] - 1)) + 1,
Less => xs[y_i] & (ys[y_i] - 1),
Greater => (xs[x_i] - 1) & ys[x_i],
};
if xs_len > ys_len {
if y_i > x_i {
ys[x_i..y_i].copy_from_slice(&xs[x_i..y_i]);
}
ys[max_i] = boundary;
for (y, x) in ys[max_i + 1..].iter_mut().zip(xs[max_i + 1..].iter()) {
*y &= x;
}
true
} else {
if x_i > y_i {
xs[y_i..x_i].copy_from_slice(&ys[y_i..x_i]);
}
xs[max_i] = boundary;
for (x, y) in xs[max_i + 1..].iter_mut().zip(ys[max_i + 1..].iter()) {
*x &= y;
}
false
}
}
}}
impl Natural {
fn or_assign_pos_limb_neg(&mut self, other: Limb) {
*self = self.or_pos_limb_neg(other);
}
fn or_pos_limb_neg(&self, other: Limb) -> Self {
Self(Small(match self {
Self(Small(small)) => (small | other).wrapping_neg(),
Self(Large(limbs)) => limbs_pos_or_neg_limb(limbs, other),
}))
}
fn or_assign_neg_limb_neg(&mut self, other: Limb) {
*self = self.or_neg_limb_neg(other);
}
#[allow(clippy::missing_const_for_fn)]
fn or_neg_limb_neg(&self, other: Limb) -> Self {
Self(Small(match self {
Self(Small(small)) => (small.wrapping_neg() | other).wrapping_neg(),
Self(Large(limbs)) => limbs_neg_or_neg_limb(limbs, other),
}))
}
fn or_assign_neg_limb_pos(&mut self, other: Limb) {
match self {
Self(Small(small)) => {
*small = (small.wrapping_neg() | other).wrapping_neg();
}
Self(Large(limbs)) => {
limbs_neg_or_limb_in_place(limbs, other);
self.trim();
}
}
}
fn or_neg_limb_pos(&self, other: Limb) -> Self {
match self {
Self(Small(small)) => Self(Small((small.wrapping_neg() | other).wrapping_neg())),
Self(Large(limbs)) => Self::from_owned_limbs_asc(limbs_neg_or_limb(limbs, other)),
}
}
fn or_assign_pos_neg_ref(&mut self, other: &Self) {
match (&mut *self, other) {
(_, Self(Small(y))) => self.or_assign_pos_limb_neg(y.wrapping_neg()),
(Self(Small(x)), _) => *self = other.or_neg_limb_pos(*x),
(Self(Large(xs)), Self(Large(ys))) => {
limbs_vec_or_pos_neg_in_place_left(xs, ys);
self.trim();
}
}
}
fn or_assign_pos_neg(&mut self, mut other: Self) {
match (&mut *self, &mut other) {
(_, Self(Small(y))) => self.or_assign_pos_limb_neg(y.wrapping_neg()),
(Self(Small(x)), _) => {
other.or_assign_neg_limb_pos(*x);
*self = other;
}
(Self(Large(xs)), Self(Large(ys))) => {
limbs_or_pos_neg_in_place_right(xs, ys);
*self = other;
self.trim();
}
}
}
fn or_assign_neg_pos_ref(&mut self, other: &Self) {
match (&mut *self, other) {
(_, Self(Small(y))) => self.or_assign_neg_limb_pos(*y),
(Self(Small(x)), _) => *self = other.or_pos_limb_neg(x.wrapping_neg()),
(Self(Large(xs)), Self(Large(ys))) => {
limbs_or_pos_neg_in_place_right(ys, xs);
self.trim();
}
}
}
fn or_assign_neg_pos(&mut self, mut other: Self) {
match (&mut *self, &mut other) {
(_, Self(Small(y))) => self.or_assign_neg_limb_pos(*y),
(Self(Small(x)), _) => {
other.or_assign_pos_limb_neg(x.wrapping_neg());
*self = other;
}
(Self(Large(xs)), Self(Large(ys))) => {
limbs_or_pos_neg_in_place_right(ys, xs);
self.trim();
}
}
}
fn or_pos_neg(&self, other: &Self) -> Self {
match (self, other) {
(_, &Self(Small(y))) => self.or_pos_limb_neg(y.wrapping_neg()),
(&Self(Small(x)), _) => other.or_neg_limb_pos(x),
(Self(Large(xs)), Self(Large(ys))) => {
Self::from_owned_limbs_asc(limbs_or_pos_neg(xs, ys))
}
}
}
fn or_assign_neg_neg_ref(&mut self, other: &Self) {
match (&mut *self, other) {
(_, Self(Small(y))) => self.or_assign_neg_limb_neg(y.wrapping_neg()),
(Self(Small(x)), _) => *self = other.or_neg_limb_neg(x.wrapping_neg()),
(Self(Large(xs)), Self(Large(ys))) => {
limbs_vec_or_neg_neg_in_place_left(xs, ys);
self.trim();
}
}
}
fn or_assign_neg_neg(&mut self, mut other: Self) {
match (&mut *self, &mut other) {
(_, Self(Small(y))) => self.or_assign_neg_limb_neg(y.wrapping_neg()),
(Self(Small(x)), _) => {
other.or_assign_neg_limb_neg(x.wrapping_neg());
*self = other;
}
(Self(Large(xs)), Self(Large(ys))) => {
if limbs_or_neg_neg_in_place_either(xs, ys) {
*self = other;
}
self.trim();
}
}
}
fn or_neg_neg(&self, other: &Self) -> Self {
match (self, other) {
(_, &Self(Small(y))) => self.or_neg_limb_neg(y.wrapping_neg()),
(&Self(Small(x)), _) => other.or_neg_limb_neg(x.wrapping_neg()),
(Self(Large(xs)), Self(Large(ys))) => {
Self::from_owned_limbs_asc(limbs_or_neg_neg(xs, ys))
}
}
}
}
impl BitOr<Self> for Integer {
type Output = Self;
#[inline]
fn bitor(mut self, other: Self) -> Self {
self |= other;
self
}
}
impl<'a> BitOr<&'a Self> for Integer {
type Output = Self;
#[inline]
fn bitor(mut self, other: &'a Self) -> Self {
self |= other;
self
}
}
impl BitOr<Integer> for &Integer {
type Output = Integer;
#[inline]
fn bitor(self, mut other: Integer) -> Integer {
other |= self;
other
}
}
impl BitOr<&Integer> for &Integer {
type Output = Integer;
fn bitor(self, other: &Integer) -> Integer {
match (self.sign, other.sign) {
(true, true) => Integer {
sign: true,
abs: &self.abs | &other.abs,
},
(true, false) => Integer {
sign: false,
abs: self.abs.or_pos_neg(&other.abs),
},
(false, true) => Integer {
sign: false,
abs: other.abs.or_pos_neg(&self.abs),
},
(false, false) => Integer {
sign: false,
abs: self.abs.or_neg_neg(&other.abs),
},
}
}
}
impl BitOrAssign<Self> for Integer {
fn bitor_assign(&mut self, other: Self) {
match (self.sign, other.sign) {
(true, true) => self.abs.bitor_assign(other.abs),
(true, false) => {
self.sign = false;
self.abs.or_assign_pos_neg(other.abs);
}
(false, true) => self.abs.or_assign_neg_pos(other.abs),
(false, false) => self.abs.or_assign_neg_neg(other.abs),
}
}
}
impl<'a> BitOrAssign<&'a Self> for Integer {
fn bitor_assign(&mut self, other: &'a Self) {
match (self.sign, other.sign) {
(true, true) => self.abs.bitor_assign(&other.abs),
(true, false) => {
self.sign = false;
self.abs.or_assign_pos_neg_ref(&other.abs);
}
(false, true) => self.abs.or_assign_neg_pos_ref(&other.abs),
(false, false) => self.abs.or_assign_neg_neg_ref(&other.abs),
}
}
}