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.
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.
11 #[allow(missing_doc)];
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};
21 use vec::{CopyableVector, ImmutableVector, MutableVector};
23 use num::{NumCast, Zero, One, cast, pow_with_uint, Integer};
24 use num::{Round, Float, FPNaN, FPInfinite};
26 pub enum ExponentFormat {
32 pub enum SignificantDigits {
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>;
50 fn round_to_zero(&self) -> Self;
51 fn fractional_part(&self) -> Self;
54 macro_rules! impl_NumStrConv_Floating (($t:ty) => (
55 impl NumStrConv for $t {
57 fn NaN() -> Option<$t> { Some( 0.0 / 0.0) }
59 fn inf() -> Option<$t> { Some( 1.0 / 0.0) }
61 fn neg_inf() -> Option<$t> { Some(-1.0 / 0.0) }
63 fn neg_zero() -> Option<$t> { Some(-0.0 ) }
66 fn round_to_zero(&self) -> $t { self.trunc() }
68 fn fractional_part(&self) -> $t { self.fract() }
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 }
79 #[inline] fn round_to_zero(&self) -> $t { *self }
80 #[inline] fn fractional_part(&self) -> $t { 0 }
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)
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)
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)
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,
107 static NEG_INF_BUF: [u8, ..4] = ['-' as u8, 'i' as u8, 'n' as u8,
109 static NAN_BUF: [u8, ..3] = ['N' as u8, 'a' as u8, 'N' as u8];
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()`.
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
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.
134 * - Fails if `radix` < 2 or `radix` > 36.
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);
141 let _0: T = Zero::zero();
144 let radix_gen: T = cast(radix);
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];
153 // Loop at least once to make sure at least a `0` gets emitted.
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
167 buf[cur] = match current_digit.to_u8() {
168 i @ 0..9 => '0' as u8 + i,
169 i => 'a' as u8 + (i - 10),
173 deccum = deccum / radix_gen;
174 // No more digits to calculate for the non-fractional part -> break
175 if deccum == _0 { break; }
178 // Decide what sign to put in front
180 SignNeg | SignAll if neg => { f('-' as u8); }
181 SignAll => { f('+' as u8); }
185 // We built the number in reverse order, so un-reverse it here
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()`.
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
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
211 * - `DigMax(uint)`: Maximum N digits, truncating any trailing zeros.
212 * - `DigExact(uint)`: Exactly N digits.
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.
221 * - Fails if `radix` < 2 or `radix` > 36.
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);
229 let _0: T = Zero::zero();
230 let _1: T = One::one();
232 match num.classify() {
233 FPNaN => { return ("NaN".as_bytes().to_owned(), true); }
234 FPInfinite if num > _0 => {
236 SignAll => ("+inf".as_bytes().to_owned(), true),
237 _ => ("inf".as_bytes().to_owned(), true)
240 FPInfinite if num < _0 => {
242 SignNone => ("inf".as_bytes().to_owned(), true),
243 _ => ("-inf".as_bytes().to_owned(), true),
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);
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();
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();
265 // Decrease the deccumulator one digit at a time
266 deccum = deccum / radix_gen;
267 deccum = deccum.trunc();
269 buf.push(char::from_digit(current_digit.to_int() as uint, radix)
272 // No more digits to calculate for the non-fractional part -> break
273 if deccum == _0 { break; }
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)
283 // Decide what sign to put in front
285 SignNeg | SignAll if neg => {
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();
301 // Now emit the fractional part, if any
302 deccum = num.fract();
303 if deccum != _0 || (limit_digits && exact && digit_count > 0) {
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
311 // - or it's a maximum, and there are still digits left
312 while (!limit_digits && deccum != _0)
313 || (limit_digits && dig < digit_count && (
315 || (!exact && deccum != _0)
318 // Shift first fractional digit into the integer part
319 deccum = deccum * radix_gen;
321 // Calculate the absolute value of each digit.
322 // See note in first loop.
323 let current_digit = deccum.trunc().abs();
325 buf.push(char::from_digit(
326 current_digit.to_int() as uint, radix).unwrap() as u8);
328 // Decrease the deccumulator one fractional digit at a time
329 deccum = deccum.fract();
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
340 let value2ascii = |val: uint| {
341 char::from_digit(val, radix).unwrap() as u8
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;
348 // If reached left end of number, have to
349 // insert additional digit:
351 || buf[i] == '-' as u8
352 || buf[i] == '+' as u8 {
353 buf.insert((i + 1) as uint, value2ascii(1));
358 if buf[i] == '.' as u8 { i -= 1; loop; }
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);
367 buf[i] = value2ascii(0);
375 // if number of digits is not exact, remove all trailing '0's up to
376 // and including the '.'
378 let buf_max_i = buf.len() - 1;
380 // index to truncate from
381 let mut i = buf_max_i;
383 // discover trailing zeros of fractional part
384 while i > start_fractional_digits && buf[i] == '0' as u8 {
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 }
393 // only resize buf if we actually remove digits
395 buf = buf.slice(0, i + 1).to_owned();
398 } // If exact and trailing '.', just cut that
400 let max_i = buf.len() - 1;
401 if buf[max_i] == '.' as u8 {
402 buf = buf.slice(0, max_i).to_owned();
410 * Converts a number to its string representation. This is a wrapper for
411 * `to_str_bytes_common()`, for details see there.
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)
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;
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()`.
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
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
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
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'`.
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>+
471 buf: &[u8], radix: uint, negative: bool, fractional: bool,
472 special: bool, exponent: ExponentFormat, empty_zero: bool,
473 ignore_underscores: bool
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),
494 let _0: T = Zero::zero();
495 let _1: T = One::one();
496 let radix_gen: T = cast(radix as int);
509 if buf == INF_BUF || buf == POS_INF_BUF {
510 return NumStrConv::inf();
511 } else if buf == NEG_INF_BUF {
513 return NumStrConv::neg_inf();
517 } else if buf == NAN_BUF {
518 return NumStrConv::NaN();
522 let (start, accum_positive) = match buf[0] as char {
523 '-' if !negative => return None,
529 // Initialize accumulator with signed zero for floating point parsing to
531 let mut accum = if accum_positive { _0.clone() } else { -_1 * _0};
532 let mut last_accum = accum.clone(); // Necessary to detect overflow
534 let mut exp_found = false;
536 // Parse integer part of number
538 let c = buf[i] as char;
540 match char::to_digit(c, radix) {
542 // shift accum one digit left
543 accum = accum * radix_gen.clone();
545 // add/subtract current digit depending on sign
547 accum = accum + cast(digit as int);
549 accum = accum - cast(digit as int);
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; }
558 last_accum = accum.clone();
561 '_' if ignore_underscores => {}
562 'e' | 'E' | 'p' | 'P' => {
564 break; // start of exponent
566 '.' if fractional => {
567 i += 1u; // skip the '.'
568 break; // start of fractional part
570 _ => return None // invalid number
577 // Parse fractional part of number
578 // Skip if already reached start of exponent
580 let mut power = _1.clone();
583 let c = buf[i] as char;
585 match char::to_digit(c, radix) {
587 // Decrease power one order of magnitude
588 power = power / radix_gen;
590 let digit_t: T = cast(digit);
592 // add/subtract current digit depending on sign
594 accum = accum + digit_t * power;
596 accum = accum - digit_t * power;
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();
605 '_' if ignore_underscores => {}
606 'e' | 'E' | 'p' | 'P' => {
608 break; // start of exponent
610 _ => return None // invalid number
618 // Special case: buf not empty, but does not contain any digit in front
619 // of the exponent sign -> number is empty string
628 let mut multiplier = _1.clone();
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
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,
647 multiplier = if exp_pow < 0 {
648 _1 / pow_with_uint::<T>(base, (-exp_pow.to_int()) as uint)
650 pow_with_uint::<T>(base, exp_pow.to_int() as uint)
653 None => return None // invalid exponent -> invalid number
657 Some(accum * multiplier)
661 * Parses a string as a number. This is a wrapper for
662 * `from_str_bytes_common()`, for details see there.
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
671 from_str_bytes_common(buf.as_bytes(), radix, negative,
672 fractional, special, exponent, empty_zero,
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));
687 let n : Option<u8> = from_str_common("__1__", 2, false, false, false,
688 ExpNone, false, false);
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));
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
701 let n : Option<u8> = from_str_common("111111111", 2, false, false, false,
702 ExpNone, false, false);
709 use extra::test::BenchHarness;
710 use rand::{XorShiftRng,RngUtil};
715 fn uint_to_str_rand(bh: &mut BenchHarness) {
716 let mut rng = XorShiftRng::new();
718 uint::to_str(rng.gen());
723 fn float_to_str_rand(bh: &mut BenchHarness) {
724 let mut rng = XorShiftRng::new();
726 float::to_str(rng.gen());