]> git.lizzy.rs Git - rust.git/blob - src/libstd/num/strconv.rs
rollup merge of #19577: aidancully/master
[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_docs)]
14
15 pub use self::ExponentFormat::*;
16 pub use self::SignificantDigits::*;
17 pub use self::SignFormat::*;
18
19 use char;
20 use char::Char;
21 use kinds::Copy;
22 use num;
23 use num::{Int, Float, FPNaN, FPInfinite, ToPrimitive};
24 use slice::{SlicePrelude, CloneSliceAllocPrelude};
25 use str::StrPrelude;
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 impl Copy for ExponentFormat {}
43
44 /// The number of digits used for emitting the fractional part of a number, if
45 /// any.
46 pub enum SignificantDigits {
47     /// All calculable digits will be printed.
48     ///
49     /// Note that bignums or fractions may cause a surprisingly large number
50     /// of digits to be printed.
51     DigAll,
52
53     /// At most the given number of digits will be printed, truncating any
54     /// trailing zeroes.
55     DigMax(uint),
56
57     /// Precisely the given number of digits will be printed.
58     DigExact(uint)
59 }
60
61 impl Copy for SignificantDigits {}
62
63 /// How to emit the sign of a number.
64 pub enum SignFormat {
65     /// No sign will be printed. The exponent sign will also be emitted.
66     SignNone,
67     /// `-` will be printed for negative values, but no sign will be emitted
68     /// for positive numbers.
69     SignNeg,
70     /// `+` will be printed for positive values, and `-` will be printed for
71     /// negative values.
72     SignAll,
73 }
74
75 impl Copy for SignFormat {}
76
77 /**
78  * Converts an integral number to its string representation as a byte vector.
79  * This is meant to be a common base implementation for all integral string
80  * conversion functions like `to_string()` or `to_str_radix()`.
81  *
82  * # Arguments
83  * - `num`           - The number to convert. Accepts any number that
84  *                     implements the numeric traits.
85  * - `radix`         - Base to use. Accepts only the values 2-36.
86  * - `sign`          - How to emit the sign. Options are:
87  *     - `SignNone`: No sign at all. Basically emits `abs(num)`.
88  *     - `SignNeg`:  Only `-` on negative values.
89  *     - `SignAll`:  Both `+` on positive, and `-` on negative numbers.
90  * - `f`             - a callback which will be invoked for each ascii character
91  *                     which composes the string representation of this integer
92  *
93  * # Return value
94  * A tuple containing the byte vector, and a boolean flag indicating
95  * whether it represents a special value like `inf`, `-inf`, `NaN` or not.
96  * It returns a tuple because there can be ambiguity between a special value
97  * and a number representation at higher bases.
98  *
99  * # Failure
100  * - Fails if `radix` < 2 or `radix` > 36.
101  */
102 fn int_to_str_bytes_common<T: Int>(num: T, radix: uint, sign: SignFormat, f: |u8|) {
103     assert!(2 <= radix && radix <= 36);
104
105     let _0: T = Int::zero();
106
107     let neg = num < _0;
108     let radix_gen: T = num::cast(radix).unwrap();
109
110     let mut deccum = num;
111     // This is just for integral types, the largest of which is a u64. The
112     // smallest base that we can have is 2, so the most number of digits we're
113     // ever going to have is 64
114     let mut buf = [0u8, ..64];
115     let mut cur = 0;
116
117     // Loop at least once to make sure at least a `0` gets emitted.
118     loop {
119         // Calculate the absolute value of each digit instead of only
120         // doing it once for the whole number because a
121         // representable negative number doesn't necessary have an
122         // representable additive inverse of the same type
123         // (See twos complement). But we assume that for the
124         // numbers [-35 .. 0] we always have [0 .. 35].
125         let current_digit_signed = deccum % radix_gen;
126         let current_digit = if current_digit_signed < _0 {
127             _0 - current_digit_signed
128         } else {
129             current_digit_signed
130         };
131         buf[cur] = match current_digit.to_u8().unwrap() {
132             i @ 0...9 => b'0' + i,
133             i         => b'a' + (i - 10),
134         };
135         cur += 1;
136
137         deccum = deccum / radix_gen;
138         // No more digits to calculate for the non-fractional part -> break
139         if deccum == _0 { break; }
140     }
141
142     // Decide what sign to put in front
143     match sign {
144         SignNeg | SignAll if neg => { f(b'-'); }
145         SignAll => { f(b'+'); }
146         _ => ()
147     }
148
149     // We built the number in reverse order, so un-reverse it here
150     while cur > 0 {
151         cur -= 1;
152         f(buf[cur]);
153     }
154 }
155
156 /// Converts a number to its string representation as a byte vector.
157 /// This is meant to be a common base implementation for all numeric string
158 /// conversion functions like `to_string()` or `to_str_radix()`.
159 ///
160 /// # Arguments
161 ///
162 /// - `num`           - The number to convert. Accepts any number that
163 ///                     implements the numeric traits.
164 /// - `radix`         - Base to use. Accepts only the values 2-36. If the exponential notation
165 ///                     is used, then this base is only used for the significand. The exponent
166 ///                     itself always printed using a base of 10.
167 /// - `negative_zero` - Whether to treat the special value `-0` as
168 ///                     `-0` or as `+0`.
169 /// - `sign`          - How to emit the sign. See `SignFormat`.
170 /// - `digits`        - The amount of digits to use for emitting the fractional
171 ///                     part, if any. See `SignificantDigits`.
172 /// - `exp_format`   - Whether or not to use the exponential (scientific) notation.
173 ///                    See `ExponentFormat`.
174 /// - `exp_capital`   - Whether or not to use a capital letter for the exponent sign, if
175 ///                     exponential notation is desired.
176 ///
177 /// # Return value
178 ///
179 /// A tuple containing the byte vector, and a boolean flag indicating
180 /// whether it represents a special value like `inf`, `-inf`, `NaN` or not.
181 /// It returns a tuple because there can be ambiguity between a special value
182 /// and a number representation at higher bases.
183 ///
184 /// # Panics
185 ///
186 /// - Panics if `radix` < 2 or `radix` > 36.
187 /// - Panics if `radix` > 14 and `exp_format` is `ExpDec` due to conflict
188 ///   between digit and exponent sign `'e'`.
189 /// - Panics if `radix` > 25 and `exp_format` is `ExpBin` due to conflict
190 ///   between digit and exponent sign `'p'`.
191 pub fn float_to_str_bytes_common<T: Float>(
192         num: T, radix: uint, negative_zero: bool,
193         sign: SignFormat, digits: SignificantDigits, exp_format: ExponentFormat, exp_upper: bool
194         ) -> (Vec<u8>, bool) {
195     assert!(2 <= radix && radix <= 36);
196     match exp_format {
197         ExpDec if radix >= DIGIT_E_RADIX       // decimal exponent 'e'
198           => panic!("float_to_str_bytes_common: radix {} incompatible with \
199                     use of 'e' as decimal exponent", radix),
200         ExpBin if radix >= DIGIT_P_RADIX       // binary exponent 'p'
201           => panic!("float_to_str_bytes_common: radix {} incompatible with \
202                     use of 'p' as binary exponent", radix),
203         _ => ()
204     }
205
206     let _0: T = Float::zero();
207     let _1: T = Float::one();
208
209     match num.classify() {
210         FPNaN => { return (b"NaN".to_vec(), true); }
211         FPInfinite if num > _0 => {
212             return match sign {
213                 SignAll => (b"+inf".to_vec(), true),
214                 _       => (b"inf".to_vec(), true)
215             };
216         }
217         FPInfinite if num < _0 => {
218             return match sign {
219                 SignNone => (b"inf".to_vec(), true),
220                 _        => (b"-inf".to_vec(), true),
221             };
222         }
223         _ => {}
224     }
225
226     let neg = num < _0 || (negative_zero && _1 / num == Float::neg_infinity());
227     let mut buf = Vec::new();
228     let radix_gen: T = num::cast(radix as int).unwrap();
229
230     let (num, exp) = match exp_format {
231         ExpNone => (num, 0i32),
232         ExpDec | ExpBin => {
233             if num == _0 {
234                 (num, 0i32)
235             } else {
236                 let (exp, exp_base) = match exp_format {
237                     ExpDec => (num.abs().log10().floor(), num::cast::<f64, T>(10.0f64).unwrap()),
238                     ExpBin => (num.abs().log2().floor(), num::cast::<f64, T>(2.0f64).unwrap()),
239                     ExpNone => unreachable!()
240                 };
241
242                 (num / exp_base.powf(exp), num::cast::<T, i32>(exp).unwrap())
243             }
244         }
245     };
246
247     // First emit the non-fractional part, looping at least once to make
248     // sure at least a `0` gets emitted.
249     let mut deccum = num.trunc();
250     loop {
251         // Calculate the absolute value of each digit instead of only
252         // doing it once for the whole number because a
253         // representable negative number doesn't necessary have an
254         // representable additive inverse of the same type
255         // (See twos complement). But we assume that for the
256         // numbers [-35 .. 0] we always have [0 .. 35].
257         let current_digit = (deccum % radix_gen).abs();
258
259         // Decrease the deccumulator one digit at a time
260         deccum = deccum / radix_gen;
261         deccum = deccum.trunc();
262
263         buf.push(char::from_digit(current_digit.to_int().unwrap() as uint, radix)
264              .unwrap() as u8);
265
266         // No more digits to calculate for the non-fractional part -> break
267         if deccum == _0 { break; }
268     }
269
270     // If limited digits, calculate one digit more for rounding.
271     let (limit_digits, digit_count, exact) = match digits {
272         DigAll          => (false, 0u,      false),
273         DigMax(count)   => (true,  count+1, false),
274         DigExact(count) => (true,  count+1, true)
275     };
276
277     // Decide what sign to put in front
278     match sign {
279         SignNeg | SignAll if neg => {
280             buf.push(b'-');
281         }
282         SignAll => {
283             buf.push(b'+');
284         }
285         _ => ()
286     }
287
288     buf.reverse();
289
290     // Remember start of the fractional digits.
291     // Points one beyond end of buf if none get generated,
292     // or at the '.' otherwise.
293     let start_fractional_digits = buf.len();
294
295     // Now emit the fractional part, if any
296     deccum = num.fract();
297     if deccum != _0 || (limit_digits && exact && digit_count > 0) {
298         buf.push(b'.');
299         let mut dig = 0u;
300
301         // calculate new digits while
302         // - there is no limit and there are digits left
303         // - or there is a limit, it's not reached yet and
304         //   - it's exact
305         //   - or it's a maximum, and there are still digits left
306         while (!limit_digits && deccum != _0)
307            || (limit_digits && dig < digit_count && (
308                    exact
309                 || (!exact && deccum != _0)
310               )
311         ) {
312             // Shift first fractional digit into the integer part
313             deccum = deccum * radix_gen;
314
315             // Calculate the absolute value of each digit.
316             // See note in first loop.
317             let current_digit = deccum.trunc().abs();
318
319             buf.push(char::from_digit(
320                 current_digit.to_int().unwrap() as uint, radix).unwrap() as u8);
321
322             // Decrease the deccumulator one fractional digit at a time
323             deccum = deccum.fract();
324             dig += 1u;
325         }
326
327         // If digits are limited, and that limit has been reached,
328         // cut off the one extra digit, and depending on its value
329         // round the remaining ones.
330         if limit_digits && dig == digit_count {
331             let ascii2value = |chr: u8| {
332                 (chr as char).to_digit(radix).unwrap()
333             };
334             let value2ascii = |val: uint| {
335                 char::from_digit(val, radix).unwrap() as u8
336             };
337
338             let extra_digit = ascii2value(buf.pop().unwrap());
339             if extra_digit >= radix / 2 { // -> need to round
340                 let mut i: int = buf.len() as int - 1;
341                 loop {
342                     // If reached left end of number, have to
343                     // insert additional digit:
344                     if i < 0
345                     || buf[i as uint] == b'-'
346                     || buf[i as uint] == b'+' {
347                         buf.insert((i + 1) as uint, value2ascii(1));
348                         break;
349                     }
350
351                     // Skip the '.'
352                     if buf[i as uint] == b'.' { i -= 1; continue; }
353
354                     // Either increment the digit,
355                     // or set to 0 if max and carry the 1.
356                     let current_digit = ascii2value(buf[i as uint]);
357                     if current_digit < (radix - 1) {
358                         buf[i as uint] = value2ascii(current_digit+1);
359                         break;
360                     } else {
361                         buf[i as uint] = value2ascii(0);
362                         i -= 1;
363                     }
364                 }
365             }
366         }
367     }
368
369     // if number of digits is not exact, remove all trailing '0's up to
370     // and including the '.'
371     if !exact {
372         let buf_max_i = buf.len() - 1;
373
374         // index to truncate from
375         let mut i = buf_max_i;
376
377         // discover trailing zeros of fractional part
378         while i > start_fractional_digits && buf[i] == b'0' {
379             i -= 1;
380         }
381
382         // Only attempt to truncate digits if buf has fractional digits
383         if i >= start_fractional_digits {
384             // If buf ends with '.', cut that too.
385             if buf[i] == b'.' { i -= 1 }
386
387             // only resize buf if we actually remove digits
388             if i < buf_max_i {
389                 buf = buf.slice(0, i + 1).to_vec();
390             }
391         }
392     } // If exact and trailing '.', just cut that
393     else {
394         let max_i = buf.len() - 1;
395         if buf[max_i] == b'.' {
396             buf = buf.slice(0, max_i).to_vec();
397         }
398     }
399
400     match exp_format {
401         ExpNone => (),
402         _ => {
403             buf.push(match exp_format {
404                 ExpDec if exp_upper => 'E',
405                 ExpDec if !exp_upper => 'e',
406                 ExpBin if exp_upper => 'P',
407                 ExpBin if !exp_upper => 'p',
408                 _ => unreachable!()
409             } as u8);
410
411             int_to_str_bytes_common(exp, 10, sign, |c| buf.push(c));
412         }
413     }
414
415     (buf, false)
416 }
417
418 /**
419  * Converts a number to its string representation. This is a wrapper for
420  * `to_str_bytes_common()`, for details see there.
421  */
422 #[inline]
423 pub fn float_to_str_common<T: Float>(
424         num: T, radix: uint, negative_zero: bool,
425         sign: SignFormat, digits: SignificantDigits, exp_format: ExponentFormat, exp_capital: bool
426         ) -> (String, bool) {
427     let (bytes, special) = float_to_str_bytes_common(num, radix,
428                                negative_zero, sign, digits, exp_format, exp_capital);
429     (String::from_utf8(bytes).unwrap(), special)
430 }
431
432 // Some constants for from_str_bytes_common's input validation,
433 // they define minimum radix values for which the character is a valid digit.
434 static DIGIT_P_RADIX: uint = ('p' as uint) - ('a' as uint) + 11u;
435 static DIGIT_E_RADIX: uint = ('e' as uint) - ('a' as uint) + 11u;
436
437 #[cfg(test)]
438 mod tests {
439     use string::ToString;
440
441     #[test]
442     fn test_int_to_str_overflow() {
443         let mut i8_val: i8 = 127_i8;
444         assert_eq!(i8_val.to_string(), "127");
445
446         i8_val += 1 as i8;
447         assert_eq!(i8_val.to_string(), "-128");
448
449         let mut i16_val: i16 = 32_767_i16;
450         assert_eq!(i16_val.to_string(), "32767");
451
452         i16_val += 1 as i16;
453         assert_eq!(i16_val.to_string(), "-32768");
454
455         let mut i32_val: i32 = 2_147_483_647_i32;
456         assert_eq!(i32_val.to_string(), "2147483647");
457
458         i32_val += 1 as i32;
459         assert_eq!(i32_val.to_string(), "-2147483648");
460
461         let mut i64_val: i64 = 9_223_372_036_854_775_807_i64;
462         assert_eq!(i64_val.to_string(), "9223372036854775807");
463
464         i64_val += 1 as i64;
465         assert_eq!(i64_val.to_string(), "-9223372036854775808");
466     }
467 }
468
469 #[cfg(test)]
470 mod bench {
471     extern crate test;
472
473     mod uint {
474         use super::test::Bencher;
475         use rand::{weak_rng, Rng};
476         use std::fmt;
477
478         #[inline]
479         fn to_string(x: uint, base: u8) {
480             format!("{}", fmt::radix(x, base));
481         }
482
483         #[bench]
484         fn to_str_bin(b: &mut Bencher) {
485             let mut rng = weak_rng();
486             b.iter(|| { to_string(rng.gen::<uint>(), 2); })
487         }
488
489         #[bench]
490         fn to_str_oct(b: &mut Bencher) {
491             let mut rng = weak_rng();
492             b.iter(|| { to_string(rng.gen::<uint>(), 8); })
493         }
494
495         #[bench]
496         fn to_str_dec(b: &mut Bencher) {
497             let mut rng = weak_rng();
498             b.iter(|| { to_string(rng.gen::<uint>(), 10); })
499         }
500
501         #[bench]
502         fn to_str_hex(b: &mut Bencher) {
503             let mut rng = weak_rng();
504             b.iter(|| { to_string(rng.gen::<uint>(), 16); })
505         }
506
507         #[bench]
508         fn to_str_base_36(b: &mut Bencher) {
509             let mut rng = weak_rng();
510             b.iter(|| { to_string(rng.gen::<uint>(), 36); })
511         }
512     }
513
514     mod int {
515         use super::test::Bencher;
516         use rand::{weak_rng, Rng};
517         use std::fmt;
518
519         #[inline]
520         fn to_string(x: int, base: u8) {
521             format!("{}", fmt::radix(x, base));
522         }
523
524         #[bench]
525         fn to_str_bin(b: &mut Bencher) {
526             let mut rng = weak_rng();
527             b.iter(|| { to_string(rng.gen::<int>(), 2); })
528         }
529
530         #[bench]
531         fn to_str_oct(b: &mut Bencher) {
532             let mut rng = weak_rng();
533             b.iter(|| { to_string(rng.gen::<int>(), 8); })
534         }
535
536         #[bench]
537         fn to_str_dec(b: &mut Bencher) {
538             let mut rng = weak_rng();
539             b.iter(|| { to_string(rng.gen::<int>(), 10); })
540         }
541
542         #[bench]
543         fn to_str_hex(b: &mut Bencher) {
544             let mut rng = weak_rng();
545             b.iter(|| { to_string(rng.gen::<int>(), 16); })
546         }
547
548         #[bench]
549         fn to_str_base_36(b: &mut Bencher) {
550             let mut rng = weak_rng();
551             b.iter(|| { to_string(rng.gen::<int>(), 36); })
552         }
553     }
554
555     mod f64 {
556         use super::test::Bencher;
557         use rand::{weak_rng, Rng};
558         use f64;
559
560         #[bench]
561         fn float_to_string(b: &mut Bencher) {
562             let mut rng = weak_rng();
563             b.iter(|| { f64::to_string(rng.gen()); })
564         }
565     }
566 }