use crate::integer::Integer;
use crate::natural::Natural;
use crate::natural::arithmetic::add::limbs_slice_add_limb_in_place;
use crate::natural::conversion::to_limbs::LimbIterator;
use crate::natural::logic::not::limbs_not_in_place;
use crate::platform::Limb;
use alloc::vec::Vec;
use malachite_base::num::arithmetic::traits::{IsPowerOf2, UnsignedAbs};
use malachite_base::num::basic::integers::PrimitiveInt;
use malachite_base::num::conversion::traits::{ExactFrom, WrappingFrom};
use malachite_base::slices::slice_leading_zeros;
pub_crate_test! {limbs_twos_complement(xs: &[Limb]) -> Vec<Limb> {
let i = slice_leading_zeros(xs);
let mut result = vec![0; i];
if i != xs.len() {
result.push(xs[i].wrapping_neg());
for x in &xs[i + 1..] {
result.push(!x);
}
}
result
}}
pub_test! {limbs_maybe_sign_extend_non_negative_in_place(xs: &mut Vec<Limb>) {
if let Some(last) = xs.last() && last.get_highest_bit() {
xs.push(0);
}
}}
pub_crate_test! {limbs_twos_complement_in_place(xs: &mut [Limb]) -> bool {
limbs_not_in_place(xs);
limbs_slice_add_limb_in_place(xs, 1)
}}
pub_test! {limbs_twos_complement_and_maybe_sign_extend_negative_in_place(xs: &mut Vec<Limb>) {
assert!(!limbs_twos_complement_in_place(xs));
if let Some(last) = xs.last() && !last.get_highest_bit() {
xs.push(Limb::MAX);
}
}}
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub struct NegativeLimbIterator<'a>(NLIterator<'a>);
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
struct NLIterator<'a> {
pub(crate) limbs: LimbIterator<'a>,
first_nonzero_index: Option<usize>,
}
impl NLIterator<'_> {
fn get_limb(&self, index: u64) -> Limb {
let index = usize::exact_from(index);
if index >= self.limbs.len() {
Limb::MAX
} else {
for i in 0..index {
if self.limbs[i] != 0 {
return !self.limbs[index];
}
}
self.limbs[index].wrapping_neg()
}
}
}
impl Iterator for NLIterator<'_> {
type Item = Limb;
fn next(&mut self) -> Option<Limb> {
let previous_i = self.limbs.i;
self.limbs.next().map(|limb| {
if let Some(first_nonzero_index) = self.first_nonzero_index {
if previous_i <= u64::wrapping_from(first_nonzero_index) {
limb.wrapping_neg()
} else {
!limb
}
} else {
if limb != 0 {
self.first_nonzero_index = Some(usize::exact_from(previous_i));
}
limb.wrapping_neg()
}
})
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
self.limbs.size_hint()
}
}
impl DoubleEndedIterator for NLIterator<'_> {
fn next_back(&mut self) -> Option<Limb> {
let previous_j = self.limbs.j;
self.limbs.next_back().map(|limb| {
if self.first_nonzero_index.is_none() {
let mut i = 0;
while self.limbs[i] == 0 {
i += 1;
}
self.first_nonzero_index = Some(i);
}
let first_nonzero_index = self.first_nonzero_index.unwrap();
if previous_j <= u64::wrapping_from(first_nonzero_index) {
limb.wrapping_neg()
} else {
!limb
}
})
}
}
trait SignExtendedLimbIterator: DoubleEndedIterator<Item = Limb> {
const EXTENSION: Limb;
fn needs_sign_extension(&self) -> bool;
fn iterate_forward(&mut self, extension_checked: &mut bool) -> Option<Limb> {
let next = self.next();
if next.is_none() {
if *extension_checked {
None
} else {
*extension_checked = true;
if self.needs_sign_extension() {
Some(Self::EXTENSION)
} else {
None
}
}
} else {
next
}
}
fn iterate_backward(&mut self, extension_checked: &mut bool) -> Option<Limb> {
if !*extension_checked {
*extension_checked = true;
if self.needs_sign_extension() {
return Some(Self::EXTENSION);
}
}
self.next_back()
}
}
impl SignExtendedLimbIterator for LimbIterator<'_> {
const EXTENSION: Limb = 0;
fn needs_sign_extension(&self) -> bool {
self[self.limb_count - 1].get_highest_bit()
}
}
impl SignExtendedLimbIterator for NLIterator<'_> {
const EXTENSION: Limb = Limb::MAX;
fn needs_sign_extension(&self) -> bool {
let mut i = 0;
while self.limbs[i] == 0 {
i += 1;
}
let last_limb_index = self.limbs.limb_count - 1;
let last_limb = self.limbs[last_limb_index];
let twos_complement_limb = if i == last_limb_index {
last_limb.wrapping_neg()
} else {
!last_limb
};
!twos_complement_limb.get_highest_bit()
}
}
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub enum TwosComplementLimbIterator<'a> {
Zero,
Positive(LimbIterator<'a>, bool),
Negative(NegativeLimbIterator<'a>, bool),
}
impl TwosComplementLimbIterator<'_> {
pub fn get_limb(&self, index: u64) -> Limb {
match self {
Self::Zero => 0,
Self::Positive(limbs, _) => limbs[usize::exact_from(index)],
Self::Negative(limbs, _) => limbs.0.get_limb(index),
}
}
}
impl Iterator for TwosComplementLimbIterator<'_> {
type Item = Limb;
fn next(&mut self) -> Option<Limb> {
match self {
Self::Zero => None,
Self::Positive(limbs, extension_checked) => limbs.iterate_forward(extension_checked),
Self::Negative(limbs, extension_checked) => limbs.0.iterate_forward(extension_checked),
}
}
}
impl DoubleEndedIterator for TwosComplementLimbIterator<'_> {
fn next_back(&mut self) -> Option<Limb> {
match self {
Self::Zero => None,
Self::Positive(limbs, extension_checked) => limbs.iterate_backward(extension_checked),
Self::Negative(limbs, extension_checked) => limbs.0.iterate_backward(extension_checked),
}
}
}
impl Natural {
fn negative_limbs(&self) -> NegativeLimbIterator<'_> {
assert_ne!(*self, 0, "Cannot get negative limbs of 0.");
NegativeLimbIterator(NLIterator {
limbs: self.limbs(),
first_nonzero_index: None,
})
}
}
impl Integer {
pub fn to_twos_complement_limbs_asc(&self) -> Vec<Limb> {
let mut limbs = self.abs.to_limbs_asc();
if self.sign {
limbs_maybe_sign_extend_non_negative_in_place(&mut limbs);
} else {
limbs_twos_complement_and_maybe_sign_extend_negative_in_place(&mut limbs);
}
limbs
}
pub fn to_twos_complement_limbs_desc(&self) -> Vec<Limb> {
let mut xs = self.to_twos_complement_limbs_asc();
xs.reverse();
xs
}
pub fn into_twos_complement_limbs_asc(self) -> Vec<Limb> {
let mut xs = self.abs.into_limbs_asc();
if self.sign {
limbs_maybe_sign_extend_non_negative_in_place(&mut xs);
} else {
limbs_twos_complement_and_maybe_sign_extend_negative_in_place(&mut xs);
}
xs
}
pub fn into_twos_complement_limbs_desc(self) -> Vec<Limb> {
let mut xs = self.into_twos_complement_limbs_asc();
xs.reverse();
xs
}
pub fn twos_complement_limbs(&self) -> TwosComplementLimbIterator<'_> {
if *self == 0 {
TwosComplementLimbIterator::Zero
} else if self.sign {
TwosComplementLimbIterator::Positive(self.abs.limbs(), false)
} else {
TwosComplementLimbIterator::Negative(self.abs.negative_limbs(), false)
}
}
pub fn twos_complement_limb_count(&self) -> u64 {
if *self == 0 {
return 0;
}
let abs_limbs_count = self.unsigned_abs_ref().limb_count();
let highest_bit_of_highest_limb =
self.unsigned_abs().limbs()[usize::exact_from(abs_limbs_count - 1)].get_highest_bit();
if highest_bit_of_highest_limb
&& (*self > 0 || (*self < 0 && !self.unsigned_abs_ref().is_power_of_2()))
{
abs_limbs_count + 1
} else {
abs_limbs_count
}
}
}