use crate::integer::Integer;
use crate::natural::InnerNatural::{Large, Small};
use crate::natural::logic::bit_scan::{
limbs_index_of_next_false_bit, limbs_index_of_next_true_bit,
};
use crate::natural::{Natural, bit_to_limb_count_floor, limb_to_bit_count};
use crate::platform::Limb;
use core::cmp::Ordering::*;
use malachite_base::num::basic::integers::PrimitiveInt;
use malachite_base::num::logic::traits::{BitScan, LowMask, TrailingZeros};
use malachite_base::slices::slice_leading_zeros;
pub_test! {limbs_index_of_next_false_bit_neg(xs: &[Limb], mut starting_index: u64) -> Option<u64> {
let n = xs.len();
let i = slice_leading_zeros(xs);
assert!(i < n);
let starting_limb_index = bit_to_limb_count_floor(starting_index);
if starting_limb_index >= n {
return None;
}
let after_boundary_offset = limb_to_bit_count(i + 1);
match starting_limb_index.cmp(&i) {
Equal => {
let within_limb_index = starting_index & Limb::WIDTH_MASK;
if let Some(result) = xs[i]
.wrapping_neg()
.index_of_next_false_bit(within_limb_index)
{
if result < Limb::WIDTH {
return Some(limb_to_bit_count(i) + result);
}
starting_index = 0;
}
}
Less => {
return Some(starting_index);
}
Greater => {
starting_index -= after_boundary_offset;
}
}
limbs_index_of_next_true_bit(&xs[i + 1..], starting_index)
.map(|result| result + after_boundary_offset)
}}
pub_test! {limbs_index_of_next_true_bit_neg(xs: &[Limb], mut starting_index: u64) -> u64 {
let n = xs.len();
let i = slice_leading_zeros(xs);
assert!(i < n);
let mut starting_limb_index = bit_to_limb_count_floor(starting_index);
if starting_limb_index >= n {
return starting_index;
}
let after_boundary_offset = limb_to_bit_count(i + 1);
if starting_limb_index < i {
starting_index = limb_to_bit_count(i);
starting_limb_index = i;
}
if starting_limb_index == i {
let within_limb_index = starting_index & Limb::WIDTH_MASK;
if let Some(result) = xs[i]
.wrapping_neg()
.index_of_next_true_bit(within_limb_index)
{
return limb_to_bit_count(i) + result;
}
starting_index = 0;
} else {
starting_index -= after_boundary_offset;
}
limbs_index_of_next_false_bit(&xs[i + 1..], starting_index) + after_boundary_offset
}}
impl Natural {
fn index_of_next_false_bit_neg(&self, starting_index: u64) -> Option<u64> {
match self {
Self(Small(small)) => {
if starting_index >= Limb::WIDTH {
None
} else {
let index = TrailingZeros::trailing_zeros(
(small - 1) & !Limb::low_mask(starting_index),
);
if index == Limb::WIDTH {
None
} else {
Some(index)
}
}
}
Self(Large(limbs)) => limbs_index_of_next_false_bit_neg(limbs, starting_index),
}
}
fn index_of_next_true_bit_neg(&self, starting_index: u64) -> u64 {
match self {
Self(Small(small)) => {
if starting_index >= Limb::WIDTH {
starting_index
} else {
TrailingZeros::trailing_zeros(!((small - 1) | Limb::low_mask(starting_index)))
}
}
Self(Large(limbs)) => limbs_index_of_next_true_bit_neg(limbs, starting_index),
}
}
}
impl BitScan for &Integer {
fn index_of_next_false_bit(self, starting_index: u64) -> Option<u64> {
if self.sign {
self.abs.index_of_next_false_bit(starting_index)
} else {
self.abs.index_of_next_false_bit_neg(starting_index)
}
}
fn index_of_next_true_bit(self, starting_index: u64) -> Option<u64> {
if self.sign {
self.abs.index_of_next_true_bit(starting_index)
} else {
Some(self.abs.index_of_next_true_bit_neg(starting_index))
}
}
}