Skip to content

Commit ac8869e

Browse files
committed
---
yaml --- r: 235575 b: refs/heads/stable c: 5d30413 h: refs/heads/master i: 235573: 38bb231 235571: aa2541d 235567: f674e13 v: v3
1 parent 0b2f832 commit ac8869e

File tree

4 files changed

+121
-16
lines changed

4 files changed

+121
-16
lines changed

[refs]

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ refs/heads/tmp: afae2ff723393b3ab4ccffef6ac7c6d1809e2da0
2929
refs/tags/1.0.0-alpha.2: 4c705f6bc559886632d3871b04f58aab093bfa2f
3030
refs/tags/homu-tmp: f859507de8c410b648d934d8f5ec1c52daac971d
3131
refs/tags/1.0.0-beta: 8cbb92b53468ee2b0c2d3eeb8567005953d40828
32-
refs/heads/stable: 60734a65deeef396bb029b159d75a8fa29622067
32+
refs/heads/stable: 5d304134ff65931e0529bf68ec14972f81d2fdb1
3333
refs/tags/1.0.0: 55bd4f8ff2b323f317ae89e254ce87162d52a375
3434
refs/tags/1.1.0: bc3c16f09287e5545c1d3f76b7abd54f2eca868b
3535
refs/tags/1.2.0: f557861f822c34f07270347b94b5280de20a597e

branches/stable/src/libcore/fmt/num.rs

Lines changed: 86 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,18 +20,25 @@ use fmt;
2020
use num::Zero;
2121
use ops::{Div, Rem, Sub};
2222
use str;
23+
use slice;
24+
use ptr;
25+
use mem;
2326

2427
#[doc(hidden)]
2528
trait Int: Zero + PartialEq + PartialOrd + Div<Output=Self> + Rem<Output=Self> +
2629
Sub<Output=Self> + Copy {
2730
fn from_u8(u: u8) -> Self;
2831
fn to_u8(&self) -> u8;
32+
fn to_u32(&self) -> u32;
33+
fn to_u64(&self) -> u64;
2934
}
3035

