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