|
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