use crate::integer::Integer;
use crate::natural::InnerNatural::{Large, Small};
use crate::natural::arithmetic::divisible_by_power_of_2::limbs_divisible_by_power_of_2;
use crate::natural::{Natural, bit_to_limb_count_floor};
use crate::platform::Limb;
use core::cmp::Ordering::*;
use malachite_base::num::arithmetic::traits::EqModPowerOf2;
use malachite_base::num::basic::integers::PrimitiveInt;
pub_test! {limbs_eq_mod_power_of_2_neg_limb(xs: &[Limb], y: Limb, pow: u64) -> bool {
if y == 0 {
return limbs_divisible_by_power_of_2(xs, pow);
}
let i = bit_to_limb_count_floor(pow);
match i.cmp(&xs.len()) {
Greater => false,
Equal => {
if pow & Limb::WIDTH_MASK == 0 {
let mut carry = y;
for &x in xs {
let sum = x.wrapping_add(carry);
if sum != 0 {
return false;
}
carry = 1;
}
true
} else {
false
}
}
Less => {
if i == 0 {
xs[0].eq_mod_power_of_2(y.wrapping_neg(), pow)
} else {
xs[0] == y.wrapping_neg()
&& xs[1..i].iter().all(|&x| x == Limb::MAX)
&& xs[i].eq_mod_power_of_2(Limb::MAX, pow & Limb::WIDTH_MASK)
}
}
}
}}
fn limbs_eq_mod_power_of_2_neg_pos_greater(xs: &[Limb], ys: &[Limb], pow: u64) -> bool {
let xs_len = xs.len();
let i = bit_to_limb_count_floor(pow);
let small_pow = pow & Limb::WIDTH_MASK;
if i > xs_len || i == xs_len && small_pow != 0 {
false
} else {
let ys_len = ys.len();
let mut y_nonzero_seen = false;
for j in 0..i {
let y = if j >= ys_len {
Limb::MAX
} else if y_nonzero_seen {
!ys[j]
} else if ys[j] == 0 {
0
} else {
y_nonzero_seen = true;
ys[j].wrapping_neg()
};
if xs[j] != y {
return false;
}
}
if small_pow == 0 {
true
} else {
let y = if i >= ys_len {
Limb::MAX
} else if y_nonzero_seen {
!ys[i]
} else {
ys[i].wrapping_neg()
};
xs[i].eq_mod_power_of_2(y, small_pow)
}
}
}
pub_test! {limbs_eq_mod_power_of_2_neg_pos(xs: &[Limb], ys: &[Limb], pow: u64) -> bool {
if xs.len() >= ys.len() {
limbs_eq_mod_power_of_2_neg_pos_greater(xs, ys, pow)
} else {
limbs_eq_mod_power_of_2_neg_pos_greater(ys, xs, pow)
}
}}
impl Natural {
fn eq_mod_power_of_2_neg_limb(&self, other: Limb, pow: u64) -> bool {
match self {
Self(Small(small)) => {
pow <= Limb::WIDTH && small.wrapping_neg().eq_mod_power_of_2(other, pow)
}
Self(Large(limbs)) => limbs_eq_mod_power_of_2_neg_limb(limbs, other, pow),
}
}
fn eq_mod_power_of_2_neg_pos(&self, other: &Self, pow: u64) -> bool {
match (self, other) {
(_, &Self(Small(y))) => self.eq_mod_power_of_2_neg_limb(y, pow),
(&Self(Small(x)), _) => other.eq_mod_power_of_2_neg_limb(x, pow),
(Self(Large(xs)), Self(Large(ys))) => limbs_eq_mod_power_of_2_neg_pos(xs, ys, pow),
}
}
}
impl EqModPowerOf2<&Integer> for &Integer {
fn eq_mod_power_of_2(self, other: &Integer, pow: u64) -> bool {
if self.sign == other.sign {
self.abs.eq_mod_power_of_2(&other.abs, pow)
} else {
self.abs.eq_mod_power_of_2_neg_pos(&other.abs, pow)
}
}
}