(index<- ) ./libstd/num/strconv.rs
git branch: * master 5200215 auto merge of #14035 : alexcrichton/rust/experimental, r=huonw
modified: Fri May 9 13:02:28 2014
1 // Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
4 //
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
10
11 #![allow(missing_doc)]
12
13 use char;
14 use clone::Clone;
15 use container::Container;
16 use iter::Iterator;
17 use num::{NumCast, Zero, One, cast, Int};
18 use num::{Float, FPNaN, FPInfinite, ToPrimitive};
19 use num;
20 use ops::{Add, Sub, Mul, Div, Rem, Neg};
21 use option::{None, Option, Some};
22 use slice::{CloneableVector, ImmutableVector, MutableVector};
23 use std::cmp::{Ord, Eq};
24 use str::{StrAllocating, StrSlice};
25 use strbuf::StrBuf;
26 use vec::Vec;
27
28 /// A flag that specifies whether to use exponential (scientific) notation.
29 pub enum ExponentFormat {
30 /// Do not use exponential notation.
31 ExpNone,
32 /// Use exponential notation with the exponent having a base of 10 and the
33 /// exponent sign being `e` or `E`. For example, 1000 would be printed
34 /// 1e3.
35 ExpDec,
36 /// Use exponential notation with the exponent having a base of 2 and the
37 /// exponent sign being `p` or `P`. For example, 8 would be printed 1p3.
38 ExpBin,
39 }
40
41 /// The number of digits used for emitting the fractional part of a number, if
42 /// any.
43 pub enum SignificantDigits {
44 /// All calculable digits will be printed.
45 ///
46 /// Note that bignums or fractions may cause a surprisingly large number
47 /// of digits to be printed.
48 DigAll,
49
50 /// At most the given number of digits will be printed, truncating any
51 /// trailing zeroes.
52 DigMax(uint),
53
54 /// Precisely the given number of digits will be printed.
55 DigExact(uint)
56 }
57
58 /// How to emit the sign of a number.
59 pub enum SignFormat {
60 /// No sign will be printed. The exponent sign will also be emitted.
61 SignNone,
62 /// `-` will be printed for negative values, but no sign will be emitted
63 /// for positive numbers.
64 SignNeg,
65 /// `+` will be printed for positive values, and `-` will be printed for
66 /// negative values.
67 SignAll,
68 }
69
70 /// Encompasses functions used by the string converter.
71 pub trait NumStrConv {
72 /// Returns the NaN value.
73 fn nan() -> Option<Self>;
74
75 /// Returns the infinite value.
76 fn inf() -> Option<Self>;
77
78 /// Returns the negative infinite value.
79 fn neg_inf() -> Option<Self>;
80
81 /// Returns -0.0.
82 fn neg_zero() -> Option<Self>;
83
84 /// Rounds the number toward zero.
85 fn round_to_zero(&self) -> Self;
86
87 /// Returns the fractional part of the number.
88 fn fractional_part(&self) -> Self;
89 }
90
91 macro_rules! impl_NumStrConv_Floating (($t:ty) => (
92 impl NumStrConv for $t {
93 #[inline]
94 fn nan() -> Option<$t> { Some( 0.0 / 0.0) }
95 #[inline]
96 fn inf() -> Option<$t> { Some( 1.0 / 0.0) }
97 #[inline]
98 fn neg_inf() -> Option<$t> { Some(-1.0 / 0.0) }
99 #[inline]
100 fn neg_zero() -> Option<$t> { Some(-0.0 ) }
101
102 #[inline]
103 fn round_to_zero(&self) -> $t { self.trunc() }
104 #[inline]
105 fn fractional_part(&self) -> $t { self.fract() }
106 }
107 ))
108
109 macro_rules! impl_NumStrConv_Integer (($t:ty) => (
110 impl NumStrConv for $t {
111 #[inline] fn nan() -> Option<$t> { None }
112 #[inline] fn inf() -> Option<$t> { None }
113 #[inline] fn neg_inf() -> Option<$t> { None }
114 #[inline] fn neg_zero() -> Option<$t> { None }
115
116 #[inline] fn round_to_zero(&self) -> $t { *self }
117 #[inline] fn fractional_part(&self) -> $t { 0 }
118 }
119 ))
120
121 // FIXME: #4955
122 // Replace by two generic impls for traits 'Integral' and 'Floating'
123 impl_NumStrConv_Floating!(f32)
124 impl_NumStrConv_Floating!(f64)
125
126 impl_NumStrConv_Integer!(int)
127 impl_NumStrConv_Integer!(i8)
128 impl_NumStrConv_Integer!(i16)
129 impl_NumStrConv_Integer!(i32)
130 impl_NumStrConv_Integer!(i64)
131
132 impl_NumStrConv_Integer!(uint)
133 impl_NumStrConv_Integer!(u8)
134 impl_NumStrConv_Integer!(u16)
135 impl_NumStrConv_Integer!(u32)
136 impl_NumStrConv_Integer!(u64)
137
138
139 // Special value strings as [u8] consts.
140 static INF_BUF: [u8, ..3] = ['i' as u8, 'n' as u8, 'f' as u8];
141 static POS_INF_BUF: [u8, ..4] = ['+' as u8, 'i' as u8, 'n' as u8,
142 'f' as u8];
143 static NEG_INF_BUF: [u8, ..4] = ['-' as u8, 'i' as u8, 'n' as u8,
144 'f' as u8];
145 static NAN_BUF: [u8, ..3] = ['N' as u8, 'a' as u8, 'N' as u8];
146
147 /**
148 * Converts an integral number to its string representation as a byte vector.
149 * This is meant to be a common base implementation for all integral string
150 * conversion functions like `to_str()` or `to_str_radix()`.
151 *
152 * # Arguments
153 * - `num` - The number to convert. Accepts any number that
154 * implements the numeric traits.
155 * - `radix` - Base to use. Accepts only the values 2-36.
156 * - `sign` - How to emit the sign. Options are:
157 * - `SignNone`: No sign at all. Basically emits `abs(num)`.
158 * - `SignNeg`: Only `-` on negative values.
159 * - `SignAll`: Both `+` on positive, and `-` on negative numbers.
160 * - `f` - a callback which will be invoked for each ascii character
161 * which composes the string representation of this integer
162 *
163 * # Return value
164 * A tuple containing the byte vector, and a boolean flag indicating
165 * whether it represents a special value like `inf`, `-inf`, `NaN` or not.
166 * It returns a tuple because there can be ambiguity between a special value
167 * and a number representation at higher bases.
168 *
169 * # Failure
170 * - Fails if `radix` < 2 or `radix` > 36.
171 */
172 pub fn int_to_str_bytes_common<T: Int>(num: T, radix: uint, sign: SignFormat, f: |u8|) {
173 assert!(2 <= radix && radix <= 36);
174
175 let _0: T = Zero::zero();
176
177 let neg = num < _0;
178 let radix_gen: T = cast(radix).unwrap();
179
180 let mut deccum = num;
181 // This is just for integral types, the largest of which is a u64. The
182 // smallest base that we can have is 2, so the most number of digits we're
183 // ever going to have is 64
184 let mut buf = [0u8, ..64];
185 let mut cur = 0;
186
187 // Loop at least once to make sure at least a `0` gets emitted.
188 loop {
189 // Calculate the absolute value of each digit instead of only
190 // doing it once for the whole number because a
191 // representable negative number doesn't necessary have an
192 // representable additive inverse of the same type
193 // (See twos complement). But we assume that for the
194 // numbers [-35 .. 0] we always have [0 .. 35].
195 let current_digit_signed = deccum % radix_gen;
196 let current_digit = if current_digit_signed < _0 {
197 -current_digit_signed
198 } else {
199 current_digit_signed
200 };
201 buf[cur] = match current_digit.to_u8().unwrap() {
202 i @ 0..9 => '0' as u8 + i,
203 i => 'a' as u8 + (i - 10),
204 };
205 cur += 1;
206
207 deccum = deccum / radix_gen;
208 // No more digits to calculate for the non-fractional part -> break
209 if deccum == _0 { break; }
210 }
211
212 // Decide what sign to put in front
213 match sign {
214 SignNeg | SignAll if neg => { f('-' as u8); }
215 SignAll => { f('+' as u8); }
216 _ => ()
217 }
218
219 // We built the number in reverse order, so un-reverse it here
220 while cur > 0 {
221 cur -= 1;
222 f(buf[cur]);
223 }
224 }
225
226 /**
227 * Converts a number to its string representation as a byte vector.
228 * This is meant to be a common base implementation for all numeric string
229 * conversion functions like `to_str()` or `to_str_radix()`.
230 *
231 * # Arguments
232 * - `num` - The number to convert. Accepts any number that
233 * implements the numeric traits.
234 * - `radix` - Base to use. Accepts only the values 2-36. If the exponential notation
235 * is used, then this base is only used for the significand. The exponent
236 * itself always printed using a base of 10.
237 * - `negative_zero` - Whether to treat the special value `-0` as
238 * `-0` or as `+0`.
239 * - `sign` - How to emit the sign. See `SignFormat`.
240 * - `digits` - The amount of digits to use for emitting the fractional
241 * part, if any. See `SignificantDigits`.
242 * - `exp_format` - Whether or not to use the exponential (scientific) notation.
243 * See `ExponentFormat`.
244 * - `exp_capital` - Whether or not to use a capital letter for the exponent sign, if
245 * exponential notation is desired.
246 *
247 * # Return value
248 * A tuple containing the byte vector, and a boolean flag indicating
249 * whether it represents a special value like `inf`, `-inf`, `NaN` or not.
250 * It returns a tuple because there can be ambiguity between a special value
251 * and a number representation at higher bases.
252 *
253 * # Failure
254 * - Fails if `radix` < 2 or `radix` > 36.
255 * - Fails if `radix` > 14 and `exp_format` is `ExpDec` due to conflict
256 * between digit and exponent sign `'e'`.
257 * - Fails if `radix` > 25 and `exp_format` is `ExpBin` due to conflict
258 * between digit and exponent sign `'p'`.
259 */
260 pub fn float_to_str_bytes_common<T:NumCast+Zero+One+Eq+Ord+Float+
261 Div<T,T>+Neg<T>+Rem<T,T>+Mul<T,T>>(
262 num: T, radix: uint, negative_zero: bool,
263 sign: SignFormat, digits: SignificantDigits, exp_format: ExponentFormat, exp_upper: bool
264 ) -> (Vec<u8>, bool) {
265 assert!(2 <= radix && radix <= 36);
266 match exp_format {
267 ExpDec if radix >= DIGIT_E_RADIX // decimal exponent 'e'
268 => fail!("float_to_str_bytes_common: radix {} incompatible with \
269 use of 'e' as decimal exponent", radix),
270 ExpBin if radix >= DIGIT_P_RADIX // binary exponent 'p'
271 => fail!("float_to_str_bytes_common: radix {} incompatible with \
272 use of 'p' as binary exponent", radix),
273 _ => ()
274 }
275
276 let _0: T = Zero::zero();
277 let _1: T = One::one();
278
279 match num.classify() {
280 FPNaN => { return (Vec::from_slice("NaN".as_bytes()), true); }
281 FPInfinite if num > _0 => {
282 return match sign {
283 SignAll => (Vec::from_slice("+inf".as_bytes()), true),
284 _ => (Vec::from_slice("inf".as_bytes()), true)
285 };
286 }
287 FPInfinite if num < _0 => {
288 return match sign {
289 SignNone => (Vec::from_slice("inf".as_bytes()), true),
290 _ => (Vec::from_slice("-inf".as_bytes()), true),
291 };
292 }
293 _ => {}
294 }
295
296 let neg = num < _0 || (negative_zero && _1 / num == Float::neg_infinity());
297 let mut buf = Vec::new();
298 let radix_gen: T = cast(radix as int).unwrap();
299
300 let (num, exp) = match exp_format {
301 ExpNone => (num, 0i32),
302 ExpDec | ExpBin => {
303 if num == _0 {
304 (num, 0i32)
305 } else {
306 let (exp, exp_base) = match exp_format {
307 ExpDec => (num.abs().log10().floor(), cast::<f64, T>(10.0f64).unwrap()),
308 ExpBin => (num.abs().log2().floor(), cast::<f64, T>(2.0f64).unwrap()),
309 ExpNone => unreachable!()
310 };
311
312 (num / exp_base.powf(exp), cast::<T, i32>(exp).unwrap())
313 }
314 }
315 };
316
317 // First emit the non-fractional part, looping at least once to make
318 // sure at least a `0` gets emitted.
319 let mut deccum = num.trunc();
320 loop {
321 // Calculate the absolute value of each digit instead of only
322 // doing it once for the whole number because a
323 // representable negative number doesn't necessary have an
324 // representable additive inverse of the same type
325 // (See twos complement). But we assume that for the
326 // numbers [-35 .. 0] we always have [0 .. 35].
327 let current_digit = (deccum % radix_gen).abs();
328
329 // Decrease the deccumulator one digit at a time
330 deccum = deccum / radix_gen;
331 deccum = deccum.trunc();
332
333 buf.push(char::from_digit(current_digit.to_int().unwrap() as uint, radix)
334 .unwrap() as u8);
335
336 // No more digits to calculate for the non-fractional part -> break
337 if deccum == _0 { break; }
338 }
339
340 // If limited digits, calculate one digit more for rounding.
341 let (limit_digits, digit_count, exact) = match digits {
342 DigAll => (false, 0u, false),
343 DigMax(count) => (true, count+1, false),
344 DigExact(count) => (true, count+1, true)
345 };
346
347 // Decide what sign to put in front
348 match sign {
349 SignNeg | SignAll if neg => {
350 buf.push('-' as u8);
351 }
352 SignAll => {
353 buf.push('+' as u8);
354 }
355 _ => ()
356 }
357
358 buf.reverse();
359
360 // Remember start of the fractional digits.
361 // Points one beyond end of buf if none get generated,
362 // or at the '.' otherwise.
363 let start_fractional_digits = buf.len();
364
365 // Now emit the fractional part, if any
366 deccum = num.fract();
367 if deccum != _0 || (limit_digits && exact && digit_count > 0) {
368 buf.push('.' as u8);
369 let mut dig = 0u;
370
371 // calculate new digits while
372 // - there is no limit and there are digits left
373 // - or there is a limit, it's not reached yet and
374 // - it's exact
375 // - or it's a maximum, and there are still digits left
376 while (!limit_digits && deccum != _0)
377 || (limit_digits && dig < digit_count && (
378 exact
379 || (!exact && deccum != _0)
380 )
381 ) {
382 // Shift first fractional digit into the integer part
383 deccum = deccum * radix_gen;
384
385 // Calculate the absolute value of each digit.
386 // See note in first loop.
387 let current_digit = deccum.trunc().abs();
388
389 buf.push(char::from_digit(
390 current_digit.to_int().unwrap() as uint, radix).unwrap() as u8);
391
392 // Decrease the deccumulator one fractional digit at a time
393 deccum = deccum.fract();
394 dig += 1u;
395 }
396
397 // If digits are limited, and that limit has been reached,
398 // cut off the one extra digit, and depending on its value
399 // round the remaining ones.
400 if limit_digits && dig == digit_count {
401 let ascii2value = |chr: u8| {
402 char::to_digit(chr as char, radix).unwrap()
403 };
404 let value2ascii = |val: uint| {
405 char::from_digit(val, radix).unwrap() as u8
406 };
407
408 let extra_digit = ascii2value(buf.pop().unwrap());
409 if extra_digit >= radix / 2 { // -> need to round
410 let mut i: int = buf.len() as int - 1;
411 loop {
412 // If reached left end of number, have to
413 // insert additional digit:
414 if i < 0
415 || *buf.get(i as uint) == '-' as u8
416 || *buf.get(i as uint) == '+' as u8 {
417 buf.insert((i + 1) as uint, value2ascii(1));
418 break;
419 }
420
421 // Skip the '.'
422 if *buf.get(i as uint) == '.' as u8 { i -= 1; continue; }
423
424 // Either increment the digit,
425 // or set to 0 if max and carry the 1.
426 let current_digit = ascii2value(*buf.get(i as uint));
427 if current_digit < (radix - 1) {
428 *buf.get_mut(i as uint) = value2ascii(current_digit+1);
429 break;
430 } else {
431 *buf.get_mut(i as uint) = value2ascii(0);
432 i -= 1;
433 }
434 }
435 }
436 }
437 }
438
439 // if number of digits is not exact, remove all trailing '0's up to
440 // and including the '.'
441 if !exact {
442 let buf_max_i = buf.len() - 1;
443
444 // index to truncate from
445 let mut i = buf_max_i;
446
447 // discover trailing zeros of fractional part
448 while i > start_fractional_digits && *buf.get(i) == '0' as u8 {
449 i -= 1;
450 }
451
452 // Only attempt to truncate digits if buf has fractional digits
453 if i >= start_fractional_digits {
454 // If buf ends with '.', cut that too.
455 if *buf.get(i) == '.' as u8 { i -= 1 }
456
457 // only resize buf if we actually remove digits
458 if i < buf_max_i {
459 buf = Vec::from_slice(buf.slice(0, i + 1));
460 }
461 }
462 } // If exact and trailing '.', just cut that
463 else {
464 let max_i = buf.len() - 1;
465 if *buf.get(max_i) == '.' as u8 {
466 buf = Vec::from_slice(buf.slice(0, max_i));
467 }
468 }
469
470 match exp_format {
471 ExpNone => (),
472 _ => {
473 buf.push(match exp_format {
474 ExpDec if exp_upper => 'E',
475 ExpDec if !exp_upper => 'e',
476 ExpBin if exp_upper => 'P',
477 ExpBin if !exp_upper => 'p',
478 _ => unreachable!()
479 } as u8);
480
481 int_to_str_bytes_common(exp, 10, sign, |c| buf.push(c));
482 }
483 }
484
485 (buf, false)
486 }
487
488 /**
489 * Converts a number to its string representation. This is a wrapper for
490 * `to_str_bytes_common()`, for details see there.
491 */
492 #[inline]
493 pub fn float_to_str_common<T:NumCast+Zero+One+Eq+Ord+NumStrConv+Float+
494 Div<T,T>+Neg<T>+Rem<T,T>+Mul<T,T>>(
495 num: T, radix: uint, negative_zero: bool,
496 sign: SignFormat, digits: SignificantDigits, exp_format: ExponentFormat, exp_capital: bool
497 ) -> (~str, bool) {
498 let (bytes, special) = float_to_str_bytes_common(num, radix,
499 negative_zero, sign, digits, exp_format, exp_capital);
500 (StrBuf::from_utf8(bytes).unwrap().into_owned(), special)
501 }
502
503 // Some constants for from_str_bytes_common's input validation,
504 // they define minimum radix values for which the character is a valid digit.
505 static DIGIT_P_RADIX: uint = ('p' as uint) - ('a' as uint) + 11u;
506 static DIGIT_I_RADIX: uint = ('i' as uint) - ('a' as uint) + 11u;
507 static DIGIT_E_RADIX: uint = ('e' as uint) - ('a' as uint) + 11u;
508
509 /**
510 * Parses a byte slice as a number. This is meant to
511 * be a common base implementation for all numeric string conversion
512 * functions like `from_str()` or `from_str_radix()`.
513 *
514 * # Arguments
515 * - `buf` - The byte slice to parse.
516 * - `radix` - Which base to parse the number as. Accepts 2-36.
517 * - `negative` - Whether to accept negative numbers.
518 * - `fractional` - Whether to accept numbers with fractional parts.
519 * - `special` - Whether to accept special values like `inf`
520 * and `NaN`. Can conflict with `radix`, see Failure.
521 * - `exponent` - Which exponent format to accept. Options are:
522 * - `ExpNone`: No Exponent, accepts just plain numbers like `42` or
523 * `-8.2`.
524 * - `ExpDec`: Accepts numbers with a decimal exponent like `42e5` or
525 * `8.2E-2`. The exponent string itself is always base 10.
526 * Can conflict with `radix`, see Failure.
527 * - `ExpBin`: Accepts numbers with a binary exponent like `42P-8` or
528 * `FFp128`. The exponent string itself is always base 10.
529 * Can conflict with `radix`, see Failure.
530 * - `empty_zero` - Whether to accept an empty `buf` as a 0 or not.
531 * - `ignore_underscores` - Whether all underscores within the string should
532 * be ignored.
533 *
534 * # Return value
535 * Returns `Some(n)` if `buf` parses to a number n without overflowing, and
536 * `None` otherwise, depending on the constraints set by the remaining
537 * arguments.
538 *
539 * # Failure
540 * - Fails if `radix` < 2 or `radix` > 36.
541 * - Fails if `radix` > 14 and `exponent` is `ExpDec` due to conflict
542 * between digit and exponent sign `'e'`.
543 * - Fails if `radix` > 25 and `exponent` is `ExpBin` due to conflict
544 * between digit and exponent sign `'p'`.
545 * - Fails if `radix` > 18 and `special == true` due to conflict
546 * between digit and lowest first character in `inf` and `NaN`, the `'i'`.
547 */
548 pub fn from_str_bytes_common<T:NumCast+Zero+One+Eq+Ord+Div<T,T>+
549 Mul<T,T>+Sub<T,T>+Neg<T>+Add<T,T>+
550 NumStrConv+Clone>(
551 buf: &[u8], radix: uint, negative: bool, fractional: bool,
552 special: bool, exponent: ExponentFormat, empty_zero: bool,
553 ignore_underscores: bool
554 ) -> Option<T> {
555 match exponent {
556 ExpDec if radix >= DIGIT_E_RADIX // decimal exponent 'e'
557 => fail!("from_str_bytes_common: radix {} incompatible with \
558 use of 'e' as decimal exponent", radix),
559 ExpBin if radix >= DIGIT_P_RADIX // binary exponent 'p'
560 => fail!("from_str_bytes_common: radix {} incompatible with \
561 use of 'p' as binary exponent", radix),
562 _ if special && radix >= DIGIT_I_RADIX // first digit of 'inf'
563 => fail!("from_str_bytes_common: radix {} incompatible with \
564 special values 'inf' and 'NaN'", radix),
565 _ if (radix as int) < 2
566 => fail!("from_str_bytes_common: radix {} to low, \
567 must lie in the range [2, 36]", radix),
568 _ if (radix as int) > 36
569 => fail!("from_str_bytes_common: radix {} to high, \
570 must lie in the range [2, 36]", radix),
571 _ => ()
572 }
573
574 let _0: T = Zero::zero();
575 let _1: T = One::one();
576 let radix_gen: T = cast(radix as int).unwrap();
577
578 let len = buf.len();
579
580 if len == 0 {
581 if empty_zero {
582 return Some(_0);
583 } else {
584 return None;
585 }
586 }
587
588 if special {
589 if buf == INF_BUF || buf == POS_INF_BUF {
590 return NumStrConv::inf();
591 } else if buf == NEG_INF_BUF {
592 if negative {
593 return NumStrConv::neg_inf();
594 } else {
595 return None;
596 }
597 } else if buf == NAN_BUF {
598 return NumStrConv::nan();
599 }
600 }
601
602 let (start, accum_positive) = match buf[0] as char {
603 '-' if !negative => return None,
604 '-' => (1u, false),
605 '+' => (1u, true),
606 _ => (0u, true)
607 };
608
609 // Initialize accumulator with signed zero for floating point parsing to
610 // work
611 let mut accum = if accum_positive { _0.clone() } else { -_1 * _0};
612 let mut last_accum = accum.clone(); // Necessary to detect overflow
613 let mut i = start;
614 let mut exp_found = false;
615
616 // Parse integer part of number
617 while i < len {
618 let c = buf[i] as char;
619
620 match char::to_digit(c, radix) {
621 Some(digit) => {
622 // shift accum one digit left
623 accum = accum * radix_gen.clone();
624
625 // add/subtract current digit depending on sign
626 if accum_positive {
627 accum = accum + cast(digit as int).unwrap();
628 } else {
629 accum = accum - cast(digit as int).unwrap();
630 }
631
632 // Detect overflow by comparing to last value, except
633 // if we've not seen any non-zero digits.
634 if last_accum != _0 {
635 if accum_positive && accum <= last_accum { return NumStrConv::inf(); }
636 if !accum_positive && accum >= last_accum { return NumStrConv::neg_inf(); }
637
638 // Detect overflow by reversing the shift-and-add proccess
639 if accum_positive &&
640 (last_accum != ((accum - cast(digit as int).unwrap())/radix_gen.clone())) {
641 return NumStrConv::inf();
642 }
643 if !accum_positive &&
644 (last_accum != ((accum + cast(digit as int).unwrap())/radix_gen.clone())) {
645 return NumStrConv::neg_inf();
646 }
647 }
648 last_accum = accum.clone();
649 }
650 None => match c {
651 '_' if ignore_underscores => {}
652 'e' | 'E' | 'p' | 'P' => {
653 exp_found = true;
654 break; // start of exponent
655 }
656 '.' if fractional => {
657 i += 1u; // skip the '.'
658 break; // start of fractional part
659 }
660 _ => return None // invalid number
661 }
662 }
663
664 i += 1u;
665 }
666
667 // Parse fractional part of number
668 // Skip if already reached start of exponent
669 if !exp_found {
670 let mut power = _1.clone();
671
672 while i < len {
673 let c = buf[i] as char;
674
675 match char::to_digit(c, radix) {
676 Some(digit) => {
677 // Decrease power one order of magnitude
678 power = power / radix_gen;
679
680 let digit_t: T = cast(digit).unwrap();
681
682 // add/subtract current digit depending on sign
683 if accum_positive {
684 accum = accum + digit_t * power;
685 } else {
686 accum = accum - digit_t * power;
687 }
688
689 // Detect overflow by comparing to last value
690 if accum_positive && accum < last_accum { return NumStrConv::inf(); }
691 if !accum_positive && accum > last_accum { return NumStrConv::neg_inf(); }
692 last_accum = accum.clone();
693 }
694 None => match c {
695 '_' if ignore_underscores => {}
696 'e' | 'E' | 'p' | 'P' => {
697 exp_found = true;
698 break; // start of exponent
699 }
700 _ => return None // invalid number
701 }
702 }
703
704 i += 1u;
705 }
706 }
707
708 // Special case: buf not empty, but does not contain any digit in front
709 // of the exponent sign -> number is empty string
710 if i == start {
711 if empty_zero {
712 return Some(_0);
713 } else {
714 return None;
715 }
716 }
717
718 let mut multiplier = _1.clone();
719
720 if exp_found {
721 let c = buf[i] as char;
722 let base: T = match (c, exponent) {
723 // c is never _ so don't need to handle specially
724 ('e', ExpDec) | ('E', ExpDec) => cast(10u).unwrap(),
725 ('p', ExpBin) | ('P', ExpBin) => cast(2u).unwrap(),
726 _ => return None // char doesn't fit given exponent format
727 };
728
729 // parse remaining bytes as decimal integer,
730 // skipping the exponent char
731 let exp: Option<int> = from_str_bytes_common(
732 buf.slice(i+1, len), 10, true, false, false, ExpNone, false,
733 ignore_underscores);
734
735 match exp {
736 Some(exp_pow) => {
737 multiplier = if exp_pow < 0 {
738 _1 / num::pow(base, (-exp_pow.to_int().unwrap()) as uint)
739 } else {
740 num::pow(base, exp_pow.to_int().unwrap() as uint)
741 }
742 }
743 None => return None // invalid exponent -> invalid number
744 }
745 }
746
747 Some(accum * multiplier)
748 }
749
750 /**
751 * Parses a string as a number. This is a wrapper for
752 * `from_str_bytes_common()`, for details see there.
753 */
754 #[inline]
755 pub fn from_str_common<T:NumCast+Zero+One+Eq+Ord+Div<T,T>+Mul<T,T>+
756 Sub<T,T>+Neg<T>+Add<T,T>+NumStrConv+Clone>(
757 buf: &str, radix: uint, negative: bool, fractional: bool,
758 special: bool, exponent: ExponentFormat, empty_zero: bool,
759 ignore_underscores: bool
760 ) -> Option<T> {
761 from_str_bytes_common(buf.as_bytes(), radix, negative,
762 fractional, special, exponent, empty_zero,
763 ignore_underscores)
764 }
765
766 #[cfg(test)]
767 mod test {
768 use super::*;
769 use option::*;
770
771 #[test]
772 fn from_str_ignore_underscores() {
773 let s : Option<u8> = from_str_common("__1__", 2, false, false, false,
774 ExpNone, false, true);
775 assert_eq!(s, Some(1u8));
776
777 let n : Option<u8> = from_str_common("__1__", 2, false, false, false,
778 ExpNone, false, false);
779 assert_eq!(n, None);
780
781 let f : Option<f32> = from_str_common("_1_._5_e_1_", 10, false, true, false,
782 ExpDec, false, true);
783 assert_eq!(f, Some(1.5e1f32));
784 }
785
786 #[test]
787 fn from_str_issue5770() {
788 // try to parse 0b1_1111_1111 = 511 as a u8. Caused problems
789 // since 255*2+1 == 255 (mod 256) so the overflow wasn't
790 // detected.
791 let n : Option<u8> = from_str_common("111111111", 2, false, false, false,
792 ExpNone, false, false);
793 assert_eq!(n, None);
794 }
795
796 #[test]
797 fn from_str_issue7588() {
798 let u : Option<u8> = from_str_common("1000", 10, false, false, false,
799 ExpNone, false, false);
800 assert_eq!(u, None);
801 let s : Option<i16> = from_str_common("80000", 10, false, false, false,
802 ExpNone, false, false);
803 assert_eq!(s, None);
804 let f : Option<f32> = from_str_common(
805 "10000000000000000000000000000000000000000", 10, false, false, false,
806 ExpNone, false, false);
807 assert_eq!(f, NumStrConv::inf())
808 let fe : Option<f32> = from_str_common("1e40", 10, false, false, false,
809 ExpDec, false, false);
810 assert_eq!(fe, NumStrConv::inf())
811 }
812 }
813
814 #[cfg(test)]
815 mod bench {
816 extern crate test;
817
818 mod uint {
819 use super::test::Bencher;
820 use rand::{XorShiftRng, Rng};
821 use num::ToStrRadix;
822 use realstd::result::ResultUnwrap;
823
824 #[bench]
825 fn to_str_bin(b: &mut Bencher) {
826 let mut rng = XorShiftRng::new().unwrap();
827 b.iter(|| { rng.gen::<uint>().to_str_radix(2); })
828 }
829
830 #[bench]
831 fn to_str_oct(b: &mut Bencher) {
832 let mut rng = XorShiftRng::new().unwrap();
833 b.iter(|| { rng.gen::<uint>().to_str_radix(8); })
834 }
835
836 #[bench]
837 fn to_str_dec(b: &mut Bencher) {
838 let mut rng = XorShiftRng::new().unwrap();
839 b.iter(|| { rng.gen::<uint>().to_str_radix(10); })
840 }
841
842 #[bench]
843 fn to_str_hex(b: &mut Bencher) {
844 let mut rng = XorShiftRng::new().unwrap();
845 b.iter(|| { rng.gen::<uint>().to_str_radix(16); })
846 }
847
848 #[bench]
849 fn to_str_base_36(b: &mut Bencher) {
850 let mut rng = XorShiftRng::new().unwrap();
851 b.iter(|| { rng.gen::<uint>().to_str_radix(36); })
852 }
853 }
854
855 mod int {
856 use super::test::Bencher;
857 use rand::{XorShiftRng, Rng};
858 use num::ToStrRadix;
859 use realstd::result::ResultUnwrap;
860
861 #[bench]
862 fn to_str_bin(b: &mut Bencher) {
863 let mut rng = XorShiftRng::new().unwrap();
864 b.iter(|| { rng.gen::<int>().to_str_radix(2); })
865 }
866
867 #[bench]
868 fn to_str_oct(b: &mut Bencher) {
869 let mut rng = XorShiftRng::new().unwrap();
870 b.iter(|| { rng.gen::<int>().to_str_radix(8); })
871 }
872
873 #[bench]
874 fn to_str_dec(b: &mut Bencher) {
875 let mut rng = XorShiftRng::new().unwrap();
876 b.iter(|| { rng.gen::<int>().to_str_radix(10); })
877 }
878
879 #[bench]
880 fn to_str_hex(b: &mut Bencher) {
881 let mut rng = XorShiftRng::new().unwrap();
882 b.iter(|| { rng.gen::<int>().to_str_radix(16); })
883 }
884
885 #[bench]
886 fn to_str_base_36(b: &mut Bencher) {
887 let mut rng = XorShiftRng::new().unwrap();
888 b.iter(|| { rng.gen::<int>().to_str_radix(36); })
889 }
890 }
891
892 mod f64 {
893 use super::test::Bencher;
894 use rand::{XorShiftRng, Rng};
895 use f64;
896 use realstd::result::ResultUnwrap;
897
898 #[bench]
899 fn float_to_str(b: &mut Bencher) {
900 let mut rng = XorShiftRng::new().unwrap();
901 b.iter(|| { f64::to_str(rng.gen()); })
902 }
903 }
904 }
libstd/num/strconv.rs:42:9-42:9 -enum- definition:
/// any.
pub enum SignificantDigits {
/// All calculable digits will be printed.
references:- 2495: num: T, radix: uint, negative_zero: bool,
496: sign: SignFormat, digits: SignificantDigits, exp_format: ExponentFormat, exp_capital: bool
497: ) -> (~str, bool) {
libstd/num/strconv.rs:547:4-547:4 -fn- definition:
*/
pub fn from_str_bytes_common<T:NumCast+Zero+One+Eq+Ord+Div<T,T>+
Mul<T,T>+Sub<T,T>+Neg<T>+Add<T,T>+
references:- 12760: ) -> Option<T> {
761: from_str_bytes_common(buf.as_bytes(), radix, negative,
762: fractional, special, exponent, empty_zero,
libstd/num/int_macros.rs:
29: pub fn parse_bytes(buf: &[u8], radix: uint) -> Option<$T> {
30: strconv::from_str_bytes_common(buf, radix, true, false, false,
31: strconv::ExpNone, false, false)
libstd/num/uint_macros.rs:
30: pub fn parse_bytes(buf: &[u8], radix: uint) -> Option<$T> {
31: strconv::from_str_bytes_common(buf, radix, false, false, false,
32: strconv::ExpNone, false, false)
libstd/num/int_macros.rs:
29: pub fn parse_bytes(buf: &[u8], radix: uint) -> Option<$T> {
30: strconv::from_str_bytes_common(buf, radix, true, false, false,
31: strconv::ExpNone, false, false)
libstd/num/strconv.rs:28:76-28:76 -enum- definition:
/// A flag that specifies whether to use exponential (scientific) notation.
pub enum ExponentFormat {
/// Do not use exponential notation.
references:- 4262: num: T, radix: uint, negative_zero: bool,
263: sign: SignFormat, digits: SignificantDigits, exp_format: ExponentFormat, exp_upper: bool
264: ) -> (Vec<u8>, bool) {
--
495: num: T, radix: uint, negative_zero: bool,
496: sign: SignFormat, digits: SignificantDigits, exp_format: ExponentFormat, exp_capital: bool
497: ) -> (~str, bool) {
--
551: buf: &[u8], radix: uint, negative: bool, fractional: bool,
552: special: bool, exponent: ExponentFormat, empty_zero: bool,
553: ignore_underscores: bool
--
757: buf: &str, radix: uint, negative: bool, fractional: bool,
758: special: bool, exponent: ExponentFormat, empty_zero: bool,
759: ignore_underscores: bool
libstd/num/strconv.rs:58:38-58:38 -enum- definition:
/// How to emit the sign of a number.
pub enum SignFormat {
/// No sign will be printed. The exponent sign will also be emitted.
references:- 3171: */
172: pub fn int_to_str_bytes_common<T: Int>(num: T, radix: uint, sign: SignFormat, f: |u8|) {
173: assert!(2 <= radix && radix <= 36);
--
495: num: T, radix: uint, negative_zero: bool,
496: sign: SignFormat, digits: SignificantDigits, exp_format: ExponentFormat, exp_capital: bool
497: ) -> (~str, bool) {
libstd/num/strconv.rs:171:4-171:4 -fn- definition:
*/
pub fn int_to_str_bytes_common<T: Int>(num: T, radix: uint, sign: SignFormat, f: |u8|) {
assert!(2 <= radix && radix <= 36);
references:- 21481: int_to_str_bytes_common(exp, 10, sign, |c| buf.push(c));
482: }
libstd/num/int_macros.rs:
68: let mut cur = 0;
69: strconv::int_to_str_bytes_common(n, radix, strconv::SignNeg, |i| {
70: buf[cur] = i;
--
83: let mut buf = ::vec::Vec::new();
84: strconv::int_to_str_bytes_common(*self, radix, strconv::SignNeg, |i| {
85: buf.push(i);
libstd/num/uint_macros.rs:
69: let mut cur = 0;
70: strconv::int_to_str_bytes_common(n, radix, strconv::SignNone, |i| {
71: buf[cur] = i;
--
84: let mut buf = ::vec::Vec::new();
85: strconv::int_to_str_bytes_common(*self, radix, strconv::SignNone, |i| {
86: buf.push(i);
libstd/num/int_macros.rs:
68: let mut cur = 0;
69: strconv::int_to_str_bytes_common(n, radix, strconv::SignNeg, |i| {
70: buf[cur] = i;
libstd/num/strconv.rs:70:56-70:56 -trait- definition:
/// Encompasses functions used by the string converter.
pub trait NumStrConv {
/// Returns the NaN value.
references:- 2191: macro_rules! impl_NumStrConv_Floating (($t:ty) => (
92: impl NumStrConv for $t {
93: #[inline]
--
493: pub fn float_to_str_common<T:NumCast+Zero+One+Eq+Ord+NumStrConv+Float+
494: Div<T,T>+Neg<T>+Rem<T,T>+Mul<T,T>>(
--
755: pub fn from_str_common<T:NumCast+Zero+One+Eq+Ord+Div<T,T>+Mul<T,T>+
756: Sub<T,T>+Neg<T>+Add<T,T>+NumStrConv+Clone>(
757: buf: &str, radix: uint, negative: bool, fractional: bool,
libstd/num/strconv.rs:754:10-754:10 -fn- definition:
pub fn from_str_common<T:NumCast+Zero+One+Eq+Ord+Div<T,T>+Mul<T,T>+
Sub<T,T>+Neg<T>+Add<T,T>+NumStrConv+Clone>(
buf: &str, radix: uint, negative: bool, fractional: bool,
references:- 26libstd/num/int_macros.rs:
36: fn from_str(s: &str) -> Option<$T> {
37: strconv::from_str_common(s, 10u, true, false, false,
38: strconv::ExpNone, false, false)
--
44: fn from_str_radix(s: &str, radix: uint) -> Option<$T> {
45: strconv::from_str_common(s, radix, true, false, false,
46: strconv::ExpNone, false, false)
libstd/num/uint_macros.rs:
45: fn from_str_radix(s: &str, radix: uint) -> Option<$T> {
46: strconv::from_str_common(s, radix, false, false, false,
47: strconv::ExpNone, false, false)
libstd/num/f32.rs:
650: pub fn from_str_hex(num: &str) -> Option<f32> {
651: strconv::from_str_common(num, 16u, true, true, true,
652: strconv::ExpBin, false, false)
--
707: fn from_str_radix(val: &str, rdx: uint) -> Option<f32> {
708: strconv::from_str_common(val, rdx, true, true, false,
709: strconv::ExpNone, false, false)
libstd/num/f64.rs:
691: fn from_str(val: &str) -> Option<f64> {
692: strconv::from_str_common(val, 10u, true, true, true,
693: strconv::ExpDec, false, false)
--
716: fn from_str_radix(val: &str, rdx: uint) -> Option<f64> {
717: strconv::from_str_common(val, rdx, true, true, false,
718: strconv::ExpNone, false, false)
libstd/num/uint_macros.rs:
37: fn from_str(s: &str) -> Option<$T> {
38: strconv::from_str_common(s, 10u, false, false, false,
39: strconv::ExpNone, false, false)
libstd/num/strconv.rs:492:10-492:10 -fn- definition:
pub fn float_to_str_common<T:NumCast+Zero+One+Eq+Ord+NumStrConv+Float+
Div<T,T>+Neg<T>+Rem<T,T>+Mul<T,T>>(
num: T, radix: uint, negative_zero: bool,
references:- 16libstd/num/f32.rs:
595: pub fn to_str_exp_digits(num: f32, dig: uint, upper: bool) -> ~str {
596: let (r, _) = strconv::float_to_str_common(
597: num, 10u, true, strconv::SignNeg, strconv::DigMax(dig), strconv::ExpDec, upper);
--
615: fn to_str_radix(&self, rdx: uint) -> ~str {
616: let (r, special) = strconv::float_to_str_common(
617: *self, rdx, true, strconv::SignNeg, strconv::DigAll, strconv::ExpNone, false);
libstd/num/f64.rs:
521: pub fn to_str(num: f64) -> ~str {
522: let (r, _) = strconv::float_to_str_common(
523: num, 10u, true, strconv::SignNeg, strconv::DigAll, strconv::ExpNone, false);
--
547: pub fn to_str_radix_special(num: f64, rdx: uint) -> (~str, bool) {
548: strconv::float_to_str_common(num, rdx, true,
549: strconv::SignNeg, strconv::DigAll, strconv::ExpNone, false)
--
604: pub fn to_str_exp_digits(num: f64, dig: uint, upper: bool) -> ~str {
605: let (r, _) = strconv::float_to_str_common(
606: num, 10u, true, strconv::SignNeg, strconv::DigMax(dig), strconv::ExpDec, upper);
--
624: fn to_str_radix(&self, rdx: uint) -> ~str {
625: let (r, special) = strconv::float_to_str_common(
626: *self, rdx, true, strconv::SignNeg, strconv::DigAll, strconv::ExpNone, false);
libstd/num/f32.rs:
538: pub fn to_str_radix_special(num: f32, rdx: uint) -> (~str, bool) {
539: strconv::float_to_str_common(num, rdx, true,
540: strconv::SignNeg, strconv::DigAll, strconv::ExpNone, false)