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 use core::cmp::{Ord, Eq};
13 use ops::{Add, Sub, Mul, Div, Neg};
15 use Rem = ops::Modulo;
19 use ops::{Add, Sub, Mul, Div, Rem, Neg};
20 use option::{None, Option, Some};
25 use num::{NumCast, Zero, One, cast, pow_with_uint};
28 pub enum ExponentFormat {
34 pub enum SignificantDigits {
47 fn is_NaN<T:Eq>(num: &T) -> bool {
52 fn is_inf<T:Eq+NumStrConv>(num: &T) -> bool {
53 match NumStrConv::inf() {
60 fn is_neg_inf<T:Eq+NumStrConv>(num: &T) -> bool {
61 match NumStrConv::neg_inf() {
68 fn is_neg_zero<T:Eq+One+Zero+NumStrConv+Div<T,T>>(num: &T) -> bool {
69 let _0: T = Zero::zero();
70 let _1: T = One::one();
72 *num == _0 && is_neg_inf(&(_1 / *num))
75 pub trait NumStrConv {
76 fn NaN() -> Option<Self>;
77 fn inf() -> Option<Self>;
78 fn neg_inf() -> Option<Self>;
79 fn neg_zero() -> Option<Self>;
81 fn round_to_zero(&self) -> Self;
82 fn fractional_part(&self) -> Self;
85 macro_rules! impl_NumStrConv_Floating (($t:ty) => (
86 impl NumStrConv for $t {
88 fn NaN() -> Option<$t> { Some( 0.0 / 0.0) }
90 fn inf() -> Option<$t> { Some( 1.0 / 0.0) }
92 fn neg_inf() -> Option<$t> { Some(-1.0 / 0.0) }
94 fn neg_zero() -> Option<$t> { Some(-0.0 ) }
97 fn round_to_zero(&self) -> $t {
98 ( if *self < 0.0 { f64::ceil(*self as f64) }
99 else { f64::floor(*self as f64) }
104 fn fractional_part(&self) -> $t {
105 *self - self.round_to_zero()
110 macro_rules! impl_NumStrConv_Integer (($t:ty) => (
111 impl NumStrConv for $t {
112 #[inline(always)] fn NaN() -> Option<$t> { None }
113 #[inline(always)] fn inf() -> Option<$t> { None }
114 #[inline(always)] fn neg_inf() -> Option<$t> { None }
115 #[inline(always)] fn neg_zero() -> Option<$t> { None }
117 #[inline(always)] fn round_to_zero(&self) -> $t { *self }
118 #[inline(always)] fn fractional_part(&self) -> $t { 0 }
123 // Replace by two generic impls for traits 'Integral' and 'Floating'
124 impl_NumStrConv_Floating!(float)
125 impl_NumStrConv_Floating!(f32)
126 impl_NumStrConv_Floating!(f64)
128 impl_NumStrConv_Integer!(int)
129 impl_NumStrConv_Integer!(i8)
130 impl_NumStrConv_Integer!(i16)
131 impl_NumStrConv_Integer!(i32)
132 impl_NumStrConv_Integer!(i64)
134 impl_NumStrConv_Integer!(uint)
135 impl_NumStrConv_Integer!(u8)
136 impl_NumStrConv_Integer!(u16)
137 impl_NumStrConv_Integer!(u32)
138 impl_NumStrConv_Integer!(u64)
141 // Special value strings as [u8] consts.
142 static inf_buf: [u8, ..3] = ['i' as u8, 'n' as u8, 'f' as u8];
143 static positive_inf_buf: [u8, ..4] = ['+' as u8, 'i' as u8, 'n' as u8,
145 static negative_inf_buf: [u8, ..4] = ['-' as u8, 'i' as u8, 'n' as u8,
147 static nan_buf: [u8, ..3] = ['N' as u8, 'a' as u8, 'N' as u8];
150 * Converts a number to its string representation as a byte vector.
151 * This is meant to be a common base implementation for all numeric string
152 * conversion functions like `to_str()` or `to_str_radix()`.
155 * - `num` - The number to convert. Accepts any number that
156 * implements the numeric traits.
157 * - `radix` - Base to use. Accepts only the values 2-36.
158 * - `negative_zero` - Whether to treat the special value `-0` as
160 * - `sign` - How to emit the sign. Options are:
161 * - `SignNone`: No sign at all. Basically emits `abs(num)`.
162 * - `SignNeg`: Only `-` on negative values.
163 * - `SignAll`: Both `+` on positive, and `-` on negative numbers.
164 * - `digits` - The amount of digits to use for emitting the
165 * fractional part, if any. Options are:
166 * - `DigAll`: All calculatable digits. Beware of bignums or
168 * - `DigMax(uint)`: Maximum N digits, truncating any trailing zeros.
169 * - `DigExact(uint)`: Exactly N digits.
172 * A tuple containing the byte vector, and a boolean flag indicating
173 * whether it represents a special value like `inf`, `-inf`, `NaN` or not.
174 * It returns a tuple because there can be ambiguity between a special value
175 * and a number representation at higher bases.
178 * - Fails if `radix` < 2 or `radix` > 36.
180 pub fn to_str_bytes_common<T:NumCast+Zero+One+Eq+Ord+NumStrConv+Copy+
181 Div<T,T>+Neg<T>+Rem<T,T>+Mul<T,T>>(
182 num: &T, radix: uint, negative_zero: bool,
183 sign: SignFormat, digits: SignificantDigits) -> (~[u8], bool) {
184 if (radix as int) < 2 {
185 fail!(fmt!("to_str_bytes_common: radix %? to low, \
186 must lie in the range [2, 36]", radix));
187 } else if radix as int > 36 {
188 fail!(fmt!("to_str_bytes_common: radix %? to high, \
189 must lie in the range [2, 36]", radix));
192 let _0: T = Zero::zero();
193 let _1: T = One::one();
196 return (str::to_bytes("NaN"), true);
200 SignAll => (str::to_bytes("+inf"), true),
201 _ => (str::to_bytes("inf"), true)
204 else if is_neg_inf(num) {
206 SignNone => (str::to_bytes("inf"), true),
207 _ => (str::to_bytes("-inf"), true),
211 let neg = *num < _0 || (negative_zero && is_neg_zero(num));
212 let mut buf: ~[u8] = ~[];
213 let radix_gen: T = cast(radix as int);
217 // First emit the non-fractional part, looping at least once to make
218 // sure at least a `0` gets emitted.
219 deccum = num.round_to_zero();
221 // Calculate the absolute value of each digit instead of only
222 // doing it once for the whole number because a
223 // representable negative number doesn't necessary have an
224 // representable additive inverse of the same type
225 // (See twos complement). But we assume that for the
226 // numbers [-35 .. 0] we always have [0 .. 35].
227 let current_digit_signed = deccum % radix_gen;
228 let current_digit = if current_digit_signed < _0 {
229 -current_digit_signed
234 // Decrease the deccumulator one digit at a time
236 deccum = deccum.round_to_zero();
238 buf.push(char::from_digit(current_digit.to_int() as uint, radix)
241 // No more digits to calculate for the non-fractional part -> break
242 if deccum == _0 { break; }
245 // If limited digits, calculate one digit more for rounding.
246 let (limit_digits, digit_count, exact) = match digits {
247 DigAll => (false, 0u, false),
248 DigMax(count) => (true, count+1, false),
249 DigExact(count) => (true, count+1, true)
252 // Decide what sign to put in front
254 SignNeg | SignAll if neg => {
265 // Remember start of the fractional digits.
266 // Points one beyond end of buf if none get generated,
267 // or at the '.' otherwise.
268 let start_fractional_digits = buf.len();
270 // Now emit the fractional part, if any
271 deccum = num.fractional_part();
272 if deccum != _0 || (limit_digits && exact && digit_count > 0) {
276 // calculate new digits while
277 // - there is no limit and there are digits left
278 // - or there is a limit, it's not reached yet and
280 // - or it's a maximum, and there are still digits left
281 while (!limit_digits && deccum != _0)
282 || (limit_digits && dig < digit_count && (
284 || (!exact && deccum != _0)
287 // Shift first fractional digit into the integer part
290 // Calculate the absolute value of each digit.
291 // See note in first loop.
292 let current_digit_signed = deccum.round_to_zero();
293 let current_digit = if current_digit_signed < _0 {
294 -current_digit_signed
299 buf.push(char::from_digit(
300 current_digit.to_int() as uint, radix).unwrap() as u8);
302 // Decrease the deccumulator one fractional digit at a time
303 deccum = deccum.fractional_part();
307 // If digits are limited, and that limit has been reached,
308 // cut off the one extra digit, and depending on its value
309 // round the remaining ones.
310 if limit_digits && dig == digit_count {
311 let ascii2value = |chr: u8| {
312 char::to_digit(chr as char, radix).unwrap() as uint
314 let value2ascii = |val: uint| {
315 char::from_digit(val, radix).unwrap() as u8
318 let extra_digit = ascii2value(buf.pop());
319 if extra_digit >= radix / 2 { // -> need to round
320 let mut i: int = buf.len() as int - 1;
322 // If reached left end of number, have to
323 // insert additional digit:
325 || buf[i] == '-' as u8
326 || buf[i] == '+' as u8 {
327 buf.insert((i + 1) as uint, value2ascii(1));
332 if buf[i] == '.' as u8 { i -= 1; loop; }
334 // Either increment the digit,
335 // or set to 0 if max and carry the 1.
336 let current_digit = ascii2value(buf[i]);
337 if current_digit < (radix - 1) {
338 buf[i] = value2ascii(current_digit+1);
341 buf[i] = value2ascii(0);
349 // if number of digits is not exact, remove all trailing '0's up to
350 // and including the '.'
352 let buf_max_i = buf.len() - 1;
354 // index to truncate from
355 let mut i = buf_max_i;
357 // discover trailing zeros of fractional part
358 while i > start_fractional_digits && buf[i] == '0' as u8 {
362 // Only attempt to truncate digits if buf has fractional digits
363 if i >= start_fractional_digits {
364 // If buf ends with '.', cut that too.
365 if buf[i] == '.' as u8 { i -= 1 }
367 // only resize buf if we actually remove digits
369 buf = buf.slice(0, i + 1).to_owned();
372 } // If exact and trailing '.', just cut that
374 let max_i = buf.len() - 1;
375 if buf[max_i] == '.' as u8 {
376 buf = buf.slice(0, max_i).to_owned();
384 * Converts a number to its string representation. This is a wrapper for
385 * `to_str_bytes_common()`, for details see there.
388 pub fn to_str_common<T:NumCast+Zero+One+Eq+Ord+NumStrConv+Copy+
389 Div<T,T>+Neg<T>+Rem<T,T>+Mul<T,T>>(
390 num: &T, radix: uint, negative_zero: bool,
391 sign: SignFormat, digits: SignificantDigits) -> (~str, bool) {
392 let (bytes, special) = to_str_bytes_common(num, radix,
393 negative_zero, sign, digits);
394 (str::from_bytes(bytes), special)
397 // Some constants for from_str_bytes_common's input validation,
398 // they define minimum radix values for which the character is a valid digit.
399 priv static DIGIT_P_RADIX: uint = ('p' as uint) - ('a' as uint) + 11u;
400 priv static DIGIT_I_RADIX: uint = ('i' as uint) - ('a' as uint) + 11u;
401 priv static DIGIT_E_RADIX: uint = ('e' as uint) - ('a' as uint) + 11u;
404 * Parses a byte slice as a number. This is meant to
405 * be a common base implementation for all numeric string conversion
406 * functions like `from_str()` or `from_str_radix()`.
409 * - `buf` - The byte slice to parse.
410 * - `radix` - Which base to parse the number as. Accepts 2-36.
411 * - `negative` - Whether to accept negative numbers.
412 * - `fractional` - Whether to accept numbers with fractional parts.
413 * - `special` - Whether to accept special values like `inf`
414 * and `NaN`. Can conflict with `radix`, see Failure.
415 * - `exponent` - Which exponent format to accept. Options are:
416 * - `ExpNone`: No Exponent, accepts just plain numbers like `42` or
418 * - `ExpDec`: Accepts numbers with a decimal exponent like `42e5` or
419 * `8.2E-2`. The exponent string itself is always base 10.
420 * Can conflict with `radix`, see Failure.
421 * - `ExpBin`: Accepts numbers with a binary exponent like `42P-8` or
422 * `FFp128`. The exponent string itself is always base 10.
423 * Can conflict with `radix`, see Failure.
424 * - `empty_zero` - Whether to accept a empty `buf` as a 0 or not.
425 * - `ignore_underscores` - Whether all underscores within the string should
429 * Returns `Some(n)` if `buf` parses to a number n without overflowing, and
430 * `None` otherwise, depending on the constraints set by the remaining
434 * - Fails if `radix` < 2 or `radix` > 36.
435 * - Fails if `radix` > 14 and `exponent` is `ExpDec` due to conflict
436 * between digit and exponent sign `'e'`.
437 * - Fails if `radix` > 25 and `exponent` is `ExpBin` due to conflict
438 * between digit and exponent sign `'p'`.
439 * - Fails if `radix` > 18 and `special == true` due to conflict
440 * between digit and lowest first character in `inf` and `NaN`, the `'i'`.
442 pub fn from_str_bytes_common<T:NumCast+Zero+One+Eq+Ord+Copy+Div<T,T>+
443 Mul<T,T>+Sub<T,T>+Neg<T>+Add<T,T>+
445 buf: &[u8], radix: uint, negative: bool, fractional: bool,
446 special: bool, exponent: ExponentFormat, empty_zero: bool,
447 ignore_underscores: bool
450 ExpDec if radix >= DIGIT_E_RADIX // decimal exponent 'e'
451 => fail!(fmt!("from_str_bytes_common: radix %? incompatible with \
452 use of 'e' as decimal exponent", radix)),
453 ExpBin if radix >= DIGIT_P_RADIX // binary exponent 'p'
454 => fail!(fmt!("from_str_bytes_common: radix %? incompatible with \
455 use of 'p' as binary exponent", radix)),
456 _ if special && radix >= DIGIT_I_RADIX // first digit of 'inf'
457 => fail!(fmt!("from_str_bytes_common: radix %? incompatible with \
458 special values 'inf' and 'NaN'", radix)),
459 _ if (radix as int) < 2
460 => fail!(fmt!("from_str_bytes_common: radix %? to low, \
461 must lie in the range [2, 36]", radix)),
462 _ if (radix as int) > 36
463 => fail!(fmt!("from_str_bytes_common: radix %? to high, \
464 must lie in the range [2, 36]", radix)),
468 let _0: T = Zero::zero();
469 let _1: T = One::one();
470 let radix_gen: T = cast(radix as int);
483 if buf == inf_buf || buf == positive_inf_buf {
484 return NumStrConv::inf();
485 } else if buf == negative_inf_buf {
487 return NumStrConv::neg_inf();
491 } else if buf == nan_buf {
492 return NumStrConv::NaN();
496 let (start, accum_positive) = match buf[0] {
497 '-' as u8 if !negative => return None,
498 '-' as u8 => (1u, false),
499 '+' as u8 => (1u, true),
503 // Initialize accumulator with signed zero for floating point parsing to
505 let mut accum = if accum_positive { _0 } else { -_1 * _0};
506 let mut last_accum = accum; // Necessary to detect overflow
508 let mut exp_found = false;
510 // Parse integer part of number
512 let c = buf[i] as char;
514 match char::to_digit(c, radix) {
516 // shift accum one digit left
519 // add/subtract current digit depending on sign
521 accum += cast(digit as int);
523 accum -= cast(digit as int);
526 // Detect overflow by comparing to last value, except
527 // if we've not seen any non-zero digits.
528 if last_accum != _0 {
529 if accum_positive && accum <= last_accum { return None; }
530 if !accum_positive && accum >= last_accum { return None; }
535 '_' if ignore_underscores => {}
536 'e' | 'E' | 'p' | 'P' => {
538 break; // start of exponent
540 '.' if fractional => {
541 i += 1u; // skip the '.'
542 break; // start of fractional part
544 _ => return None // invalid number
551 // Parse fractional part of number
552 // Skip if already reached start of exponent
557 let c = buf[i] as char;
559 match char::to_digit(c, radix) {
561 // Decrease power one order of magnitude
564 let digit_t: T = cast(digit);
566 // add/subtract current digit depending on sign
568 accum += digit_t * power;
570 accum -= digit_t * power;
573 // Detect overflow by comparing to last value
574 if accum_positive && accum < last_accum { return None; }
575 if !accum_positive && accum > last_accum { return None; }
579 '_' if ignore_underscores => {}
580 'e' | 'E' | 'p' | 'P' => {
582 break; // start of exponent
584 _ => return None // invalid number
592 // Special case: buf not empty, but does not contain any digit in front
593 // of the exponent sign -> number is empty string
602 let mut multiplier = _1;
605 let c = buf[i] as char;
606 let base = match (c, exponent) {
607 // c is never _ so don't need to handle specially
608 ('e', ExpDec) | ('E', ExpDec) => 10u,
609 ('p', ExpBin) | ('P', ExpBin) => 2u,
610 _ => return None // char doesn't fit given exponent format
613 // parse remaining bytes as decimal integer,
614 // skipping the exponent char
615 let exp: Option<int> = from_str_bytes_common(
616 buf.slice(i+1, len), 10, true, false, false, ExpNone, false,
621 multiplier = if exp_pow < 0 {
622 _1 / pow_with_uint::<T>(base, (-exp_pow.to_int()) as uint)
624 pow_with_uint::<T>(base, exp_pow.to_int() as uint)
627 None => return None // invalid exponent -> invalid number
631 Some(accum * multiplier)
635 * Parses a string as a number. This is a wrapper for
636 * `from_str_bytes_common()`, for details see there.
639 pub fn from_str_common<T:NumCast+Zero+One+Eq+Ord+Copy+Div<T,T>+Mul<T,T>+
640 Sub<T,T>+Neg<T>+Add<T,T>+NumStrConv>(
641 buf: &str, radix: uint, negative: bool, fractional: bool,
642 special: bool, exponent: ExponentFormat, empty_zero: bool,
643 ignore_underscores: bool
645 from_str_bytes_common(str::to_bytes(buf), radix, negative,
646 fractional, special, exponent, empty_zero,
656 fn from_str_ignore_underscores() {
657 let s : Option<u8> = from_str_common("__1__", 2, false, false, false,
658 ExpNone, false, true);
659 assert_eq!(s, Some(1u8));
661 let n : Option<u8> = from_str_common("__1__", 2, false, false, false,
662 ExpNone, false, false);
665 let f : Option<f32> = from_str_common("_1_._5_e_1_", 10, false, true, false,
666 ExpDec, false, true);
667 assert_eq!(f, Some(1.5e1f32));
671 fn from_str_issue5770() {
672 // try to parse 0b1_1111_1111 = 511 as a u8. Caused problems
673 // since 255*2+1 == 255 (mod 256) so the overflow wasn't
675 let n : Option<u8> = from_str_common("111111111", 2, false, false, false,
676 ExpNone, false, false);