use crate::common::*;
use crate::f2s;
use crate::f2s_intrinsics::*;
use crate::parse::Error;
#[cfg(feature = "no-panic")]
use no_panic::no_panic;
const FLOAT_EXPONENT_BIAS: usize = 127;
fn floor_log2(value: u32) -> u32 {
31_u32.wrapping_sub(value.leading_zeros())
}
#[cfg_attr(feature = "no-panic", no_panic)]
pub fn s2f(buffer: &[u8]) -> Result<f32, Error> {
let len = buffer.len();
if len == 0 {
return Err(Error::InputTooShort);
}
let mut m10digits = 0;
let mut e10digits = 0;
let mut dot_index = len;
let mut e_index = len;
let mut m10 = 0u32;
let mut e10 = 0i32;
let mut signed_m = false;
let mut signed_e = false;
let mut i = 0;
if unsafe { *buffer.get_unchecked(0) } == b'-' {
signed_m = true;
i += 1;
}
while let Some(c) = buffer.get(i).copied() {
if c == b'.' {
if dot_index != len {
return Err(Error::MalformedInput);
}
dot_index = i;
i += 1;
continue;
}
if c < b'0' || c > b'9' {
break;
}
if m10digits >= 9 {
return Err(Error::InputTooLong);
}
m10 = 10 * m10 + (c - b'0') as u32;
if m10 != 0 {
m10digits += 1;
}
i += 1;
}
if let Some(b'e') | Some(b'E') = buffer.get(i) {
e_index = i;
i += 1;
match buffer.get(i) {
Some(b'-') => {
signed_e = true;
i += 1;
}
Some(b'+') => i += 1,
_ => {}
}
while let Some(c) = buffer.get(i).copied() {
if c < b'0' || c > b'9' {
return Err(Error::MalformedInput);
}
if e10digits > 3 {
return Err(Error::InputTooLong);
}
e10 = 10 * e10 + (c - b'0') as i32;
if e10 != 0 {
e10digits += 1;
}
i += 1;
}
}
if i < len {
return Err(Error::MalformedInput);
}
if signed_e {
e10 = -e10;
}
e10 -= if dot_index < e_index {
(e_index - dot_index - 1) as i32
} else {
0
};
if m10 == 0 {
return Ok(if signed_m { -0.0 } else { 0.0 });
}
if m10digits + e10 <= -46 || m10 == 0 {
let ieee = (signed_m as u32) << (f2s::FLOAT_EXPONENT_BITS + f2s::FLOAT_MANTISSA_BITS);
return Ok(f32::from_bits(ieee));
}
if m10digits + e10 >= 40 {
let ieee = ((signed_m as u32) << (f2s::FLOAT_EXPONENT_BITS + f2s::FLOAT_MANTISSA_BITS))
| (0xff_u32 << f2s::FLOAT_MANTISSA_BITS);
return Ok(f32::from_bits(ieee));
}
let e2: i32;
let m2: u32;
let mut trailing_zeros = if e10 >= 0 {
e2 = floor_log2(m10)
.wrapping_add(e10 as u32)
.wrapping_add(log2_pow5(e10) as u32)
.wrapping_sub(f2s::FLOAT_MANTISSA_BITS + 1) as i32;
let j = e2
.wrapping_sub(e10)
.wrapping_sub(ceil_log2_pow5(e10))
.wrapping_add(f2s::FLOAT_POW5_BITCOUNT);
debug_assert!(j >= 0);
m2 = mul_pow5_div_pow2(m10, e10 as u32, j);
e2 < e10 || e2 - e10 < 32 && multiple_of_power_of_2_32(m10, (e2 - e10) as u32)
} else {
e2 = floor_log2(m10)
.wrapping_add(e10 as u32)
.wrapping_sub(ceil_log2_pow5(-e10) as u32)
.wrapping_sub(f2s::FLOAT_MANTISSA_BITS + 1) as i32;
let j = e2
.wrapping_sub(e10)
.wrapping_add(ceil_log2_pow5(-e10))
.wrapping_sub(1)
.wrapping_add(f2s::FLOAT_POW5_INV_BITCOUNT);
m2 = mul_pow5_inv_div_pow2(m10, -e10 as u32, j);
multiple_of_power_of_5_32(m10, -e10 as u32)
};
let mut ieee_e2 = i32::max(0, e2 + FLOAT_EXPONENT_BIAS as i32 + floor_log2(m2) as i32) as u32;
if ieee_e2 > 0xfe {
let ieee = ((signed_m as u32) << (f2s::FLOAT_EXPONENT_BITS + f2s::FLOAT_MANTISSA_BITS))
| (0xff_u32 << f2s::FLOAT_MANTISSA_BITS);
return Ok(f32::from_bits(ieee));
}
let shift = if ieee_e2 == 0 { 1 } else { ieee_e2 as i32 }
.wrapping_sub(e2)
.wrapping_sub(FLOAT_EXPONENT_BIAS as i32)
.wrapping_sub(f2s::FLOAT_MANTISSA_BITS as i32);
debug_assert!(shift >= 0);
trailing_zeros &= (m2 & ((1_u32 << (shift - 1)) - 1)) == 0;
let last_removed_bit = (m2 >> (shift - 1)) & 1;
let round_up = last_removed_bit != 0 && (!trailing_zeros || ((m2 >> shift) & 1) != 0);
let mut ieee_m2 = (m2 >> shift).wrapping_add(round_up as u32);
if ieee_m2 == (1_u32 << (f2s::FLOAT_MANTISSA_BITS + 1)) {
ieee_e2 += 1;
}
ieee_m2 &= (1_u32 << f2s::FLOAT_MANTISSA_BITS) - 1;
let ieee = ((((signed_m as u32) << f2s::FLOAT_EXPONENT_BITS) | ieee_e2 as u32)
<< f2s::FLOAT_MANTISSA_BITS)
| ieee_m2;
Ok(f32::from_bits(ieee))
}