use crate::integer::Integer;
use crate::natural::InnerNatural::{Large, Small};
use crate::natural::arithmetic::add::limbs_slice_add_limb_in_place;
use crate::natural::arithmetic::sub::limbs_sub_limb_in_place;
use crate::natural::{Natural, bit_to_limb_count_floor};
use crate::platform::Limb;
use alloc::vec::Vec;
use core::cmp::Ordering::*;
use malachite_base::num::arithmetic::traits::{PowerOf2, WrappingAddAssign, WrappingNegAssign};
use malachite_base::num::basic::integers::PrimitiveInt;
use malachite_base::num::logic::traits::BitAccess;
use malachite_base::slices::{slice_leading_zeros, slice_test_zero};
pub_test! {limbs_get_bit_neg(xs: &[Limb], index: u64) -> bool {
let x_i = bit_to_limb_count_floor(index);
if x_i >= xs.len() {
true
} else {
let x = if slice_test_zero(&xs[..x_i]) {
xs[x_i].wrapping_neg()
} else {
!xs[x_i]
};
x.get_bit(index & Limb::WIDTH_MASK)
}
}}
pub_test! {limbs_set_bit_neg(xs: &mut [Limb], index: u64) {
let x_i = bit_to_limb_count_floor(index);
if x_i >= xs.len() {
return;
}
let reduced_index = index & Limb::WIDTH_MASK;
let zero_bound = slice_leading_zeros(xs);
match x_i.cmp(&zero_bound) {
Equal => {
let boundary = &mut xs[x_i];
*boundary -= 1;
boundary.clear_bit(reduced_index);
*boundary += 1;
}
Less => {
assert!(!limbs_sub_limb_in_place(
&mut xs[x_i..],
Limb::power_of_2(reduced_index),
));
}
Greater => {
xs[x_i].clear_bit(reduced_index);
}
}
}}
fn limbs_clear_bit_neg_helper(xs: &mut [Limb], x_i: usize, reduced_index: u64) -> bool {
let zero_bound = slice_leading_zeros(xs);
match x_i.cmp(&zero_bound) {
Equal => {
let mut boundary = xs[x_i] - 1;
boundary.set_bit(reduced_index);
boundary.wrapping_add_assign(1);
xs[x_i] = boundary;
boundary == 0 && limbs_slice_add_limb_in_place(&mut xs[x_i + 1..], 1)
}
Greater => {
xs[x_i].set_bit(reduced_index);
false
}
_ => false,
}
}
pub fn limbs_slice_clear_bit_neg(xs: &mut [Limb], index: u64) {
let x_i = bit_to_limb_count_floor(index);
let reduced_index = index & Limb::WIDTH_MASK;
assert!(
x_i < xs.len() && !limbs_clear_bit_neg_helper(xs, x_i, reduced_index),
"Setting bit cannot be done within existing slice"
);
}
pub_test! {limbs_vec_clear_bit_neg(xs: &mut Vec<Limb>, index: u64) {
let x_i = bit_to_limb_count_floor(index);
let reduced_index = index & Limb::WIDTH_MASK;
if x_i < xs.len() {
if limbs_clear_bit_neg_helper(xs, x_i, reduced_index) {
xs.push(1);
}
} else {
xs.resize(x_i, 0);
xs.push(Limb::power_of_2(reduced_index));
}
}}
impl Natural {
pub(crate) fn get_bit_neg(&self, index: u64) -> bool {
match self {
Self(Small(small)) => index >= Limb::WIDTH || small.wrapping_neg().get_bit(index),
Self(Large(limbs)) => limbs_get_bit_neg(limbs, index),
}
}
fn set_bit_neg(&mut self, index: u64) {
match self {
Self(Small(small)) => {
if index < Limb::WIDTH {
small.wrapping_neg_assign();
small.set_bit(index);
small.wrapping_neg_assign();
}
}
Self(Large(limbs)) => {
limbs_set_bit_neg(limbs, index);
self.trim();
}
}
}
fn clear_bit_neg(&mut self, index: u64) {
match self {
Self(Small(small)) if index < Limb::WIDTH => {
let mut cleared_small = small.wrapping_neg();
cleared_small.clear_bit(index);
if cleared_small == 0 {
*self = Self(Large(vec![0, 1]));
} else {
*small = cleared_small.wrapping_neg();
}
}
Self(Small(_)) => {
let limbs = self.promote_in_place();
limbs_vec_clear_bit_neg(limbs, index);
}
Self(Large(limbs)) => {
limbs_vec_clear_bit_neg(limbs, index);
}
}
}
}
impl BitAccess for Integer {
fn get_bit(&self, index: u64) -> bool {
match self {
Self { sign: true, abs } => abs.get_bit(index),
Self { sign: false, abs } => abs.get_bit_neg(index),
}
}
fn set_bit(&mut self, index: u64) {
match self {
Self { sign: true, abs } => abs.set_bit(index),
Self { sign: false, abs } => abs.set_bit_neg(index),
}
}
fn clear_bit(&mut self, index: u64) {
match self {
Self { sign: true, abs } => abs.clear_bit(index),
Self { sign: false, abs } => abs.clear_bit_neg(index),
}
}
}