3136
macro_rules! doit {
3237
($($t:ident)*) => ($(impl Int for $t {
3338
fn from_u8(u: u8) -> $t { u as $t }
3439
fn to_u8(&self) -> u8 { *self as u8 }
40+
fn to_u32(&self) -> u32 { *self as u32 }
41+
fn to_u64(&self) -> u64 { *self as u64 }
3542
})*)
3643
}
3744
doit! { i8 i16 i32 i64 isize u8 u16 u32 u64 usize }
@@ -188,6 +195,7 @@ macro_rules! radix_fmt {
188195
}
189196
}
190197
}
198+
191199
macro_rules! int_base {
192200
($Trait:ident for $T:ident as $U:ident -> $Radix:ident) => {
193201
#[stable(feature = "rust1", since = "1.0.0")]
@@ -209,17 +217,16 @@ macro_rules! debug {
209217
}
210218
}
211219
}
220+
212221
macro_rules! integer {
213222
($Int:ident, $Uint:ident) => {
214-
int_base! { Display for $Int as $Int -> Decimal }
215223
int_base! { Binary for $Int as $Uint -> Binary }
216224
int_base! { Octal for $Int as $Uint -> Octal }
217225
int_base! { LowerHex for $Int as $Uint -> LowerHex }
218226
int_base! { UpperHex for $Int as $Uint -> UpperHex }
219227
radix_fmt! { $Int as $Int, fmt_int }
220228
debug! { $Int }
221229

222-
int_base! { Display for $Uint as $Uint -> Decimal }
223230
int_base! { Binary for $Uint as $Uint -> Binary }
224231
int_base! { Octal for $Uint as $Uint -> Octal }
225232
int_base! { LowerHex for $Uint as $Uint -> LowerHex }
@@ -233,3 +240,80 @@ integer! { i8, u8 }
233240
integer! { i16, u16 }
234241
integer! { i32, u32 }
235242
integer! { i64, u64 }
243+
244+
const DEC_DIGITS_LUT: &'static[u8] =
245+
b"0001020304050607080910111213141516171819\
246+
2021222324252627282930313233343536373839\
247+
4041424344454647484950515253545556575859\
248+
6061626364656667686970717273747576777879\
249+
8081828384858687888990919293949596979899";
250+
251+
macro_rules! impl_Display {
252+
($($t:ident),*: $conv_fn:ident) => ($(
253+
impl fmt::Display for $t {
254+
#[allow(unused_comparisons)]
255+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
256+
let is_positive = *self >= 0;
257+
let mut n = if is_positive {
258+
self.$conv_fn()
259+
} else {
260+
// convert the negative num to positive by summing 1 to it's 2 complement
261+
(!self.$conv_fn()).wrapping_add(1)
262+
};
263+
let mut buf: [u8; 20] = unsafe { mem::uninitialized() };
264+
let mut curr = buf.len() as isize;
265+
let buf_ptr = buf.as_mut_ptr();
266+
let lut_ptr = DEC_DIGITS_LUT.as_ptr();
267+
268+
unsafe {
269+
// eagerly decode 4 characters at a time
270+
if <$t>::max_value() as u64 >= 10000 {
271+
while n >= 10000 {
272+
let rem = (n % 10000) as isize;
273+
n /= 10000;
274+
275+
let d1 = (rem / 100) << 1;
276+
let d2 = (rem % 100) << 1;
277+
curr -= 4;
278+
ptr::copy_nonoverlapping(lut_ptr.offset(d1), buf_ptr.offset(curr), 2);
279+
ptr::copy_nonoverlapping(lut_ptr.offset(d2), buf_ptr.offset(curr + 2), 2);
280+
}
281+
}
282+
283+
// if we reach here numbers are <= 9999, so at most 4 chars long
284+
let mut n = n as isize; // possibly reduce 64bit math
285+
286+
// decode 2 more chars, if > 2 chars
287+
if n >= 100 {
288+
let d1 = (n % 100) << 1;
289+
n /= 100;
290+
curr -= 2;
291+
ptr::copy_nonoverlapping(lut_ptr.offset(d1), buf_ptr.offset(curr), 2);
292+
}
293+
294+
// decode last 1 or 2 chars
295+
if n < 10 {
296+
curr -= 1;
297+
*buf_ptr.offset(curr) = (n as u8) + 48;
298+
} else {
299+
let d1 = n << 1;
300+
curr -= 2;
301+
ptr::copy_nonoverlapping(lut_ptr.offset(d1), buf_ptr.offset(curr), 2);
302+
}
303+
}
304+
305+
let buf_slice = unsafe {
306+
str::from_utf8_unchecked(
307+
slice::from_raw_parts(buf_ptr.offset(curr), buf.len() - curr as usize))
308+
};
309+
f.pad_integral(is_positive, "", buf_slice)
310+
}
311+
})*);
312+
}
313+
314+
impl_Display!(i8, u8, i16, u16, i32, u32: to_u32);
315+
impl_Display!(i64, u64: to_u64);
316+
#[cfg(target_pointer_width = "32")]
317+
impl_Display!(isize, usize: to_u32);
318+
#[cfg(target_pointer_width = "64")]
319+
impl_Display!(isize, usize: to_u64);

branches/stable/src/libcore/num/mod.rs

Lines changed: 25 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ use mem::size_of;
2424
use option::Option::{self, Some, None};
2525
use result::Result::{self, Ok, Err};
2626
use str::{FromStr, StrExt};
27+
use slice::SliceExt;
2728

2829
/// Provides intentionally-wrapped arithmetic on `T`.
2930
///
@@ -1448,19 +1449,30 @@ fn from_str_radix<T: FromStrRadixHelper>(src: &str, radix: u32)
14481449
-> Result<T, ParseIntError> {
14491450
use self::IntErrorKind::*;
14501451
use self::ParseIntError as PIE;
1452+
14511453
assert!(radix >= 2 && radix <= 36,
14521454
"from_str_radix_int: must lie in the range `[2, 36]` - found {}",
14531455
radix);
14541456

1457+
if src.is_empty() {
1458+
return Err(PIE { kind: Empty });
1459+
}
1460+
14551461
let is_signed_ty = T::from_u32(0) > T::min_value();
14561462

1457-
match src.slice_shift_char() {
1458-
Some(('-', "")) => Err(PIE { kind: Empty }),
1459-
Some(('-', src)) if is_signed_ty => {
1463+
// all valid digits are ascii, so we will just iterate over the utf8 bytes
1464+
// and cast them to chars. .to_digit() will safely return None for anything
1465+
// other than a valid ascii digit for a the given radix, including the first-byte
1466+
// of multi-byte sequences
1467+
let src = src.as_bytes();
1468+
1469+
match (src[0], &src[1..]) {
1470+
(b'-', digits) if digits.is_empty() => Err(PIE { kind: Empty }),
1471+
(b'-', digits) if is_signed_ty => {
14601472
// The number is negative
14611473
let mut result = T::from_u32(0);
1462-
for c in src.chars() {
1463-
let x = match c.to_digit(radix) {
1474+
for &c in digits {
1475+
let x = match (c as char).to_digit(radix) {
14641476
Some(x) => x,
14651477
None => return Err(PIE { kind: InvalidDigit }),
14661478
};
@@ -1475,11 +1487,14 @@ fn from_str_radix<T: FromStrRadixHelper>(src: &str, radix: u32)
14751487
}
14761488
Ok(result)
14771489
},
1478-
Some((_, _)) => {
1490+
(c, digits) => {
14791491
// The number is signed
1480-
let mut result = T::from_u32(0);
1481-
for c in src.chars() {
1482-
let x = match c.to_digit(radix) {
1492+
let mut result = match (c as char).to_digit(radix) {
1493+
Some(x) => T::from_u32(x),
1494+
None => return Err(PIE { kind: InvalidDigit }),
1495+
};
1496+
for &c in digits {
1497+
let x = match (c as char).to_digit(radix) {
14831498
Some(x) => x,
14841499
None => return Err(PIE { kind: InvalidDigit }),
14851500
};
@@ -1493,8 +1508,7 @@ fn from_str_radix<T: FromStrRadixHelper>(src: &str, radix: u32)
14931508
};
14941509
}
14951510
Ok(result)
1496-
},
1497-
None => Err(ParseIntError { kind: Empty }),
1511+
}
14981512
}
14991513
}
15001514

branches/stable/src/libcoretest/num/mod.rs

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,14 @@ mod tests {
117117
}
118118

119119
#[test]
120-
fn test_int_from_minus_sign() {
121-
assert_eq!("-".parse::<i32>().ok(), None);
120+
fn test_invalid() {
121+
assert_eq!("--129".parse::<i8>().ok(), None);
122+
assert_eq!("Съешь".parse::<u8>().ok(), None);
123+
}
124+
125+
#[test]
126+
fn test_empty() {
127+
assert_eq!("-".parse::<i8>().ok(), None);
128+
assert_eq!("".parse::<u8>().ok(), None);
122129
}
123130
}

0 commit comments

Comments
 (0)