#![doc(hidden)]
#[cfg(feature = "power-of-two")]
use lexical_util::format::NumberFormat;
use lexical_util::num::AsPrimitive;
use crate::float::{ExtendedFloat80, RawFloat};
use crate::mask::{lower_n_halfway, lower_n_mask};
#[cfg(not(feature = "compact"))]
macro_rules! can_try_parse_multidigit {
($iter:expr, $radix:expr) => {
$iter.is_contiguous() && (cfg!(not(feature = "power-of-two")) || $radix <= 10)
};
}
#[inline(always)]
pub fn calculate_shift<F: RawFloat>(power2: i32) -> i32 {
let mantissa_shift = 64 - F::MANTISSA_SIZE - 1;
if -power2 >= mantissa_shift {
-power2 + 1
} else {
mantissa_shift
}
}
#[inline(always)]
#[cfg(feature = "power-of-two")]
pub fn calculate_power2<F: RawFloat, const FORMAT: u128>(exponent: i64, ctlz: u32) -> i32 {
let format = NumberFormat::<{ FORMAT }> {};
exponent as i32 * log2(format.exponent_base()) + F::EXPONENT_BIAS - ctlz as i32
}
pub const INVALID_FP: i32 = i16::MIN as i32;
#[inline(always)]
pub const fn log2(radix: u32) -> i32 {
match radix {
2 => 1,
4 => 2,
8 => 3,
16 => 4,
32 => 5,
_ => 1,
}
}
#[cfg_attr(not(feature = "compact"), inline(always))]
pub fn starts_with<'a, 'b, Iter1, Iter2>(mut x: Iter1, mut y: Iter2) -> bool
where
Iter1: Iterator<Item = &'a u8>,
Iter2: Iterator<Item = &'b u8>,
{
loop {
let yi = y.next();
if yi.is_none() {
return true;
} else if x.next() != yi {
return false;
}
}
}
#[cfg_attr(not(feature = "compact"), inline(always))]
#[allow(clippy::unwrap_used)] pub fn starts_with_uncased<'a, 'b, Iter1, Iter2>(mut x: Iter1, mut y: Iter2) -> bool
where
Iter1: Iterator<Item = &'a u8>,
Iter2: Iterator<Item = &'b u8>,
{
loop {
let yi = y.next();
if yi.is_none() {
return true;
}
let yi = *yi.unwrap();
let is_not_equal = x.next().map_or(true, |&xi| {
let xor = xi ^ yi;
xor != 0 && xor != 0x20
});
if is_not_equal {
return false;
}
}
}
#[cfg_attr(not(feature = "compact"), inline(always))]
pub fn round<F, Cb>(fp: &mut ExtendedFloat80, cb: Cb)
where
F: RawFloat,
Cb: Fn(&mut ExtendedFloat80, i32),
{
let fp_inf = ExtendedFloat80 {
mant: 0,
exp: F::INFINITE_POWER,
};
let mantissa_shift = 64 - F::MANTISSA_SIZE - 1;
if -fp.exp >= mantissa_shift {
let shift = -fp.exp + 1;
debug_assert!(shift <= 65);
cb(fp, shift.min(64));
fp.exp = (fp.mant >= F::HIDDEN_BIT_MASK.as_u64()) as i32;
return;
}
cb(fp, mantissa_shift);
let carry_mask = F::CARRY_MASK.as_u64();
if fp.mant & carry_mask == carry_mask {
fp.mant >>= 1;
fp.exp += 1;
}
if fp.exp >= F::INFINITE_POWER {
*fp = fp_inf;
return;
}
fp.mant &= F::MANTISSA_MASK.as_u64();
}
#[cfg_attr(not(feature = "compact"), inline(always))]
pub fn round_nearest_tie_even<Cb>(fp: &mut ExtendedFloat80, shift: i32, cb: Cb)
where
Cb: Fn(bool, bool, bool) -> bool,
{
debug_assert!(shift <= 64);
let mask = lower_n_mask(shift as u64);
let halfway = lower_n_halfway(shift as u64);
let truncated_bits = fp.mant & mask;
let is_above = truncated_bits > halfway;
let is_halfway = truncated_bits == halfway;
fp.mant = match shift == 64 {
true => 0,
false => fp.mant >> shift,
};
fp.exp += shift;
let is_odd = fp.mant & 1 == 1;
fp.mant += cb(is_odd, is_halfway, is_above) as u64;
}
#[cfg_attr(not(feature = "compact"), inline(always))]
pub fn round_down(fp: &mut ExtendedFloat80, shift: i32) {
fp.mant = match shift == 64 {
true => 0,
false => fp.mant >> shift,
};
fp.exp += shift;
}