Skip to content
This repository was archived by the owner on Apr 28, 2025. It is now read-only.

Commit 29697dc

Browse files
committed
Add the ability to parse hex, binary, and float hex with util
1 parent 753d69f commit 29697dc

File tree

1 file changed

+89
-5
lines changed

1 file changed

+89
-5
lines changed

crates/util/src/main.rs

Lines changed: 89 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,12 @@
55

66
use std::any::type_name;
77
use std::env;
8+
use std::num::ParseIntError;
89
use std::str::FromStr;
910

1011
#[cfg(feature = "build-mpfr")]
1112
use az::Az;
13+
use libm::support::{hf32, hf64};
1214
#[cfg(feature = "build-mpfr")]
1315
use libm_test::mpfloat::MpOp;
1416
use libm_test::{MathOp, TupleCall};
@@ -238,21 +240,103 @@ impl_parse_tuple_via_rug!(f16);
238240
impl_parse_tuple_via_rug!(f128);
239241

240242
/// Try to parse the number, printing a nice message on failure.
241-
fn parse<F: FromStr>(input: &[&str], idx: usize) -> F {
243+
fn parse<T: FromStr + FromStrRadix>(input: &[&str], idx: usize) -> T {
242244
let s = input[idx];
243-
s.parse().unwrap_or_else(|_| panic!("invalid {} input '{s}'", type_name::<F>()))
245+
246+
let msg = || format!("invalid {} input '{s}'", type_name::<T>());
247+
248+
if s.starts_with("0x") {
249+
return T::from_str_radix(s, 16).unwrap_or_else(|_| panic!("{}", msg()));
250+
}
251+
252+
if s.starts_with("0b") {
253+
return T::from_str_radix(s, 2).unwrap_or_else(|_| panic!("{}", msg()));
254+
}
255+
256+
s.parse().unwrap_or_else(|_| panic!("{}", msg()))
244257
}
245258

246259
/// Try to parse the float type going via `rug`, for `f16` and `f128` which don't yet implement
247260
/// `FromStr`.
248261
#[cfg(feature = "build-mpfr")]
249-
fn parse_rug<F: libm_test::Float>(input: &[&str], idx: usize) -> F
262+
fn parse_rug<F>(input: &[&str], idx: usize) -> F
250263
where
264+
F: libm_test::Float + FromStrRadix,
251265
rug::Float: az::Cast<F>,
252266
{
253267
let s = input[idx];
254-
let x =
255-
rug::Float::parse(s).unwrap_or_else(|_| panic!("invalid {} input '{s}'", type_name::<F>()));
268+
269+
let msg = || format!("invalid {} input '{s}'", type_name::<F>());
270+
271+
if s.starts_with("0x") {
272+
return F::from_str_radix(s, 16).unwrap_or_else(|_| panic!("{}", msg()));
273+
}
274+
275+
if s.starts_with("0b") {
276+
return F::from_str_radix(s, 2).unwrap_or_else(|_| panic!("{}", msg()));
277+
}
278+
279+
let x = rug::Float::parse(s).unwrap_or_else(|_| panic!("{}", msg()));
256280
let x = rug::Float::with_val(F::BITS, x);
257281
x.az()
258282
}
283+
284+
trait FromStrRadix: Sized {
285+
fn from_str_radix(s: &str, radix: u32) -> Result<Self, ParseIntError>;
286+
}
287+
288+
impl FromStrRadix for i32 {
289+
fn from_str_radix(s: &str, radix: u32) -> Result<Self, ParseIntError> {
290+
let s = strip_radix_prefix(s, radix);
291+
i32::from_str_radix(s, radix)
292+
}
293+
}
294+
295+
#[cfg(f16_enabled)]
296+
impl FromStrRadix for f16 {
297+
fn from_str_radix(s: &str, radix: u32) -> Result<Self, ParseIntError> {
298+
let s = strip_radix_prefix(s, radix);
299+
u16::from_str_radix(s, radix).map(Self::from_bits)
300+
}
301+
}
302+
303+
impl FromStrRadix for f32 {
304+
fn from_str_radix(s: &str, radix: u32) -> Result<Self, ParseIntError> {
305+
if radix == 16 && s.contains("p") {
306+
// Parse as hex float
307+
return Ok(hf32(s));
308+
}
309+
310+
let s = strip_radix_prefix(s, radix);
311+
u32::from_str_radix(s, radix).map(Self::from_bits)
312+
}
313+
}
314+
315+
impl FromStrRadix for f64 {
316+
fn from_str_radix(s: &str, radix: u32) -> Result<Self, ParseIntError> {
317+
if s.contains("p") {
318+
return Ok(hf64(s));
319+
}
320+
321+
let s = strip_radix_prefix(s, radix);
322+
u64::from_str_radix(s, radix).map(Self::from_bits)
323+
}
324+
}
325+
326+
#[cfg(f128_enabled)]
327+
impl FromStrRadix for f128 {
328+
fn from_str_radix(s: &str, radix: u32) -> Result<Self, ParseIntError> {
329+
let s = strip_radix_prefix(s, radix);
330+
u128::from_str_radix(s, radix).map(Self::from_bits)
331+
}
332+
}
333+
334+
fn strip_radix_prefix(s: &str, radix: u32) -> &str {
335+
if radix == 16 {
336+
s.strip_prefix("0x").unwrap()
337+
} else if radix == 2 {
338+
s.strip_prefix("0b").unwrap()
339+
} else {
340+
s
341+
}
342+
}

0 commit comments

Comments
 (0)