|
5 | 5 |
|
6 | 6 | use std::any::type_name; |
7 | 7 | use std::env; |
| 8 | +use std::num::ParseIntError; |
8 | 9 | use std::str::FromStr; |
9 | 10 |
|
10 | 11 | #[cfg(feature = "build-mpfr")] |
11 | 12 | use az::Az; |
| 13 | +use libm::support::{hf32, hf64}; |
12 | 14 | #[cfg(feature = "build-mpfr")] |
13 | 15 | use libm_test::mpfloat::MpOp; |
14 | 16 | use libm_test::{MathOp, TupleCall}; |
@@ -238,21 +240,103 @@ impl_parse_tuple_via_rug!(f16); |
238 | 240 | impl_parse_tuple_via_rug!(f128); |
239 | 241 |
|
240 | 242 | /// 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 { |
242 | 244 | 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())) |
244 | 257 | } |
245 | 258 |
|
246 | 259 | /// Try to parse the float type going via `rug`, for `f16` and `f128` which don't yet implement |
247 | 260 | /// `FromStr`. |
248 | 261 | #[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 |
250 | 263 | where |
| 264 | + F: libm_test::Float + FromStrRadix, |
251 | 265 | rug::Float: az::Cast<F>, |
252 | 266 | { |
253 | 267 | 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())); |
256 | 280 | let x = rug::Float::with_val(F::BITS, x); |
257 | 281 | x.az() |
258 | 282 | } |
| 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