from_u32(0) can just be default()

This commit is contained in:
Giles Cope 2022-04-04 15:53:53 +01:00
parent 72a5e7e810
commit 82e9d9ebac
No known key found for this signature in database
GPG Key ID: 631F6352D4A949EF
3 changed files with 57 additions and 16 deletions

View File

@ -969,9 +969,8 @@ pub enum FpCategory {
}
#[doc(hidden)]
trait FromStrRadixHelper: PartialOrd + Copy {
trait FromStrRadixHelper: PartialOrd + Copy + Default {
const MIN: Self;
fn from_u32(u: u32) -> Self;
fn checked_mul(&self, other: u32) -> Option<Self>;
fn checked_sub(&self, other: u32) -> Option<Self>;
fn checked_add(&self, other: u32) -> Option<Self>;
@ -997,8 +996,6 @@ macro_rules! impl_helper_for {
($($t:ty)*) => ($(impl FromStrRadixHelper for $t {
const MIN: Self = Self::MIN;
#[inline]
fn from_u32(u: u32) -> Self { u as Self }
#[inline]
fn checked_mul(&self, other: u32) -> Option<Self> {
Self::checked_mul(*self, other as Self)
}
@ -1035,8 +1032,14 @@ unsafe fn unchecked_add(self, other: u32) -> Self {
}
impl_helper_for! { i8 i16 i32 i64 i128 isize u8 u16 u32 u64 u128 usize }
/// Determins if a string of text of that length of that radix could be guaranteed to be
/// stored in the given type T.
/// Note that if the radix is known to the compiler, it is just the check of digits.len that
/// is done at runtime.
#[doc(hidden)]
#[inline(always)]
pub(crate) fn can_not_overflow<T>(radix: u32, is_signed_ty: bool, digits:&[u8]) -> bool {
#[unstable(issue = "none", feature = "std_internals")]
pub fn can_not_overflow<T>(radix: u32, is_signed_ty: bool, digits: &[u8]) -> bool {
radix <= 16 && digits.len() <= mem::size_of::<T>() * 2 - is_signed_ty as usize
}
@ -1054,7 +1057,7 @@ fn from_str_radix<T: FromStrRadixHelper>(src: &str, radix: u32) -> Result<T, Par
return Err(PIE { kind: Empty });
}
let is_signed_ty = T::from_u32(0) > T::MIN;
let is_signed_ty = T::default() > T::MIN;
// all valid digits are ascii, so we will just iterate over the utf8 bytes
// and cast them to chars. .to_digit() will safely return None for anything
@ -1071,7 +1074,7 @@ fn from_str_radix<T: FromStrRadixHelper>(src: &str, radix: u32) -> Result<T, Par
_ => (true, src),
};
let mut result = T::from_u32(0);
let mut result = T::default();
if can_not_overflow::<T>(radix, is_signed_ty, digits) {
// SAFETY: If the len of the str is short compared to the range of the type
@ -1127,11 +1130,3 @@ macro_rules! run_checked_loop {
}
Ok(result)
}
mod tests {
#[test]
fn test_can_not_overflow() {
assert_eq!(can_not_overflow::<i8>(10, true, "99".as_bytes()), true);
assert_eq!(can_not_overflow::<i8>(10, true, "129".as_bytes()), false);
}
}

View File

@ -55,6 +55,7 @@
#![feature(numfmt)]
#![feature(step_trait)]
#![feature(str_internals)]
#![feature(std_internals)]
#![feature(test)]
#![feature(trusted_len)]
#![feature(try_blocks)]

View File

@ -2,7 +2,7 @@
use core::convert::{TryFrom, TryInto};
use core::fmt::Debug;
use core::marker::Copy;
use core::num::{IntErrorKind, ParseIntError, TryFromIntError};
use core::num::{can_not_overflow, IntErrorKind, ParseIntError, TryFromIntError};
use core::ops::{Add, Div, Mul, Rem, Sub};
use core::option::Option;
use core::option::Option::None;
@ -120,6 +120,51 @@ fn test_int_from_str_overflow() {
test_parse::<i64>("-9223372036854775809", Err(IntErrorKind::NegOverflow));
}
#[test]
fn test_can_not_overflow() {
// Not currently in std lib (issue: #27728)
fn format_radix<T>(mut x: T, radix: T) -> String
where
T: std::ops::Rem<Output = T>,
T: std::ops::Div<Output = T>,
T: std::cmp::PartialEq,
T: std::default::Default,
T: Copy,
T: Default,
u32: TryFrom<T>,
{
let mut result = vec![];
loop {
let m = x % radix;
x = x / radix;
result.push(
std::char::from_digit(m.try_into().ok().unwrap(), radix.try_into().ok().unwrap())
.unwrap(),
);
if x == T::default() {
break;
}
}
result.into_iter().rev().collect()
}
macro_rules! check {
($($t:ty)*) => ($(
for base in 2..=36 {
let num = (<$t>::MAX as u128) + 1;
// Calcutate the string length for the smallest overflowing number:
let max_len_string = format_radix(num, base as u128);
// Ensure that that string length is deemed to potentially overflow:
assert_eq!(can_not_overflow::<$t>(base, <$t>::default() > <$t>::MIN, max_len_string.as_bytes()), false);
}
)*)
}
check! { i8 i16 i32 i64 i128 isize usize u8 u16 u32 u64 }
}
#[test]
fn test_leading_plus() {
test_parse::<u8>("+127", Ok(127));