use crate::integer::Integer;
use crate::natural::InnerNatural::{Large, Small};
use crate::natural::Natural;
use crate::natural::arithmetic::add::{
limbs_add_limb, limbs_add_limb_to_out, limbs_slice_add_limb_in_place,
};
use crate::natural::arithmetic::sub::{
limbs_sub, limbs_sub_greater_in_place_left, limbs_sub_greater_to_out, limbs_sub_limb,
limbs_sub_limb_in_place, limbs_sub_limb_to_out, limbs_vec_sub_in_place_right,
};
use crate::natural::logic::not::limbs_not_in_place;
use crate::platform::Limb;
use alloc::vec::Vec;
use core::cmp::{Ordering::*, max};
use core::ops::{BitXor, BitXorAssign};
use itertools::repeat_n;
use malachite_base::num::arithmetic::traits::WrappingNegAssign;
use malachite_base::num::basic::traits::Zero;
use malachite_base::slices::{slice_leading_zeros, slice_set_zero, slice_test_zero};
pub_test! {limbs_neg_xor_limb(xs: &[Limb], y: Limb) -> Vec<Limb> {
if y == 0 {
return xs.to_vec();
}
let head = xs[0];
let tail = &xs[1..];
let mut out = Vec::with_capacity(xs.len());
if head != 0 {
let head = head.wrapping_neg() ^ y;
if head == 0 {
out.push(0);
out.extend_from_slice(&limbs_add_limb(tail, 1));
} else {
out.push(head.wrapping_neg());
out.extend_from_slice(tail);
}
} else {
out.push(y.wrapping_neg());
out.extend_from_slice(&limbs_sub_limb(tail, 1).0);
}
out
}}
pub_test! {limbs_neg_xor_limb_to_out(out: &mut [Limb], xs: &[Limb], y: Limb) -> bool {
let len = xs.len();
assert!(out.len() >= len);
if y == 0 {
out[..len].copy_from_slice(xs);
return false;
}
let head = xs[0];
let tail = &xs[1..];
if head != 0 {
let head = head.wrapping_neg() ^ y;
if head == 0 {
out[0] = 0;
limbs_add_limb_to_out(&mut out[1..len], tail, 1)
} else {
out[0] = head.wrapping_neg();
out[1..len].copy_from_slice(tail);
false
}
} else {
out[0] = y.wrapping_neg();
limbs_sub_limb_to_out(&mut out[1..len], tail, 1);
false
}
}}
pub_test! {limbs_slice_neg_xor_limb_in_place(xs: &mut [Limb], y: Limb) -> bool {
if y == 0 {
return false;
}
let (head, tail) = xs.split_at_mut(1);
let head = &mut head[0];
if *head != 0 {
*head = head.wrapping_neg() ^ y;
if *head == 0 {
limbs_slice_add_limb_in_place(tail, 1)
} else {
head.wrapping_neg_assign();
false
}
} else {
*head = y.wrapping_neg();
limbs_sub_limb_in_place(tail, 1);
false
}
}}
pub_test! {limbs_vec_neg_xor_limb_in_place(xs: &mut Vec<Limb>, y: Limb) {
if limbs_slice_neg_xor_limb_in_place(xs, y) {
xs.push(1);
}
}}
pub_test! {limbs_pos_xor_limb_neg(xs: &[Limb], y: Limb) -> Vec<Limb> {
let (head, tail) = xs.split_first().unwrap();
let lo = head ^ y;
let mut out;
if lo == 0 {
out = limbs_add_limb(tail, 1);
out.insert(0, 0);
} else {
out = xs.to_vec();
out[0] = lo.wrapping_neg();
}
out
}}
pub_test! {limbs_pos_xor_limb_neg_to_out(out: &mut [Limb], xs: &[Limb], y: Limb) -> bool {
let (head, tail) = xs.split_first().unwrap();
let (out_head, out_tail) = out[..xs.len()].split_first_mut().unwrap();
let lo = head ^ y;
if lo == 0 {
*out_head = 0;
limbs_add_limb_to_out(out_tail, tail, 1)
} else {
*out_head = lo.wrapping_neg();
out_tail.copy_from_slice(tail);
false
}
}}
pub_test! {limbs_slice_pos_xor_limb_neg_in_place(xs: &mut [Limb], y: Limb) -> bool {
let (head, tail) = xs.split_at_mut(1);
let head = &mut head[0];
*head ^= y;
if *head == 0 {
limbs_slice_add_limb_in_place(tail, 1)
} else {
*head = head.wrapping_neg();
false
}
}}
pub_test! {limbs_vec_pos_xor_limb_neg_in_place(xs: &mut Vec<Limb>, y: Limb) {
if limbs_slice_pos_xor_limb_neg_in_place(xs, y) {
xs.push(1);
}
}}
pub_test! {limbs_neg_xor_limb_neg(xs: &[Limb], y: Limb) -> Vec<Limb> {
let mut out;
if xs[0] == 0 {
let carry;
(out, carry) = limbs_sub_limb(xs, 1);
assert!(!carry);
out[0] = y;
} else {
out = xs.to_vec();
out[0] = xs[0].wrapping_neg() ^ y;
}
out
}}
pub_test! {limbs_neg_xor_limb_neg_to_out(out: &mut [Limb], xs: &[Limb], y: Limb) {
let (head, tail) = xs.split_first().unwrap();
let (out_head, out_tail) = out[..xs.len()].split_first_mut().unwrap();
if *head == 0 {
*out_head = y;
assert!(!limbs_sub_limb_to_out(out_tail, tail, 1));
} else {
*out_head = xs[0].wrapping_neg() ^ y;
out_tail.copy_from_slice(tail);
}
}}
pub_test! {limbs_neg_xor_limb_neg_in_place(xs: &mut [Limb], y: Limb) {
let (head, tail) = xs.split_first_mut().unwrap();
if *head == 0 {
assert!(!limbs_sub_limb_in_place(tail, 1));
*head = y;
} else {
head.wrapping_neg_assign();
*head ^= y;
}
}}
const fn limbs_xor_pos_neg_helper(x: Limb, boundary_seen: &mut bool) -> Limb {
if *boundary_seen {
!x
} else if x == 0 {
0
} else {
*boundary_seen = true;
x.wrapping_neg()
}
}
pub_test! {limbs_xor_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..]);
return out;
} else if x_i >= ys_len {
let mut out = ys.to_vec();
out.extend_from_slice(&xs[ys_len..]);
return out;
}
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 mut boundary_seen = false;
let x = match x_i.cmp(&y_i) {
Equal => {
limbs_xor_pos_neg_helper(xs[x_i] ^ ys[y_i].wrapping_neg(), &mut boundary_seen)
}
Less => {
boundary_seen = true;
out.push(xs[x_i].wrapping_neg());
out.extend(xs[x_i + 1..y_i].iter().map(|x| !x));
xs[y_i] ^ (ys[y_i] - 1)
}
Greater => {
boundary_seen = true;
out.extend_from_slice(&ys[y_i..x_i]);
xs[x_i] ^ ys[x_i]
}
};
out.push(x);
let xys = xs[max_i + 1..].iter().zip(ys[max_i + 1..].iter());
if boundary_seen {
out.extend(xys.map(|(x, y)| x ^ y));
} else {
for (&x, &y) in xys {
out.push(limbs_xor_pos_neg_helper(x ^ !y, &mut boundary_seen));
}
}
if xs_len != ys_len {
let zs = if xs_len > ys_len {
&xs[ys_len..]
} else {
&ys[xs_len..]
};
if boundary_seen {
out.extend_from_slice(zs);
} else {
for &z in zs {
out.push(limbs_xor_pos_neg_helper(!z, &mut boundary_seen));
}
}
}
if slice_test_zero(&out) {
out.push(1);
}
out
}}
pub_test! {limbs_xor_pos_neg_to_out(out: &mut [Limb], xs: &[Limb], ys: &[Limb]) -> bool {
let xs_len = xs.len();
let ys_len = ys.len();
assert!(out.len() >= xs_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();
for (out, &x) in out[x_i + 1..xs_len].iter_mut().zip(xs[x_i + 1..].iter()) {
*out = !x;
}
for out in &mut out[xs_len..y_i] {
*out = Limb::MAX;
}
out[y_i] = ys[y_i] - 1;
out[y_i + 1..ys_len].copy_from_slice(&ys[y_i + 1..]);
return false;
} else if x_i >= ys_len {
out[..ys_len].copy_from_slice(ys);
out[ys_len..xs_len].copy_from_slice(&xs[ys_len..]);
return false;
}
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 mut boundary_seen = false;
match x_i.cmp(&y_i) {
Equal => {
out[x_i] =
limbs_xor_pos_neg_helper(xs[x_i] ^ ys[y_i].wrapping_neg(), &mut boundary_seen);
}
Less => {
boundary_seen = true;
out[x_i] = xs[x_i].wrapping_neg();
for (out, &x) in out[x_i + 1..y_i].iter_mut().zip(xs[x_i + 1..y_i].iter()) {
*out = !x;
}
out[y_i] = xs[y_i] ^ (ys[y_i] - 1);
}
Greater => {
boundary_seen = true;
out[y_i..x_i].copy_from_slice(&ys[y_i..x_i]);
out[x_i] = xs[x_i] ^ ys[x_i];
}
}
let xys = out[max_i + 1..]
.iter_mut()
.zip(xs[max_i + 1..].iter().zip(ys[max_i + 1..].iter()));
if boundary_seen {
for (out, (&x, &y)) in xys {
*out = x ^ y;
}
} else {
for (out, (&x, &y)) in xys {
*out = limbs_xor_pos_neg_helper(x ^ !y, &mut boundary_seen);
}
}
let max_len = max(xs_len, ys_len);
if xs_len != ys_len {
let (min_len, zs) = if max_len == xs_len {
(ys_len, &xs[ys_len..])
} else {
(xs_len, &ys[xs_len..])
};
if boundary_seen {
out[min_len..max_len].copy_from_slice(zs);
} else {
for (out, &z) in out[min_len..].iter_mut().zip(zs.iter()) {
*out = limbs_xor_pos_neg_helper(!z, &mut boundary_seen);
}
}
}
slice_test_zero(&out[..max_len])
}}
fn limbs_xor_pos_neg_in_place_left_helper(
xs: &mut [Limb],
ys: &[Limb],
x_i: usize,
y_i: usize,
) -> bool {
let max_i = max(x_i, y_i);
let mut boundary_seen = false;
match x_i.cmp(&y_i) {
Equal => {
xs[x_i] =
limbs_xor_pos_neg_helper(xs[x_i] ^ ys[y_i].wrapping_neg(), &mut boundary_seen);
}
Less => {
boundary_seen = true;
xs[x_i].wrapping_neg_assign();
limbs_not_in_place(&mut xs[x_i + 1..y_i]);
xs[y_i] ^= ys[y_i] - 1;
}
Greater => {
boundary_seen = true;
xs[y_i..x_i].copy_from_slice(&ys[y_i..x_i]);
xs[x_i] ^= ys[x_i];
}
}
let xys = xs[max_i + 1..].iter_mut().zip(ys[max_i + 1..].iter());
if boundary_seen {
for (x, &y) in xys {
*x ^= y;
}
} else {
for (x, &y) in xys {
*x = limbs_xor_pos_neg_helper(*x ^ !y, &mut boundary_seen);
}
}
boundary_seen
}
pub_test! {limbs_xor_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..]);
return;
} else if x_i >= ys_len {
xs[..ys_len].copy_from_slice(ys);
return;
}
let mut boundary_seen = limbs_xor_pos_neg_in_place_left_helper(xs, ys, x_i, y_i);
match xs_len.cmp(&ys_len) {
Less => {
if boundary_seen {
xs.extend_from_slice(&ys[xs_len..]);
} else {
for &y in &ys[xs_len..] {
xs.push(limbs_xor_pos_neg_helper(!y, &mut boundary_seen));
}
}
}
Greater if !boundary_seen => {
for x in &mut xs[ys_len..] {
*x = limbs_xor_pos_neg_helper(!*x, &mut boundary_seen);
}
}
_ => {}
}
if slice_test_zero(xs) {
xs.push(1);
}
}}
fn limbs_xor_pos_neg_in_place_right_helper(
xs: &[Limb],
ys: &mut [Limb],
x_i: usize,
y_i: usize,
) -> bool {
let max_i = max(x_i, y_i);
let mut boundary_seen = false;
match x_i.cmp(&y_i) {
Equal => {
ys[y_i] =
limbs_xor_pos_neg_helper(xs[x_i] ^ ys[y_i].wrapping_neg(), &mut boundary_seen);
}
Less => {
boundary_seen = true;
ys[x_i] = xs[x_i].wrapping_neg();
for (y, &x) in ys[x_i + 1..].iter_mut().zip(xs[x_i + 1..y_i].iter()) {
*y = !x;
}
ys[y_i] -= 1;
ys[y_i] ^= xs[y_i];
}
Greater => {
boundary_seen = true;
ys[x_i] ^= xs[x_i];
}
}
let xys = xs[max_i + 1..].iter().zip(ys[max_i + 1..].iter_mut());
if boundary_seen {
for (&x, y) in xys {
*y ^= x;
}
} else {
for (&x, y) in xys {
*y = limbs_xor_pos_neg_helper(x ^ !*y, &mut boundary_seen);
}
}
boundary_seen
}
pub_test! {limbs_xor_pos_neg_in_place_right(xs: &[Limb], ys: &mut 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 {
ys[x_i] = xs[x_i].wrapping_neg();
for (y, &x) in ys[x_i + 1..].iter_mut().zip(xs[x_i + 1..].iter()) {
*y = !x;
}
for y in ys.iter_mut().take(y_i).skip(xs_len) {
*y = Limb::MAX;
}
ys[y_i] -= 1;
return;
} else if x_i >= ys_len {
ys.extend_from_slice(&xs[ys_len..]);
return;
}
let mut boundary_seen = limbs_xor_pos_neg_in_place_right_helper(xs, ys, x_i, y_i);
if xs_len > ys_len {
if boundary_seen {
ys.extend_from_slice(&xs[ys_len..]);
} else {
for &x in &xs[ys_len..] {
ys.push(limbs_xor_pos_neg_helper(!x, &mut boundary_seen));
}
}
} else if xs_len < ys_len && !boundary_seen {
for y in &mut ys[xs_len..] {
*y = limbs_xor_pos_neg_helper(!*y, &mut boundary_seen);
}
}
if slice_test_zero(ys) {
ys.push(1);
}
}}
pub_test! {limbs_xor_pos_neg_in_place_either(xs: &mut Vec<Limb>, ys: &mut Vec<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 {
ys[x_i] = xs[x_i].wrapping_neg();
for (y, &x) in ys[x_i + 1..].iter_mut().zip(xs[x_i + 1..].iter()) {
*y = !x;
}
for y in &mut ys[xs_len..y_i] {
*y = Limb::MAX;
}
ys[y_i] -= 1;
return true;
} else if x_i >= ys_len {
xs[..ys_len].copy_from_slice(ys);
return false;
}
if xs_len >= ys_len {
let mut boundary_seen = limbs_xor_pos_neg_in_place_left_helper(xs, ys, x_i, y_i);
if xs_len != ys_len && !boundary_seen {
for x in &mut xs[ys_len..] {
*x = limbs_xor_pos_neg_helper(!*x, &mut boundary_seen);
}
}
if slice_test_zero(xs) {
xs.push(1);
}
false
} else {
let mut boundary_seen = limbs_xor_pos_neg_in_place_right_helper(xs, ys, x_i, y_i);
if !boundary_seen {
for y in &mut ys[xs_len..] {
*y = limbs_xor_pos_neg_helper(!*y, &mut boundary_seen);
}
}
if slice_test_zero(ys) {
ys.push(1);
}
true
}
}}
pub_test! {limbs_xor_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 {
let (result, borrow) = limbs_sub(ys, xs);
assert!(!borrow);
return result;
} else if x_i >= ys_len {
let (result, borrow) = limbs_sub(xs, ys);
assert!(!borrow);
return result;
}
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];
if x_i == y_i {
out.push(xs[x_i].wrapping_neg() ^ ys[x_i].wrapping_neg());
} else {
let (min_zs, max_zs) = if x_i <= y_i { (xs, ys) } else { (ys, xs) };
out.push(min_zs[min_i].wrapping_neg());
out.extend(min_zs[min_i + 1..max_i].iter().map(|z| !z));
out.push((max_zs[max_i] - 1) ^ min_zs[max_i]);
}
out.extend(
xs[max_i + 1..]
.iter()
.zip(ys[max_i + 1..].iter())
.map(|(x, y)| x ^ y),
);
match xs_len.cmp(&ys_len) {
Less => out.extend_from_slice(&ys[xs_len..]),
Greater => out.extend_from_slice(&xs[ys_len..]),
_ => {}
}
out
}}
pub_test! {limbs_xor_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);
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 {
assert!(!limbs_sub_greater_to_out(out, ys, xs));
return;
} else if x_i >= ys_len {
assert!(!limbs_sub_greater_to_out(out, xs, ys));
return;
}
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]);
if x_i == y_i {
out[x_i] = xs[x_i].wrapping_neg() ^ ys[x_i].wrapping_neg();
} else {
let (min_zs, max_zs) = if x_i <= y_i { (xs, ys) } else { (ys, xs) };
out[min_i] = min_zs[min_i].wrapping_neg();
for (out, &z) in out[min_i + 1..max_i]
.iter_mut()
.zip(min_zs[min_i + 1..max_i].iter())
{
*out = !z;
}
out[max_i] = (max_zs[max_i] - 1) ^ min_zs[max_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;
}
match xs_len.cmp(&ys_len) {
Less => out[xs_len..ys_len].copy_from_slice(&ys[xs_len..]),
Greater => out[ys_len..xs_len].copy_from_slice(&xs[ys_len..]),
_ => {}
}
}}
fn limbs_xor_neg_neg_in_place_helper(xs: &mut [Limb], ys: &[Limb], x_i: usize, y_i: usize) {
let (min_i, max_i) = if x_i <= y_i { (x_i, y_i) } else { (y_i, x_i) };
if x_i == y_i {
xs[x_i] = xs[x_i].wrapping_neg() ^ ys[x_i].wrapping_neg();
} else if x_i <= y_i {
xs[min_i].wrapping_neg_assign();
limbs_not_in_place(&mut xs[min_i + 1..max_i]);
xs[max_i] ^= ys[max_i] - 1;
} else {
xs[min_i] = ys[min_i].wrapping_neg();
for (x, &y) in xs[min_i + 1..max_i].iter_mut().zip(ys[min_i + 1..].iter()) {
*x = !y;
}
xs[max_i] -= 1;
xs[max_i] ^= ys[max_i];
}
for (x, &y) in xs[max_i + 1..].iter_mut().zip(ys[max_i + 1..].iter()) {
*x ^= y;
}
}
pub_test! {limbs_xor_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 {
assert!(!limbs_vec_sub_in_place_right(ys, xs));
} else if x_i >= ys_len {
assert!(!limbs_sub_greater_in_place_left(xs, ys));
} else {
limbs_xor_neg_neg_in_place_helper(xs, ys, x_i, y_i);
if xs_len < ys_len {
xs.extend_from_slice(&ys[xs_len..]);
}
}
}}
pub_test! {limbs_xor_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 {
assert!(!limbs_sub_greater_in_place_left(ys, xs));
true
} else if x_i >= ys_len {
assert!(!limbs_sub_greater_in_place_left(xs, ys));
false
} else if xs_len >= ys_len {
limbs_xor_neg_neg_in_place_helper(xs, ys, x_i, y_i);
false
} else {
limbs_xor_neg_neg_in_place_helper(ys, xs, y_i, x_i);
true
}
}}
impl Natural {
fn xor_assign_neg_limb_pos(&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_xor_limb_in_place(limbs, other);
self.trim();
}
}
}
fn xor_neg_limb_pos(&self, other: Limb) -> Self {
match self {
&Self::ZERO => self.clone(),
Self(Small(small)) => {
let result = small.wrapping_neg() ^ other;
Self(if result == 0 {
Large(vec![0, 1])
} else {
Small(result.wrapping_neg())
})
}
Self(Large(limbs)) => Self::from_owned_limbs_asc(limbs_neg_xor_limb(limbs, other)),
}
}
fn xor_assign_pos_limb_neg(&mut self, other: Limb) {
match self {
Self(Small(small)) => {
let result = *small ^ other;
if result == 0 {
*self = Self(Large(vec![0, 1]));
} else {
*small = result.wrapping_neg();
}
}
Self(Large(limbs)) => {
limbs_vec_pos_xor_limb_neg_in_place(limbs, other);
self.trim();
}
}
}
fn xor_pos_limb_neg(&self, other: Limb) -> Self {
Self(match self {
Self(Small(small)) => {
let result = small ^ other;
if result == 0 {
Large(vec![0, 1])
} else {
Small(result.wrapping_neg())
}
}
Self(Large(limbs)) => Large(limbs_pos_xor_limb_neg(limbs, other)),
})
}
fn xor_assign_neg_limb_neg(&mut self, other: Limb) {
match &mut *self {
Self(Small(small)) => *small = small.wrapping_neg() ^ other,
Self(Large(limbs)) => {
limbs_neg_xor_limb_neg_in_place(limbs, other);
self.trim();
}
}
}
fn xor_neg_limb_neg(&self, other: Limb) -> Self {
match self {
Self(Small(small)) => Self(Small(small.wrapping_neg() ^ other)),
Self(Large(limbs)) => Self::from_owned_limbs_asc(limbs_neg_xor_limb_neg(limbs, other)),
}
}
fn xor_assign_pos_neg(&mut self, mut other: Self) {
match (&mut *self, &mut other) {
(Self(Small(x)), _) => {
other.xor_assign_neg_limb_pos(*x);
*self = other;
}
(_, Self(Small(y))) => self.xor_assign_pos_limb_neg(y.wrapping_neg()),
(Self(Large(xs)), Self(Large(ys))) => {
if limbs_xor_pos_neg_in_place_either(xs, ys) {
*self = other;
}
self.trim();
}
}
}
fn xor_assign_pos_neg_ref(&mut self, other: &Self) {
match (&mut *self, other) {
(Self(Small(x)), _) => *self = other.xor_neg_limb_pos(*x),
(_, Self(Small(y))) => self.xor_assign_pos_limb_neg(y.wrapping_neg()),
(Self(Large(xs)), Self(Large(ys))) => {
limbs_xor_pos_neg_in_place_left(xs, ys);
self.trim();
}
}
}
fn xor_assign_neg_pos(&mut self, mut other: Self) {
other.xor_assign_pos_neg_ref(&*self);
*self = other;
}
fn xor_assign_neg_pos_ref(&mut self, other: &Self) {
match (&mut *self, other) {
(Self(Small(x)), _) => *self = other.xor_pos_limb_neg(x.wrapping_neg()),
(_, Self(Small(y))) => self.xor_assign_neg_limb_pos(*y),
(Self(Large(xs)), Self(Large(ys))) => {
limbs_xor_pos_neg_in_place_right(ys, xs);
self.trim();
}
}
}
fn xor_pos_neg(&self, other: &Self) -> Self {
match (self, other) {
(&Self(Small(x)), _) => other.xor_neg_limb_pos(x),
(_, &Self(Small(y))) => self.xor_pos_limb_neg(y.wrapping_neg()),
(Self(Large(xs)), Self(Large(ys))) => {
Self::from_owned_limbs_asc(limbs_xor_pos_neg(xs, ys))
}
}
}
fn xor_assign_neg_neg(&mut self, mut other: Self) {
match (&mut *self, &mut other) {
(Self(Small(x)), _) => *self = other.xor_neg_limb_neg(x.wrapping_neg()),
(_, Self(Small(y))) => self.xor_assign_neg_limb_neg(y.wrapping_neg()),
(Self(Large(xs)), Self(Large(ys))) => {
if limbs_xor_neg_neg_in_place_either(xs, ys) {
*self = other;
}
self.trim();
}
}
}
fn xor_assign_neg_neg_ref(&mut self, other: &Self) {
match (&mut *self, other) {
(Self(Small(x)), _) => *self = other.xor_neg_limb_neg(x.wrapping_neg()),
(_, Self(Small(y))) => self.xor_assign_neg_limb_neg(y.wrapping_neg()),
(Self(Large(xs)), Self(Large(ys))) => {
limbs_xor_neg_neg_in_place_left(xs, ys);
self.trim();
}
}
}
fn xor_neg_neg(&self, other: &Self) -> Self {
match (self, other) {
(&Self(Small(x)), _) => other.xor_neg_limb_neg(x.wrapping_neg()),
(_, &Self(Small(y))) => self.xor_neg_limb_neg(y.wrapping_neg()),
(Self(Large(xs)), Self(Large(ys))) => {
Self::from_owned_limbs_asc(limbs_xor_neg_neg(xs, ys))
}
}
}
}
impl BitXor<Self> for Integer {
type Output = Self;
#[inline]
fn bitxor(mut self, other: Self) -> Self {
self ^= other;
self
}
}
impl BitXor<&Self> for Integer {
type Output = Self;
#[inline]
fn bitxor(mut self, other: &Self) -> Self {
self ^= other;
self
}
}
impl BitXor<Integer> for &Integer {
type Output = Integer;
#[inline]
fn bitxor(self, mut other: Integer) -> Integer {
other ^= self;
other
}
}
impl BitXor<&Integer> for &Integer {
type Output = Integer;
fn bitxor(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.xor_pos_neg(&other.abs),
},
(false, true) => Integer {
sign: false,
abs: other.abs.xor_pos_neg(&self.abs),
},
(false, false) => Integer {
sign: true,
abs: self.abs.xor_neg_neg(&other.abs),
},
}
}
}
impl BitXorAssign<Self> for Integer {
fn bitxor_assign(&mut self, other: Self) {
match (self.sign, other.sign) {
(true, true) => self.abs.bitxor_assign(other.abs),
(true, false) => {
self.sign = false;
self.abs.xor_assign_pos_neg(other.abs);
}
(false, true) => self.abs.xor_assign_neg_pos(other.abs),
(false, false) => {
self.sign = true;
self.abs.xor_assign_neg_neg(other.abs);
}
}
}
}
impl BitXorAssign<&Self> for Integer {
fn bitxor_assign(&mut self, other: &Self) {
match (self.sign, other.sign) {
(true, true) => self.abs.bitxor_assign(&other.abs),
(true, false) => {
self.sign = false;
self.abs.xor_assign_pos_neg_ref(&other.abs);
}
(false, true) => self.abs.xor_assign_neg_pos_ref(&other.abs),
(false, false) => {
self.sign = true;
self.abs.xor_assign_neg_neg_ref(&other.abs);
}
}
}
}