use std::hint::assert_unchecked;
use std::num::NonZeroU32;
use crate::integer::factorization::{NR_SMALL_PRIMES, start};
use crate::integer::factorization::prime::primes::SMALL_ODD_PRIMES;
use crate::Prime;
pub fn factorize(value: NonZeroU32) -> (Vec<(u32, u32)>, u32) {
let mut x = value.get();
let mut factors = Vec::with_capacity(9);
let two_powers = x.trailing_zeros();
if two_powers > 0 {
x >>= two_powers;
factors.push((2, two_powers));
}
'odd_trial_division: {
for divisor in &SMALL_ODD_PRIMES[..NR_SMALL_PRIMES] {
let divisor = *divisor as u32;
unsafe { assert_unchecked(divisor != 0); }
let mut counter = 0;
while x.is_multiple_of(divisor) {
x /= divisor;
counter += 1;
}
if counter > 0 {
factors.push((divisor, counter));
}
if x == 1 {
break 'odd_trial_division;
}
}
let mut divisor = start(NR_SMALL_PRIMES) as u32;
let mut is_prime = x.is_prime();
while x > 1 && !is_prime {
debug_assert!(
divisor as u64 * divisor as u64 <= x as u64,
"a composite `x` always has a factor at or below its square root",
);
let mut counter = 0;
while x.is_multiple_of(divisor) {
x /= divisor;
counter += 1;
}
if counter > 0 {
factors.push((divisor, counter));
is_prime = x.is_prime();
}
divisor += 2;
}
if x > 1 {
factors.push((x, 1));
}
}
(factors, 1)
}