use crate::integer::Integer;
use crate::integer_polynomial::IntegerPolynomial;
use crate::integer_polynomial::arithmetic::coefficient::PolynomialCoefficient;
use crate::integer_polynomial::arithmetic::vec::small_value;
use crate::natural::Natural;
use crate::natural::arithmetic::add::limbs_slice_add_limb_in_place;
use crate::natural::arithmetic::shl::{limbs_shl_to_out, limbs_slice_shl_in_place};
use crate::natural::arithmetic::sub::limbs_sub_limb_in_place;
use crate::natural::logic::not::limbs_not_to_out;
use crate::natural_polynomial::arithmetic::bit_pack::limbs_bit_pack;
use crate::platform::Limb;
use malachite_base::num::arithmetic::traits::{ModPowerOf2Assign, PowerOf2, WrappingAddAssign};
use malachite_base::num::basic::integers::PrimitiveInt;
use malachite_base::num::conversion::traits::{ExactFrom, WrappingFrom};
use malachite_base::num::logic::traits::LowMask;
use malachite_base::polynomial::BitPack;
pub(crate) fn field_start(i: usize, bits: u64) -> (usize, u64) {
let start = u64::exact_from(i) * bits;
(
usize::exact_from(start >> Limb::LOG_WIDTH),
start & Limb::WIDTH_MASK,
)
}
crate_test_fn! {limbs_pack_field<C: PolynomialCoefficient>(
arr: &mut [Limb],
shift: u64,
bits: u64,
x: &C,
negate: bool,
borrow: bool,
) -> bool {
let save = arr[0];
let limbs = usize::exact_from((shift + bits) >> Limb::LOG_WIDTH);
let rem_bits = (shift + bits) & Limb::WIDTH_MASK;
if x.is_zero() {
if borrow {
arr[0] = (Limb::MAX << shift).wrapping_add(save);
if limbs > 1 {
arr[1..limbs].fill(Limb::MAX);
}
if limbs != 0 {
if rem_bits != 0 {
arr[limbs] = Limb::low_mask(rem_bits);
}
} else {
arr[limbs].mod_power_of_2_assign(rem_bits);
}
}
return borrow;
}
if x.is_negative() ^ negate {
let size = if let Some(c) = small_value(x) {
let c_bits = Limb::wrapping_from(c);
let d = if c < 0 {
c_bits.wrapping_sub(Limb::from(borrow))
} else {
c_bits.wrapping_neg().wrapping_sub(Limb::from(borrow))
};
arr[0] = (d << shift).wrapping_add(save);
if limbs != 0 {
arr[1] = if shift != 0 {
(d >> (Limb::WIDTH - shift)).wrapping_add(Limb::MAX << shift)
} else {
Limb::MAX
};
}
2
} else {
let xs = x.unsigned_abs_ref().as_limbs_asc();
let mut s = xs.len();
limbs_not_to_out(&mut arr[..s], xs);
if !borrow {
limbs_slice_add_limb_in_place(&mut arr[..s], 1);
}
if shift != 0 {
let carry = limbs_slice_shl_in_place(&mut arr[..s], shift);
if limbs + usize::from(rem_bits != 0) > s {
arr[s] = (Limb::MAX << shift).wrapping_add(carry);
s += 1;
}
}
arr[0].wrapping_add_assign(save);
s
};
if limbs >= size {
if limbs > size {
arr[size..limbs].fill(Limb::MAX);
}
if rem_bits != 0 {
arr[limbs] = Limb::low_mask(rem_bits);
}
} else {
arr[limbs].mod_power_of_2_assign(rem_bits);
}
true
} else {
if let Some(c) = small_value(x) {
let d = Limb::wrapping_from(c.unsigned_abs()) - Limb::from(borrow);
arr[0] = (d << shift).wrapping_add(save);
if limbs + usize::from(rem_bits != 0) > 1 && shift != 0 {
arr[1] = d >> (Limb::WIDTH - shift);
}
} else {
let xs = x.unsigned_abs_ref().as_limbs_asc();
let mut s = xs.len();
if shift != 0 {
let carry = limbs_shl_to_out(&mut arr[..s], xs, shift);
if carry != 0 {
arr[s] = carry;
s += 1;
}
} else {
arr[..s].copy_from_slice(xs);
}
if borrow {
limbs_sub_limb_in_place(&mut arr[..s], Limb::power_of_2(shift));
}
arr[0].wrapping_add_assign(save);
}
false
}
}}
crate_test_fn! {limbs_pack_coefficients<C: PolynomialCoefficient>(
out: &mut [Limb],
xs: &[C],
bits: u64,
negate: bool,
) {
let mut borrow = false;
for (i, x) in xs.iter().enumerate() {
let (limbs, shift) = field_start(i, bits);
borrow = limbs_pack_field(&mut out[limbs..], shift, bits, x, negate, borrow);
}
}}
fn bit_pack_ref(p: &IntegerPolynomial, bits: u64) -> Integer {
let positive = limbs_bit_pack(
p.coefficients
.iter()
.enumerate()
.filter(|(_, c)| **c > 0u32)
.map(|(i, c)| (i, c.unsigned_abs_ref())),
bits,
);
let negative = limbs_bit_pack(
p.coefficients
.iter()
.enumerate()
.filter(|(_, c)| **c < 0u32)
.map(|(i, c)| (i, c.unsigned_abs_ref())),
bits,
);
let positive = Integer::from(Natural::from_owned_limbs_asc(positive));
if negative.is_empty() {
positive
} else {
positive - Integer::from(Natural::from_owned_limbs_asc(negative))
}
}
impl BitPack for IntegerPolynomial {
type Output = Integer;
#[inline]
fn bit_pack(self, bits: u64) -> Integer {
bit_pack_ref(&self, bits)
}
}
impl BitPack for &IntegerPolynomial {
type Output = Integer;
#[inline]
fn bit_pack(self, bits: u64) -> Integer {
bit_pack_ref(self, bits)
}
}