use crate::integer::Integer;
use crate::natural::InnerNatural::{Large, Small};
use crate::natural::Natural;
use crate::natural::arithmetic::add::{limbs_add_limb_to_out, limbs_slice_add_limb_in_place};
use crate::platform::Limb;
use alloc::vec::Vec;
use core::cmp::{Ordering::*, max};
use core::ops::{BitAnd, BitAndAssign};
use malachite_base::num::arithmetic::traits::WrappingNegAssign;
use malachite_base::num::basic::traits::Zero;
use malachite_base::num::logic::traits::NotAssign;
use malachite_base::slices::{slice_leading_zeros, slice_set_zero};
pub_test! {limbs_pos_and_limb_neg(xs: &[Limb], y: Limb) -> Vec<Limb> {
let mut out = xs.to_vec();
out[0] &= y;
out
}}
pub_test! {limbs_pos_and_limb_neg_to_out(out: &mut [Limb], xs: &[Limb], y: Limb) {
let len = xs.len();
assert!(out.len() >= len);
let (xs_head, xs_tail) = xs.split_first().unwrap();
let (out_head, out_tail) = out[..len].split_first_mut().unwrap();
*out_head = xs_head & y;
out_tail.copy_from_slice(xs_tail);
}}
pub_test! {limbs_pos_and_limb_neg_in_place(xs: &mut [Limb], ys: Limb) {
xs[0] &= ys;
}}
pub_test! {limbs_neg_and_limb_neg(xs: &[Limb], y: Limb) -> Vec<Limb> {
let mut out = xs.to_vec();
limbs_vec_neg_and_limb_neg_in_place(&mut out, y);
out
}}
pub_test! {limbs_neg_and_limb_neg_to_out(out: &mut [Limb], xs: &[Limb], y: Limb) -> bool {
let out = &mut out[..xs.len()];
if xs[0] == 0 {
out.copy_from_slice(xs);
false
} else {
let (xs_head, xs_tail) = xs.split_first().unwrap();
let (out_head, out_tail) = out.split_first_mut().unwrap();
let result_head = xs_head.wrapping_neg() & y;
if result_head == 0 {
*out_head = 0;
limbs_add_limb_to_out(out_tail, xs_tail, 1)
} else {
*out_head = result_head.wrapping_neg();
out_tail.copy_from_slice(xs_tail);
false
}
}
}}
pub_test! {limbs_slice_neg_and_limb_neg_in_place(xs: &mut [Limb], y: Limb) -> bool {
let (xs_head, xs_tail) = xs.split_first_mut().unwrap();
if *xs_head == 0 {
false
} else {
*xs_head = xs_head.wrapping_neg() & y;
if *xs_head == 0 {
limbs_slice_add_limb_in_place(xs_tail, 1)
} else {
xs_head.wrapping_neg_assign();
false
}
}
}}
pub_test! {limbs_vec_neg_and_limb_neg_in_place(xs: &mut Vec<Limb>, y: Limb) {
if limbs_slice_neg_and_limb_neg_in_place(xs, y) {
xs.push(1);
}
}}
pub_test! {limbs_and_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 {
return Vec::new();
} else if x_i >= ys_len {
return xs.to_vec();
}
let max_i = max(x_i, y_i);
let mut out = vec![0; max_i];
out.push(
xs[max_i]
& if x_i <= y_i {
ys[max_i].wrapping_neg()
} else {
!ys[max_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(&xs[ys_len..]);
}
out
}}
pub_test! {limbs_and_pos_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);
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[..xs_len]);
return;
} else if x_i >= ys_len {
out[..xs_len].copy_from_slice(xs);
return;
}
let max_i = max(x_i, y_i);
slice_set_zero(&mut out[..max_i]);
out[max_i] = xs[max_i]
& if x_i <= y_i {
ys[max_i].wrapping_neg()
} else {
!ys[max_i]
};
for (z, (x, y)) in out[max_i + 1..]
.iter_mut()
.zip(xs[max_i + 1..].iter().zip(ys[max_i + 1..].iter()))
{
*z = x & !y;
}
if xs_len > ys_len {
out[ys_len..xs_len].copy_from_slice(&xs[ys_len..]);
}
}}
pub_test! {limbs_and_pos_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 {
slice_set_zero(xs);
return;
} else if x_i >= ys_len {
return;
}
let max_i = max(x_i, y_i);
slice_set_zero(&mut xs[..max_i]);
xs[max_i] &= if x_i <= y_i {
ys[max_i].wrapping_neg()
} else {
!ys[max_i]
};
for (x, y) in xs[max_i + 1..].iter_mut().zip(ys[max_i + 1..].iter()) {
*x &= !y;
}
}}
pub_test! {limbs_slice_and_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 || x_i >= ys_len {
slice_set_zero(ys);
return;
}
let max_i = max(x_i, y_i);
slice_set_zero(&mut ys[..max_i]);
{
let ys_max_i = &mut ys[max_i];
if x_i <= y_i {
ys_max_i.wrapping_neg_assign();
} else {
ys_max_i.not_assign();
}
*ys_max_i &= xs[max_i];
}
for (x, y) in xs[max_i + 1..].iter().zip(ys[max_i + 1..].iter_mut()) {
*y = !*y & x;
}
}}
pub_test! {limbs_vec_and_pos_neg_in_place_right(xs: &[Limb], ys: &mut Vec<Limb>) {
limbs_slice_and_pos_neg_in_place_right(xs, ys);
let xs_len = xs.len();
let ys_len = ys.len();
match xs_len.cmp(&ys_len) {
Greater => {
let ys_len = ys.len();
ys.extend(xs[ys_len..].iter());
}
Less => {
ys.truncate(xs_len);
}
_ => {}
}
}}
const fn limbs_and_neg_neg_helper(input: Limb, boundary_limb_seen: &mut bool) -> Limb {
if *boundary_limb_seen {
input
} else {
let result = input.wrapping_add(1);
if result != 0 {
*boundary_limb_seen = true;
}
result
}
}
pub_test! {limbs_and_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 {
return ys.to_vec();
} else if x_i >= ys_len {
return xs.to_vec();
}
let max_i = max(x_i, y_i);
let mut out = vec![0; max_i];
let x = if x_i >= y_i {
xs[max_i].wrapping_sub(1)
} else {
xs[max_i]
};
let y = if x_i <= y_i {
ys[max_i].wrapping_sub(1)
} else {
ys[max_i]
};
let mut boundary_limb_seen = false;
out.push(limbs_and_neg_neg_helper(x | y, &mut boundary_limb_seen));
let xys = xs[max_i + 1..].iter().zip(ys[max_i + 1..].iter());
if boundary_limb_seen {
out.extend(xys.map(|(&x, &y)| x | y));
} else {
for (&x, &y) in xys {
out.push(limbs_and_neg_neg_helper(x | y, &mut boundary_limb_seen));
}
}
if xs_len != ys_len {
let zs = if xs_len > ys_len {
&xs[ys_len..]
} else {
&ys[xs_len..]
};
if boundary_limb_seen {
out.extend_from_slice(zs);
} else {
for &z in zs {
out.push(limbs_and_neg_neg_helper(z, &mut boundary_limb_seen));
}
}
}
if !boundary_limb_seen {
out.push(1);
}
out
}}
pub_test! {limbs_and_neg_neg_to_out(out: &mut [Limb], xs: &[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 {
out[..ys_len].copy_from_slice(ys);
if xs_len > ys_len {
slice_set_zero(&mut out[ys_len..xs_len]);
}
return true;
} else if x_i >= ys_len {
out[..xs_len].copy_from_slice(xs);
if ys_len > xs_len {
slice_set_zero(&mut out[xs_len..ys_len]);
}
return true;
}
let max_i = max(x_i, y_i);
slice_set_zero(&mut out[..max_i]);
let x = if x_i >= y_i {
xs[max_i].wrapping_sub(1)
} else {
xs[max_i]
};
let y = if x_i <= y_i {
ys[max_i].wrapping_sub(1)
} else {
ys[max_i]
};
let mut boundary_limb_seen = false;
out[max_i] = limbs_and_neg_neg_helper(x | y, &mut boundary_limb_seen);
let xys = xs[max_i + 1..].iter().zip(ys[max_i + 1..].iter());
if boundary_limb_seen {
for (z, (x, y)) in out[max_i + 1..].iter_mut().zip(xys) {
*z = x | y;
}
} else {
for (z, (x, y)) in out[max_i + 1..].iter_mut().zip(xys) {
*z = limbs_and_neg_neg_helper(x | y, &mut boundary_limb_seen);
}
}
let (xs, xs_len, ys_len) = if xs_len >= ys_len {
(xs, xs_len, ys_len)
} else {
(ys, ys_len, xs_len)
};
if xs_len != ys_len {
let zs = &xs[ys_len..];
if boundary_limb_seen {
out[ys_len..xs_len].copy_from_slice(zs);
} else {
for (z_out, &z_in) in out[ys_len..xs_len].iter_mut().zip(zs.iter()) {
*z_out = limbs_and_neg_neg_helper(z_in, &mut boundary_limb_seen);
}
}
}
boundary_limb_seen
}}
pub_test! {limbs_slice_and_neg_neg_in_place_left(xs: &mut [Limb], ys: &[Limb]) -> bool {
let xs_len = xs.len();
let ys_len = ys.len();
assert!(xs_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 x_i >= ys_len {
return true;
}
let max_i = max(x_i, y_i);
if y_i > x_i {
slice_set_zero(&mut xs[x_i..y_i]);
}
let x = if x_i >= y_i {
xs[max_i].wrapping_sub(1)
} else {
xs[max_i]
};
let y = if x_i <= y_i {
ys[max_i].wrapping_sub(1)
} else {
ys[max_i]
};
let mut boundary_limb_seen = false;
xs[max_i] = limbs_and_neg_neg_helper(x | y, &mut boundary_limb_seen);
let xys = xs[max_i + 1..].iter_mut().zip(ys[max_i + 1..].iter());
if boundary_limb_seen {
for (x, &y) in xys {
*x |= y;
}
} else {
for (x, &y) in xys {
*x = limbs_and_neg_neg_helper(*x | y, &mut boundary_limb_seen);
}
}
if xs_len > ys_len && !boundary_limb_seen {
for x in &mut xs[ys_len..] {
*x = limbs_and_neg_neg_helper(*x, &mut boundary_limb_seen);
}
}
boundary_limb_seen
}}
pub_test! {limbs_vec_and_neg_neg_in_place_left(xs: &mut Vec<Limb>, ys: &[Limb]) {
let xs_len = xs.len();
let ys_len = ys.len();
let y_i = slice_leading_zeros(ys);
assert!(y_i < ys_len);
if y_i >= xs_len {
xs.resize(ys_len, 0);
xs.copy_from_slice(ys);
return;
}
let boundary_limb_seen = if ys_len > xs_len {
let mut boundary_limb_seen = limbs_slice_and_neg_neg_in_place_left(xs, &ys[..xs_len]);
let zs = &ys[xs_len..];
if boundary_limb_seen {
xs.extend_from_slice(zs);
} else {
for &z in zs {
xs.push(limbs_and_neg_neg_helper(z, &mut boundary_limb_seen));
}
}
boundary_limb_seen
} else {
limbs_slice_and_neg_neg_in_place_left(xs, ys)
};
if !boundary_limb_seen {
xs.push(1);
}
}}
pub_test! {limbs_slice_and_neg_neg_in_place_either(
xs: &mut [Limb],
ys: &mut [Limb]
) -> (bool, bool) {
if xs.len() >= ys.len() {
(false, limbs_slice_and_neg_neg_in_place_left(xs, ys))
} else {
(true, limbs_slice_and_neg_neg_in_place_left(ys, xs))
}
}}
pub_test! {limbs_vec_and_neg_neg_in_place_either(xs: &mut Vec<Limb>, ys: &mut Vec<Limb>) -> bool {
if xs.len() >= ys.len() {
limbs_vec_and_neg_neg_in_place_left(xs, ys);
false
} else {
limbs_vec_and_neg_neg_in_place_left(ys, xs);
true
}
}}
impl Natural {
fn and_assign_pos_limb_neg(&mut self, other: Limb) {
match self {
Self(Small(small)) => *small &= other,
Self(Large(limbs)) => limbs_pos_and_limb_neg_in_place(limbs, other),
}
}
fn and_pos_limb_neg(&self, other: Limb) -> Self {
Self(match self {
Self(Small(small)) => Small(small & other),
Self(Large(limbs)) => Large(limbs_pos_and_limb_neg(limbs, other)),
})
}
fn and_assign_neg_limb_neg(&mut self, other: Limb) {
match self {
&mut Self::ZERO => {}
Self(Small(small)) => {
let result = small.wrapping_neg() & other;
if result == 0 {
*self = Self(Large(vec![0, 1]));
} else {
*small = result.wrapping_neg();
}
}
Self(Large(limbs)) => limbs_vec_neg_and_limb_neg_in_place(limbs, other),
}
}
fn and_assign_pos_neg(&mut self, other: &Self) {
match (&mut *self, other) {
(_, Self(Small(y))) => self.and_assign_pos_limb_neg(y.wrapping_neg()),
(Self(Small(x)), Self(Large(ys))) => *x &= ys[0].wrapping_neg(),
(Self(Large(xs)), Self(Large(ys))) => {
limbs_and_pos_neg_in_place_left(xs, ys);
self.trim();
}
}
}
fn and_assign_neg_pos(&mut self, mut other: Self) {
other.and_assign_pos_neg(self);
*self = other;
}
fn and_assign_neg_pos_ref(&mut self, other: &Self) {
match (&mut *self, other) {
(Self(Small(x)), y) => *self = y.and_pos_limb_neg(x.wrapping_neg()),
(Self(Large(xs)), Self(Small(y))) => {
*self = Self(Small(xs[0].wrapping_neg() & *y));
}
(Self(Large(xs)), Self(Large(ys))) => {
limbs_vec_and_pos_neg_in_place_right(ys, xs);
self.trim();
}
}
}
fn and_pos_neg(&self, other: &Self) -> Self {
match (self, other) {
(_, &Self(Small(y))) => self.and_pos_limb_neg(y.wrapping_neg()),
(Self(Small(x)), Self(Large(ys))) => Self(Small(x & ys[0].wrapping_neg())),
(Self(Large(xs)), Self(Large(ys))) => {
Self::from_owned_limbs_asc(limbs_and_pos_neg(xs, ys))
}
}
}
fn and_neg_limb_neg(&self, other: Limb) -> Self {
Self(match self {
Self(Small(small)) => {
let result = small.wrapping_neg() & other;
if result == 0 {
Large(vec![0, 1])
} else {
Small(result.wrapping_neg())
}
}
Self(Large(limbs)) => Large(limbs_neg_and_limb_neg(limbs, other)),
})
}
fn and_assign_neg_neg(&mut self, mut other: Self) {
match (&mut *self, &mut other) {
(Self(Small(x)), _) => *self = other.and_neg_limb_neg(x.wrapping_neg()),
(_, Self(Small(y))) => self.and_assign_neg_limb_neg(y.wrapping_neg()),
(Self(Large(xs)), Self(Large(ys))) => {
if limbs_vec_and_neg_neg_in_place_either(xs, ys) {
*self = other;
}
self.trim();
}
}
}
fn and_assign_neg_neg_ref(&mut self, other: &Self) {
match (&mut *self, other) {
(Self(Small(x)), _) => *self = other.and_neg_limb_neg(x.wrapping_neg()),
(_, Self(Small(y))) => self.and_assign_neg_limb_neg(y.wrapping_neg()),
(Self(Large(xs)), Self(Large(ys))) => {
limbs_vec_and_neg_neg_in_place_left(xs, ys);
self.trim();
}
}
}
fn and_neg_neg(&self, other: &Self) -> Self {
match (self, other) {
(_, &Self(Small(y))) => self.and_neg_limb_neg(y.wrapping_neg()),
(&Self(Small(x)), _) => other.and_neg_limb_neg(x.wrapping_neg()),
(Self(Large(xs)), Self(Large(ys))) => {
Self::from_owned_limbs_asc(limbs_and_neg_neg(xs, ys))
}
}
}
}
impl BitAnd<Self> for Integer {
type Output = Self;
#[inline]
fn bitand(mut self, other: Self) -> Self {
self &= other;
self
}
}
impl BitAnd<&Self> for Integer {
type Output = Self;
#[inline]
fn bitand(mut self, other: &Self) -> Self {
self &= other;
self
}
}
impl BitAnd<Integer> for &Integer {
type Output = Integer;
#[inline]
fn bitand(self, mut other: Integer) -> Integer {
other &= self;
other
}
}
impl BitAnd<&Integer> for &Integer {
type Output = Integer;
fn bitand(self, other: &Integer) -> Integer {
match (self.sign, other.sign) {
(true, true) => Integer {
sign: true,
abs: &self.abs & &other.abs,
},
(true, false) => Integer {
sign: true,
abs: self.abs.and_pos_neg(&other.abs),
},
(false, true) => Integer {
sign: true,
abs: other.abs.and_pos_neg(&self.abs),
},
(false, false) => Integer {
sign: false,
abs: self.abs.and_neg_neg(&other.abs),
},
}
}
}
impl BitAndAssign<Self> for Integer {
fn bitand_assign(&mut self, other: Self) {
match (self.sign, other.sign) {
(true, true) => self.abs.bitand_assign(other.abs),
(true, false) => self.abs.and_assign_pos_neg(&other.abs),
(false, true) => {
self.sign = true;
self.abs.and_assign_neg_pos(other.abs);
}
(false, false) => self.abs.and_assign_neg_neg(other.abs),
}
}
}
impl BitAndAssign<&Self> for Integer {
fn bitand_assign(&mut self, other: &Self) {
match (self.sign, other.sign) {
(true, true) => self.abs.bitand_assign(&other.abs),
(true, false) => self.abs.and_assign_pos_neg(&other.abs),
(false, true) => {
self.sign = true;
self.abs.and_assign_neg_pos_ref(&other.abs);
}
(false, false) => self.abs.and_assign_neg_neg_ref(&other.abs),
}
}
}