]> git.lizzy.rs Git - rust.git/blob - src/libcore/num/strconv.rs
Revert rename of Div to Quot
[rust.git] / src / libcore / 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 use core::cmp::{Ord, Eq};
12 #[cfg(stage0)]
13 use ops::{Add, Sub, Mul, Div, Neg};
14 #[cfg(stage0)]
15 use Rem = ops::Modulo;
16 #[cfg(stage1)]
17 #[cfg(stage2)]
18 #[cfg(stage3)]
19 use ops::{Add, Sub, Mul, Div, Rem, Neg};
20 use option::{None, Option, Some};
21 use char;
22 use str;
23 use kinds::Copy;
24 use vec;
25 use num::{NumCast, Zero, One, cast, pow_with_uint};
26 use f64;
27
28 pub enum ExponentFormat {
29     ExpNone,
30     ExpDec,
31     ExpBin
32 }
33
34 pub enum SignificantDigits {
35     DigAll,
36     DigMax(uint),
37     DigExact(uint)
38 }
39
40 pub enum SignFormat {
41     SignNone,
42     SignNeg,
43     SignAll
44 }
45
46 #[inline(always)]
47 fn is_NaN<T:Eq>(num: &T) -> bool {
48     *num != *num
49 }
50
51 #[inline(always)]
52 fn is_inf<T:Eq+NumStrConv>(num: &T) -> bool {
53     match NumStrConv::inf() {
54         None    => false,
55         Some(n) => *num == n
56     }
57 }
58
59 #[inline(always)]
60 fn is_neg_inf<T:Eq+NumStrConv>(num: &T) -> bool {
61     match NumStrConv::neg_inf() {
62         None    => false,
63         Some(n) => *num == n
64     }
65 }
66
67 #[inline(always)]
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();
71
72     *num == _0 && is_neg_inf(&(_1 / *num))
73 }
74
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>;
80
81     fn round_to_zero(&self)   -> Self;
82     fn fractional_part(&self) -> Self;
83 }
84
85 macro_rules! impl_NumStrConv_Floating (($t:ty) => (
86     impl NumStrConv for $t {
87         #[inline(always)]
88         fn NaN()      -> Option<$t> { Some( 0.0 / 0.0) }
89         #[inline(always)]
90         fn inf()      -> Option<$t> { Some( 1.0 / 0.0) }
91         #[inline(always)]
92         fn neg_inf()  -> Option<$t> { Some(-1.0 / 0.0) }
93         #[inline(always)]
94         fn neg_zero() -> Option<$t> { Some(-0.0      ) }
95
96         #[inline(always)]
97         fn round_to_zero(&self) -> $t {
98             ( if *self < 0.0 { f64::ceil(*self as f64)  }
99               else           { f64::floor(*self as f64) }
100             ) as $t
101         }
102
103         #[inline(always)]
104         fn fractional_part(&self) -> $t {
105             *self - self.round_to_zero()
106         }
107     }
108 ))
109
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 }
116
117         #[inline(always)] fn round_to_zero(&self)   -> $t { *self }
118         #[inline(always)] 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!(float)
125 impl_NumStrConv_Floating!(f32)
126 impl_NumStrConv_Floating!(f64)
127
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)
133
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)
139
140
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,
144                                       'f' as u8];
145 static negative_inf_buf: [u8, ..4] = ['-' as u8, 'i' as u8, 'n' as u8,
146                                       'f' as u8];
147 static nan_buf:          [u8, ..3] = ['N' as u8, 'a' as u8, 'N' as u8];
148
149 /**
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()`.
153  *
154  * # Arguments
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
159  *                     `-0` or as `+0`.
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
167  *                         fractions!
168  *     - `DigMax(uint)`:   Maximum N digits, truncating any trailing zeros.
169  *     - `DigExact(uint)`: Exactly N digits.
170  *
171  * # Return value
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.
176  *
177  * # Failure
178  * - Fails if `radix` < 2 or `radix` > 36.
179  */
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));
190     }
191
192     let _0: T = Zero::zero();
193     let _1: T = One::one();
194
195     if is_NaN(num) {
196         return (str::to_bytes("NaN"), true);
197     }
198     else if is_inf(num){
199         return match sign {
200             SignAll => (str::to_bytes("+inf"), true),
201             _       => (str::to_bytes("inf"), true)
202         }
203     }
204     else if is_neg_inf(num) {
205         return match sign {
206             SignNone => (str::to_bytes("inf"), true),
207             _        => (str::to_bytes("-inf"), true),
208         }
209     }
210
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);
214
215     let mut deccum;
216
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();
220     loop {
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
230         } else {
231             current_digit_signed
232         };
233
234         // Decrease the deccumulator one digit at a time
235         deccum /= radix_gen;
236         deccum = deccum.round_to_zero();
237
238         buf.push(char::from_digit(current_digit.to_int() as uint, radix)
239              .unwrap() as u8);
240
241         // No more digits to calculate for the non-fractional part -> break
242         if deccum == _0 { break; }
243     }
244
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)
250     };
251
252     // Decide what sign to put in front
253     match sign {
254         SignNeg | SignAll if neg => {
255             buf.push('-' as u8);
256         }
257         SignAll => {
258             buf.push('+' as u8);
259         }
260         _ => ()
261     }
262
263     vec::reverse(buf);
264
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();
269
270     // Now emit the fractional part, if any
271     deccum = num.fractional_part();
272     if deccum != _0 || (limit_digits && exact && digit_count > 0) {
273         buf.push('.' as u8);
274         let mut dig = 0u;
275
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
279         //   - it's exact
280         //   - or it's a maximum, and there are still digits left
281         while (!limit_digits && deccum != _0)
282            || (limit_digits && dig < digit_count && (
283                    exact
284                 || (!exact && deccum != _0)
285               )
286         ) {
287             // Shift first fractional digit into the integer part
288             deccum *= radix_gen;
289
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
295             } else {
296                 current_digit_signed
297             };
298
299             buf.push(char::from_digit(
300                 current_digit.to_int() as uint, radix).unwrap() as u8);
301
302             // Decrease the deccumulator one fractional digit at a time
303             deccum = deccum.fractional_part();
304             dig += 1u;
305         }
306
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
313             };
314             let value2ascii = |val: uint| {
315                 char::from_digit(val, radix).unwrap() as u8
316             };
317
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;
321                 loop {
322                     // If reached left end of number, have to
323                     // insert additional digit:
324                     if i < 0
325                     || buf[i] == '-' as u8
326                     || buf[i] == '+' as u8 {
327                         buf.insert((i + 1) as uint, value2ascii(1));
328                         break;
329                     }
330
331                     // Skip the '.'
332                     if buf[i] == '.' as u8 { i -= 1; loop; }
333
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);
339                         break;
340                     } else {
341                         buf[i] = value2ascii(0);
342                         i -= 1;
343                     }
344                 }
345             }
346         }
347     }
348
349     // if number of digits is not exact, remove all trailing '0's up to
350     // and including the '.'
351     if !exact {
352         let buf_max_i = buf.len() - 1;
353
354         // index to truncate from
355         let mut i = buf_max_i;
356
357         // discover trailing zeros of fractional part
358         while i > start_fractional_digits && buf[i] == '0' as u8 {
359             i -= 1;
360         }
361
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 }
366
367             // only resize buf if we actually remove digits
368             if i < buf_max_i {
369                 buf = buf.slice(0, i + 1).to_owned();
370             }
371         }
372     } // If exact and trailing '.', just cut that
373     else {
374         let max_i = buf.len() - 1;
375         if buf[max_i] == '.' as u8 {
376             buf = buf.slice(0, max_i).to_owned();
377         }
378     }
379
380     (buf, false)
381 }
382
383 /**
384  * Converts a number to its string representation. This is a wrapper for
385  * `to_str_bytes_common()`, for details see there.
386  */
387 #[inline(always)]
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)
395 }
396
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;
402
403 /**
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()`.
407  *
408  * # Arguments
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
417  *                  `-8.2`.
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
426  *                          be ignored.
427  *
428  * # Return value
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
431  * arguments.
432  *
433  * # Failure
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'`.
441  */
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>+
444                                     NumStrConv>(
445         buf: &[u8], radix: uint, negative: bool, fractional: bool,
446         special: bool, exponent: ExponentFormat, empty_zero: bool,
447         ignore_underscores: bool
448         ) -> Option<T> {
449     match exponent {
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)),
465         _ => ()
466     }
467
468     let _0: T = Zero::zero();
469     let _1: T = One::one();
470     let radix_gen: T = cast(radix as int);
471
472     let len = buf.len();
473
474     if len == 0 {
475         if empty_zero {
476             return Some(_0);
477         } else {
478             return None;
479         }
480     }
481
482     if special {
483         if buf == inf_buf || buf == positive_inf_buf {
484             return NumStrConv::inf();
485         } else if buf == negative_inf_buf {
486             if negative {
487                 return NumStrConv::neg_inf();
488             } else {
489                 return None;
490             }
491         } else if buf == nan_buf {
492             return NumStrConv::NaN();
493         }
494     }
495
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),
500        _        => (0u, true)
501     };
502
503     // Initialize accumulator with signed zero for floating point parsing to
504     // work
505     let mut accum      = if accum_positive { _0 } else { -_1 * _0};
506     let mut last_accum = accum; // Necessary to detect overflow
507     let mut i          = start;
508     let mut exp_found  = false;
509
510     // Parse integer part of number
511     while i < len {
512         let c = buf[i] as char;
513
514         match char::to_digit(c, radix) {
515             Some(digit) => {
516                 // shift accum one digit left
517                 accum *= radix_gen;
518
519                 // add/subtract current digit depending on sign
520                 if accum_positive {
521                     accum += cast(digit as int);
522                 } else {
523                     accum -= cast(digit as int);
524                 }
525
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; }
531                 }
532                 last_accum = accum;
533             }
534             None => match c {
535                 '_' if ignore_underscores => {}
536                 'e' | 'E' | 'p' | 'P' => {
537                     exp_found = true;
538                     break;                       // start of exponent
539                 }
540                 '.' if fractional => {
541                     i += 1u;                     // skip the '.'
542                     break;                       // start of fractional part
543                 }
544                 _ => return None                 // invalid number
545             }
546         }
547
548         i += 1u;
549     }
550
551     // Parse fractional part of number
552     // Skip if already reached start of exponent
553     if !exp_found {
554         let mut power = _1;
555
556         while i < len {
557             let c = buf[i] as char;
558
559             match char::to_digit(c, radix) {
560                 Some(digit) => {
561                     // Decrease power one order of magnitude
562                     power /= radix_gen;
563
564                     let digit_t: T = cast(digit);
565
566                     // add/subtract current digit depending on sign
567                     if accum_positive {
568                         accum += digit_t * power;
569                     } else {
570                         accum -= digit_t * power;
571                     }
572
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; }
576                     last_accum = accum;
577                 }
578                 None => match c {
579                     '_' if ignore_underscores => {}
580                     'e' | 'E' | 'p' | 'P' => {
581                         exp_found = true;
582                         break;                   // start of exponent
583                     }
584                     _ => return None             // invalid number
585                 }
586             }
587
588             i += 1u;
589         }
590     }
591
592     // Special case: buf not empty, but does not contain any digit in front
593     // of the exponent sign -> number is empty string
594     if i == start {
595         if empty_zero {
596             return Some(_0);
597         } else {
598             return None;
599         }
600     }
601
602     let mut multiplier = _1;
603
604     if exp_found {
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
611         };
612
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,
617             ignore_underscores);
618
619         match exp {
620             Some(exp_pow) => {
621                 multiplier = if exp_pow < 0 {
622                     _1 / pow_with_uint::<T>(base, (-exp_pow.to_int()) as uint)
623                 } else {
624                     pow_with_uint::<T>(base, exp_pow.to_int() as uint)
625                 }
626             }
627             None => return None // invalid exponent -> invalid number
628         }
629     }
630
631     Some(accum * multiplier)
632 }
633
634 /**
635  * Parses a string as a number. This is a wrapper for
636  * `from_str_bytes_common()`, for details see there.
637  */
638 #[inline(always)]
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
644         ) -> Option<T> {
645     from_str_bytes_common(str::to_bytes(buf), radix, negative,
646                           fractional, special, exponent, empty_zero,
647                           ignore_underscores)
648 }
649
650 #[cfg(test)]
651 mod test {
652     use super::*;
653     use option::*;
654
655     #[test]
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));
660
661         let n : Option<u8> = from_str_common("__1__", 2, false, false, false,
662                                              ExpNone, false, false);
663         assert_eq!(n, None);
664
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));
668     }
669
670     #[test]
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
674         // detected.
675         let n : Option<u8> = from_str_common("111111111", 2, false, false, false,
676                                              ExpNone, false, false);
677         assert_eq!(n, None);
678     }
679 }