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