use crate::integer::Integer;
use crate::integer::conversion::to_twos_complement_limbs::limbs_twos_complement_in_place;
use crate::natural::Natural;
use crate::natural::arithmetic::shr::limbs_slice_shr_in_place;
use crate::platform::{Limb, SignedLimb};
use alloc::vec::Vec;
use itertools::Itertools;
use malachite_base::num::basic::integers::PrimitiveInt;
use malachite_base::num::basic::traits::Zero;
use malachite_base::num::conversion::traits::{ExactFrom, WrappingFrom};
use malachite_base::num::logic::traits::{BitConvertible, LowMask, NotAssign};
pub_test! {bits_to_twos_complement_bits_non_negative(bits: &mut Vec<bool>) {
if !bits.is_empty() && *bits.last().unwrap() {
bits.push(false);
}
}}
pub_test! {bits_slice_to_twos_complement_bits_negative(bits: &mut [bool]) -> bool {
let mut true_seen = false;
for bit in &mut *bits {
if true_seen {
bit.not_assign();
} else if *bit {
true_seen = true;
}
}
!true_seen
}}
pub_test! {bits_vec_to_twos_complement_bits_negative(bits: &mut Vec<bool>) {
assert!(!bits_slice_to_twos_complement_bits_negative(bits));
if bits.last() == Some(&false) {
bits.push(true);
}
}}
fn from_bits_helper(mut limbs: Vec<Limb>, sign_bit: bool, last_width: u64) -> Integer {
if sign_bit {
if last_width != Limb::WIDTH {
*limbs.last_mut().unwrap() |= !Limb::low_mask(last_width);
}
assert!(!limbs_twos_complement_in_place(&mut limbs));
}
Integer::from_sign_and_abs(!sign_bit, Natural::from_owned_limbs_asc(limbs))
}
impl BitConvertible for Integer {
fn to_bits_asc(&self) -> Vec<bool> {
let mut bits = self.abs.to_bits_asc();
if self.sign {
bits_to_twos_complement_bits_non_negative(&mut bits);
} else {
bits_vec_to_twos_complement_bits_negative(&mut bits);
}
bits
}
fn to_bits_desc(&self) -> Vec<bool> {
let mut bits = self.to_bits_asc();
bits.reverse();
bits
}
fn from_bits_asc<I: Iterator<Item = bool>>(xs: I) -> Self {
let mut limbs = Vec::new();
let mut last_width = 0;
let mut last_bit = false;
for chunk in &xs.chunks(usize::exact_from(Limb::WIDTH)) {
let mut limb = 0;
let mut i = 0;
let mut mask = 1;
for bit in chunk {
if bit {
limb |= mask;
}
mask <<= 1;
i += 1;
last_bit = bit;
}
last_width = i;
limbs.push(limb);
}
from_bits_helper(limbs, last_bit, last_width)
}
fn from_bits_desc<I: Iterator<Item = bool>>(xs: I) -> Self {
let mut limbs = Vec::new();
let mut last_width = 0;
let mut first_bit = false;
let mut first = true;
for chunk in &xs.chunks(usize::exact_from(Limb::WIDTH)) {
let mut limb = 0;
let mut i = 0;
for bit in chunk {
if first {
first_bit = bit;
first = false;
}
limb <<= 1;
if bit {
limb |= 1;
}
i += 1;
}
last_width = i;
limbs.push(limb);
}
match limbs.len() {
0 => Self::ZERO,
1 => {
if first_bit {
if last_width != Limb::WIDTH {
limbs[0] |= !Limb::low_mask(last_width);
}
Self::from(SignedLimb::wrapping_from(limbs[0]))
} else {
Self::from(limbs[0])
}
}
_ => {
limbs.reverse();
if last_width != Limb::WIDTH {
let smallest_limb = limbs[0];
limbs[0] = 0;
limbs_slice_shr_in_place(&mut limbs, Limb::WIDTH - last_width);
limbs[0] |= smallest_limb;
}
from_bits_helper(limbs, first_bit, last_width)
}
}
}
}