use crate::integer_polynomial::arithmetic::coefficient::PolynomialCoefficient;
use crate::integer_polynomial::arithmetic::mul::mul_greater_to_out;
use crate::integer_polynomial::arithmetic::square::square_to_out;
use alloc::vec;
use core::mem::swap;
use malachite_base::num::arithmetic::traits::{FloorLogBase2, Parity, PowerOf2};
pub(crate) fn binexp_start(e: u64) -> (u64, bool) {
let bit = u64::power_of_2(e.floor_log_base_2()) >> 1;
let lower_zeros = bit.trailing_zeros() - (e & (bit - 1)).count_ones();
(bit, (e & bit != 0) != lower_zeros.odd())
}
crate_test_fn! {pow_to_out_binexp<C: PolynomialCoefficient>(out: &mut [C], xs: &[C], e: u64) {
let len = xs.len();
let mut v = vec![C::ZERO; out.len()];
let (mut bit, swaps) = binexp_start(e);
let (mut r, mut s): (&mut [C], &mut [C]) = if swaps { (&mut v, out) } else { (out, &mut v) };
let mut rlen = (len << 1) - 1;
square_to_out(&mut r[..rlen], xs);
if bit & e != 0 {
mul_greater_to_out(&mut s[..rlen + len - 1], &r[..rlen], xs);
rlen += len - 1;
swap(&mut r, &mut s);
}
loop {
bit >>= 1;
if bit == 0 {
break;
}
square_to_out(&mut s[..(rlen << 1) - 1], &r[..rlen]);
rlen += rlen - 1;
if bit & e != 0 {
mul_greater_to_out(&mut r[..rlen + len - 1], &s[..rlen], xs);
rlen += len - 1;
} else {
swap(&mut r, &mut s);
}
}
}}