2014-01-30 19:29:35 +01:00
|
|
|
// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT
|
2013-02-15 03:29:36 +01:00
|
|
|
// file at the top-level directory of this distribution and at
|
|
|
|
|
// http://rust-lang.org/COPYRIGHT.
|
|
|
|
|
//
|
|
|
|
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
|
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
|
|
|
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
|
|
|
|
// option. This file may not be copied, modified, or distributed
|
|
|
|
|
// except according to those terms.
|
2014-07-21 15:57:14 -07:00
|
|
|
//
|
|
|
|
|
// ignore-lexer-test FIXME #15679
|
2013-02-15 03:29:36 +01:00
|
|
|
|
2014-03-21 18:05:05 -07:00
|
|
|
#![allow(missing_doc)]
|
2013-05-28 16:35:52 -05:00
|
|
|
|
2014-04-17 15:28:14 -07:00
|
|
|
use char;
|
2013-07-02 12:47:32 -07:00
|
|
|
use clone::Clone;
|
2014-07-11 10:12:38 -07:00
|
|
|
use collections::{Collection, MutableSeq};
|
2014-04-17 15:28:14 -07:00
|
|
|
use num::{NumCast, Zero, One, cast, Int};
|
2014-04-18 12:48:48 +10:00
|
|
|
use num::{Float, FPNaN, FPInfinite, ToPrimitive};
|
2014-04-17 15:28:14 -07:00
|
|
|
use num;
|
2013-05-01 15:40:05 +10:00
|
|
|
use ops::{Add, Sub, Mul, Div, Rem, Neg};
|
2013-02-15 03:29:36 +01:00
|
|
|
use option::{None, Option, Some};
|
2014-08-06 18:58:43 -07:00
|
|
|
use slice::{ImmutableSlice, MutableSlice};
|
2014-05-29 17:45:07 -07:00
|
|
|
use std::cmp::{PartialOrd, PartialEq};
|
2014-05-16 10:45:16 -07:00
|
|
|
use str::StrSlice;
|
2014-05-22 16:57:53 -07:00
|
|
|
use string::String;
|
2014-04-17 15:28:14 -07:00
|
|
|
use vec::Vec;
|
2013-02-15 03:29:36 +01:00
|
|
|
|
2014-03-16 15:59:04 -07:00
|
|
|
/// A flag that specifies whether to use exponential (scientific) notation.
|
2013-02-15 03:29:36 +01:00
|
|
|
pub enum ExponentFormat {
|
2014-03-16 15:59:04 -07:00
|
|
|
/// Do not use exponential notation.
|
2013-02-15 03:29:36 +01:00
|
|
|
ExpNone,
|
2014-03-16 15:59:04 -07:00
|
|
|
/// Use exponential notation with the exponent having a base of 10 and the
|
|
|
|
|
/// exponent sign being `e` or `E`. For example, 1000 would be printed
|
|
|
|
|
/// 1e3.
|
2013-02-15 03:29:36 +01:00
|
|
|
ExpDec,
|
2014-03-16 15:59:04 -07:00
|
|
|
/// Use exponential notation with the exponent having a base of 2 and the
|
|
|
|
|
/// exponent sign being `p` or `P`. For example, 8 would be printed 1p3.
|
|
|
|
|
ExpBin,
|
2013-02-15 03:29:36 +01:00
|
|
|
}
|
|
|
|
|
|
2014-03-16 15:59:04 -07:00
|
|
|
/// The number of digits used for emitting the fractional part of a number, if
|
|
|
|
|
/// any.
|
2013-02-15 03:29:36 +01:00
|
|
|
pub enum SignificantDigits {
|
2014-03-16 15:59:04 -07:00
|
|
|
/// All calculable digits will be printed.
|
|
|
|
|
///
|
|
|
|
|
/// Note that bignums or fractions may cause a surprisingly large number
|
|
|
|
|
/// of digits to be printed.
|
2013-02-15 03:29:36 +01:00
|
|
|
DigAll,
|
2014-03-16 15:59:04 -07:00
|
|
|
|
|
|
|
|
/// At most the given number of digits will be printed, truncating any
|
|
|
|
|
/// trailing zeroes.
|
2013-02-15 03:29:36 +01:00
|
|
|
DigMax(uint),
|
2014-03-16 15:59:04 -07:00
|
|
|
|
|
|
|
|
/// Precisely the given number of digits will be printed.
|
2013-02-15 03:29:36 +01:00
|
|
|
DigExact(uint)
|
|
|
|
|
}
|
|
|
|
|
|
2014-03-16 15:59:04 -07:00
|
|
|
/// How to emit the sign of a number.
|
2013-02-15 03:29:36 +01:00
|
|
|
pub enum SignFormat {
|
2014-03-16 15:59:04 -07:00
|
|
|
/// No sign will be printed. The exponent sign will also be emitted.
|
2013-02-15 03:29:36 +01:00
|
|
|
SignNone,
|
2014-03-16 15:59:04 -07:00
|
|
|
/// `-` will be printed for negative values, but no sign will be emitted
|
|
|
|
|
/// for positive numbers.
|
2013-02-15 03:29:36 +01:00
|
|
|
SignNeg,
|
2014-03-16 15:59:04 -07:00
|
|
|
/// `+` will be printed for positive values, and `-` will be printed for
|
|
|
|
|
/// negative values.
|
|
|
|
|
SignAll,
|
2013-02-15 03:29:36 +01:00
|
|
|
}
|
|
|
|
|
|
2014-03-16 15:59:04 -07:00
|
|
|
/// Encompasses functions used by the string converter.
|
2013-02-15 13:39:51 +01:00
|
|
|
pub trait NumStrConv {
|
2014-03-16 15:59:04 -07:00
|
|
|
/// Returns the NaN value.
|
2013-09-19 15:37:34 +10:00
|
|
|
fn nan() -> Option<Self>;
|
2014-03-16 15:59:04 -07:00
|
|
|
|
|
|
|
|
/// Returns the infinite value.
|
2013-03-21 21:20:48 -07:00
|
|
|
fn inf() -> Option<Self>;
|
2014-03-16 15:59:04 -07:00
|
|
|
|
|
|
|
|
/// Returns the negative infinite value.
|
2013-03-21 21:20:48 -07:00
|
|
|
fn neg_inf() -> Option<Self>;
|
2014-03-16 15:59:04 -07:00
|
|
|
|
|
|
|
|
/// Returns -0.0.
|
2013-03-21 21:20:48 -07:00
|
|
|
fn neg_zero() -> Option<Self>;
|
2013-02-15 04:40:32 +01:00
|
|
|
|
2014-03-16 15:59:04 -07:00
|
|
|
/// Rounds the number toward zero.
|
2013-03-21 21:20:48 -07:00
|
|
|
fn round_to_zero(&self) -> Self;
|
2014-03-16 15:59:04 -07:00
|
|
|
|
|
|
|
|
/// Returns the fractional part of the number.
|
2013-03-21 21:20:48 -07:00
|
|
|
fn fractional_part(&self) -> Self;
|
2013-02-15 04:40:32 +01:00
|
|
|
}
|
|
|
|
|
|
2013-02-15 05:40:01 +01:00
|
|
|
macro_rules! impl_NumStrConv_Floating (($t:ty) => (
|
|
|
|
|
impl NumStrConv for $t {
|
2013-06-18 14:45:18 -07:00
|
|
|
#[inline]
|
2013-09-19 15:37:34 +10:00
|
|
|
fn nan() -> Option<$t> { Some( 0.0 / 0.0) }
|
2013-06-18 14:45:18 -07:00
|
|
|
#[inline]
|
2013-03-21 21:20:48 -07:00
|
|
|
fn inf() -> Option<$t> { Some( 1.0 / 0.0) }
|
2013-06-18 14:45:18 -07:00
|
|
|
#[inline]
|
2013-03-21 21:20:48 -07:00
|
|
|
fn neg_inf() -> Option<$t> { Some(-1.0 / 0.0) }
|
2013-06-18 14:45:18 -07:00
|
|
|
#[inline]
|
2013-03-21 21:20:48 -07:00
|
|
|
fn neg_zero() -> Option<$t> { Some(-0.0 ) }
|
2013-02-15 05:40:01 +01:00
|
|
|
|
2013-06-18 14:45:18 -07:00
|
|
|
#[inline]
|
2013-06-28 14:05:10 -07:00
|
|
|
fn round_to_zero(&self) -> $t { self.trunc() }
|
2013-06-18 14:45:18 -07:00
|
|
|
#[inline]
|
2013-06-28 14:05:10 -07:00
|
|
|
fn fractional_part(&self) -> $t { self.fract() }
|
2013-02-15 05:40:01 +01:00
|
|
|
}
|
|
|
|
|
))
|
|
|
|
|
|
|
|
|
|
macro_rules! impl_NumStrConv_Integer (($t:ty) => (
|
|
|
|
|
impl NumStrConv for $t {
|
2013-09-19 15:37:34 +10:00
|
|
|
#[inline] fn nan() -> Option<$t> { None }
|
2013-06-18 14:45:18 -07:00
|
|
|
#[inline] fn inf() -> Option<$t> { None }
|
|
|
|
|
#[inline] fn neg_inf() -> Option<$t> { None }
|
|
|
|
|
#[inline] fn neg_zero() -> Option<$t> { None }
|
2013-02-15 05:40:01 +01:00
|
|
|
|
2013-06-18 14:45:18 -07:00
|
|
|
#[inline] fn round_to_zero(&self) -> $t { *self }
|
|
|
|
|
#[inline] fn fractional_part(&self) -> $t { 0 }
|
2013-02-15 05:40:01 +01:00
|
|
|
}
|
|
|
|
|
))
|
2013-02-15 04:40:32 +01:00
|
|
|
|
2013-02-15 05:40:01 +01:00
|
|
|
// FIXME: #4955
|
|
|
|
|
// Replace by two generic impls for traits 'Integral' and 'Floating'
|
2013-02-15 04:40:32 +01:00
|
|
|
impl_NumStrConv_Floating!(f32)
|
|
|
|
|
impl_NumStrConv_Floating!(f64)
|
|
|
|
|
|
|
|
|
|
impl_NumStrConv_Integer!(int)
|
|
|
|
|
impl_NumStrConv_Integer!(i8)
|
|
|
|
|
impl_NumStrConv_Integer!(i16)
|
|
|
|
|
impl_NumStrConv_Integer!(i32)
|
|
|
|
|
impl_NumStrConv_Integer!(i64)
|
|
|
|
|
|
|
|
|
|
impl_NumStrConv_Integer!(uint)
|
|
|
|
|
impl_NumStrConv_Integer!(u8)
|
|
|
|
|
impl_NumStrConv_Integer!(u16)
|
|
|
|
|
impl_NumStrConv_Integer!(u32)
|
|
|
|
|
impl_NumStrConv_Integer!(u64)
|
|
|
|
|
|
2013-03-22 02:04:13 +01:00
|
|
|
|
|
|
|
|
// Special value strings as [u8] consts.
|
2014-08-06 02:02:50 -04:00
|
|
|
static INF_BUF: [u8, ..3] = [b'i', b'n', b'f'];
|
|
|
|
|
static POS_INF_BUF: [u8, ..4] = [b'+', b'i', b'n', b'f'];
|
|
|
|
|
static NEG_INF_BUF: [u8, ..4] = [b'-', b'i', b'n', b'f'];
|
|
|
|
|
static NAN_BUF: [u8, ..3] = [b'N', b'a', b'N'];
|
2013-03-22 02:04:13 +01:00
|
|
|
|
2013-06-28 14:05:10 -07:00
|
|
|
/**
|
|
|
|
|
* Converts an integral number to its string representation as a byte vector.
|
|
|
|
|
* This is meant to be a common base implementation for all integral string
|
2014-06-21 03:39:03 -07:00
|
|
|
* conversion functions like `to_string()` or `to_str_radix()`.
|
2013-06-28 14:05:10 -07:00
|
|
|
*
|
|
|
|
|
* # Arguments
|
|
|
|
|
* - `num` - The number to convert. Accepts any number that
|
|
|
|
|
* implements the numeric traits.
|
|
|
|
|
* - `radix` - Base to use. Accepts only the values 2-36.
|
|
|
|
|
* - `sign` - How to emit the sign. Options are:
|
|
|
|
|
* - `SignNone`: No sign at all. Basically emits `abs(num)`.
|
|
|
|
|
* - `SignNeg`: Only `-` on negative values.
|
|
|
|
|
* - `SignAll`: Both `+` on positive, and `-` on negative numbers.
|
|
|
|
|
* - `f` - a callback which will be invoked for each ascii character
|
|
|
|
|
* which composes the string representation of this integer
|
|
|
|
|
*
|
|
|
|
|
* # Return value
|
|
|
|
|
* A tuple containing the byte vector, and a boolean flag indicating
|
|
|
|
|
* whether it represents a special value like `inf`, `-inf`, `NaN` or not.
|
|
|
|
|
* It returns a tuple because there can be ambiguity between a special value
|
|
|
|
|
* and a number representation at higher bases.
|
|
|
|
|
*
|
|
|
|
|
* # Failure
|
|
|
|
|
* - Fails if `radix` < 2 or `radix` > 36.
|
|
|
|
|
*/
|
2014-05-10 14:19:26 -07:00
|
|
|
#[deprecated = "format!() and friends should be favored instead"]
|
2014-02-17 07:20:01 +11:00
|
|
|
pub fn int_to_str_bytes_common<T: Int>(num: T, radix: uint, sign: SignFormat, f: |u8|) {
|
2013-06-28 14:05:10 -07:00
|
|
|
assert!(2 <= radix && radix <= 36);
|
|
|
|
|
|
|
|
|
|
let _0: T = Zero::zero();
|
|
|
|
|
|
|
|
|
|
let neg = num < _0;
|
2013-09-15 09:50:17 -07:00
|
|
|
let radix_gen: T = cast(radix).unwrap();
|
2013-06-28 14:05:10 -07:00
|
|
|
|
|
|
|
|
let mut deccum = num;
|
|
|
|
|
// This is just for integral types, the largest of which is a u64. The
|
|
|
|
|
// smallest base that we can have is 2, so the most number of digits we're
|
|
|
|
|
// ever going to have is 64
|
|
|
|
|
let mut buf = [0u8, ..64];
|
|
|
|
|
let mut cur = 0;
|
|
|
|
|
|
|
|
|
|
// Loop at least once to make sure at least a `0` gets emitted.
|
|
|
|
|
loop {
|
|
|
|
|
// Calculate the absolute value of each digit instead of only
|
|
|
|
|
// doing it once for the whole number because a
|
|
|
|
|
// representable negative number doesn't necessary have an
|
|
|
|
|
// representable additive inverse of the same type
|
|
|
|
|
// (See twos complement). But we assume that for the
|
|
|
|
|
// numbers [-35 .. 0] we always have [0 .. 35].
|
|
|
|
|
let current_digit_signed = deccum % radix_gen;
|
|
|
|
|
let current_digit = if current_digit_signed < _0 {
|
|
|
|
|
-current_digit_signed
|
|
|
|
|
} else {
|
|
|
|
|
current_digit_signed
|
|
|
|
|
};
|
2013-09-15 09:50:17 -07:00
|
|
|
buf[cur] = match current_digit.to_u8().unwrap() {
|
2014-09-26 21:13:20 -07:00
|
|
|
i @ 0...9 => b'0' + i,
|
|
|
|
|
i => b'a' + (i - 10),
|
2013-06-28 14:05:10 -07:00
|
|
|
};
|
|
|
|
|
cur += 1;
|
|
|
|
|
|
|
|
|
|
deccum = deccum / radix_gen;
|
|
|
|
|
// No more digits to calculate for the non-fractional part -> break
|
|
|
|
|
if deccum == _0 { break; }
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Decide what sign to put in front
|
|
|
|
|
match sign {
|
2014-08-06 02:02:50 -04:00
|
|
|
SignNeg | SignAll if neg => { f(b'-'); }
|
|
|
|
|
SignAll => { f(b'+'); }
|
2013-06-28 14:05:10 -07:00
|
|
|
_ => ()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// We built the number in reverse order, so un-reverse it here
|
|
|
|
|
while cur > 0 {
|
|
|
|
|
cur -= 1;
|
|
|
|
|
f(buf[cur]);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2013-02-15 03:29:36 +01:00
|
|
|
/**
|
|
|
|
|
* Converts a number to its string representation as a byte vector.
|
|
|
|
|
* This is meant to be a common base implementation for all numeric string
|
2014-06-21 03:39:03 -07:00
|
|
|
* conversion functions like `to_string()` or `to_str_radix()`.
|
2013-02-15 03:29:36 +01:00
|
|
|
*
|
|
|
|
|
* # Arguments
|
|
|
|
|
* - `num` - The number to convert. Accepts any number that
|
|
|
|
|
* implements the numeric traits.
|
2014-01-16 18:24:03 -05:00
|
|
|
* - `radix` - Base to use. Accepts only the values 2-36. If the exponential notation
|
|
|
|
|
* is used, then this base is only used for the significand. The exponent
|
|
|
|
|
* itself always printed using a base of 10.
|
2013-02-15 03:29:36 +01:00
|
|
|
* - `negative_zero` - Whether to treat the special value `-0` as
|
|
|
|
|
* `-0` or as `+0`.
|
2014-03-16 15:59:04 -07:00
|
|
|
* - `sign` - How to emit the sign. See `SignFormat`.
|
|
|
|
|
* - `digits` - The amount of digits to use for emitting the fractional
|
|
|
|
|
* part, if any. See `SignificantDigits`.
|
2014-01-16 18:24:03 -05:00
|
|
|
* - `exp_format` - Whether or not to use the exponential (scientific) notation.
|
2014-03-16 15:59:04 -07:00
|
|
|
* See `ExponentFormat`.
|
2014-01-16 18:24:03 -05:00
|
|
|
* - `exp_capital` - Whether or not to use a capital letter for the exponent sign, if
|
|
|
|
|
* exponential notation is desired.
|
2013-02-15 03:29:36 +01:00
|
|
|
*
|
|
|
|
|
* # Return value
|
|
|
|
|
* A tuple containing the byte vector, and a boolean flag indicating
|
|
|
|
|
* whether it represents a special value like `inf`, `-inf`, `NaN` or not.
|
|
|
|
|
* It returns a tuple because there can be ambiguity between a special value
|
|
|
|
|
* and a number representation at higher bases.
|
|
|
|
|
*
|
|
|
|
|
* # Failure
|
|
|
|
|
* - Fails if `radix` < 2 or `radix` > 36.
|
2014-01-16 18:24:03 -05:00
|
|
|
* - Fails if `radix` > 14 and `exp_format` is `ExpDec` due to conflict
|
|
|
|
|
* between digit and exponent sign `'e'`.
|
|
|
|
|
* - Fails if `radix` > 25 and `exp_format` is `ExpBin` due to conflict
|
|
|
|
|
* between digit and exponent sign `'p'`.
|
2013-02-15 03:29:36 +01:00
|
|
|
*/
|
2014-05-10 14:19:26 -07:00
|
|
|
#[allow(deprecated)]
|
2014-05-29 17:45:07 -07:00
|
|
|
pub fn float_to_str_bytes_common<T:NumCast+Zero+One+PartialEq+PartialOrd+Float+
|
2013-05-01 15:40:05 +10:00
|
|
|
Div<T,T>+Neg<T>+Rem<T,T>+Mul<T,T>>(
|
2013-06-28 14:05:10 -07:00
|
|
|
num: T, radix: uint, negative_zero: bool,
|
2014-01-16 18:24:03 -05:00
|
|
|
sign: SignFormat, digits: SignificantDigits, exp_format: ExponentFormat, exp_upper: bool
|
2014-05-03 22:02:59 -07:00
|
|
|
) -> (Vec<u8>, bool) {
|
2013-06-28 14:05:10 -07:00
|
|
|
assert!(2 <= radix && radix <= 36);
|
2014-01-16 18:24:03 -05:00
|
|
|
match exp_format {
|
|
|
|
|
ExpDec if radix >= DIGIT_E_RADIX // decimal exponent 'e'
|
|
|
|
|
=> fail!("float_to_str_bytes_common: radix {} incompatible with \
|
|
|
|
|
use of 'e' as decimal exponent", radix),
|
|
|
|
|
ExpBin if radix >= DIGIT_P_RADIX // binary exponent 'p'
|
|
|
|
|
=> fail!("float_to_str_bytes_common: radix {} incompatible with \
|
|
|
|
|
use of 'p' as binary exponent", radix),
|
|
|
|
|
_ => ()
|
|
|
|
|
}
|
2013-02-15 03:29:36 +01:00
|
|
|
|
|
|
|
|
let _0: T = Zero::zero();
|
|
|
|
|
let _1: T = One::one();
|
|
|
|
|
|
2013-06-28 14:05:10 -07:00
|
|
|
match num.classify() {
|
2014-05-03 22:02:59 -07:00
|
|
|
FPNaN => { return (Vec::from_slice("NaN".as_bytes()), true); }
|
2013-06-28 14:05:10 -07:00
|
|
|
FPInfinite if num > _0 => {
|
|
|
|
|
return match sign {
|
2014-05-03 22:02:59 -07:00
|
|
|
SignAll => (Vec::from_slice("+inf".as_bytes()), true),
|
|
|
|
|
_ => (Vec::from_slice("inf".as_bytes()), true)
|
2013-06-28 14:05:10 -07:00
|
|
|
};
|
2013-02-15 05:20:36 +01:00
|
|
|
}
|
2013-06-28 14:05:10 -07:00
|
|
|
FPInfinite if num < _0 => {
|
|
|
|
|
return match sign {
|
2014-05-03 22:02:59 -07:00
|
|
|
SignNone => (Vec::from_slice("inf".as_bytes()), true),
|
|
|
|
|
_ => (Vec::from_slice("-inf".as_bytes()), true),
|
2013-06-28 14:05:10 -07:00
|
|
|
};
|
2013-02-15 03:29:36 +01:00
|
|
|
}
|
2013-06-28 14:05:10 -07:00
|
|
|
_ => {}
|
2013-02-15 03:29:36 +01:00
|
|
|
}
|
|
|
|
|
|
2013-06-28 14:05:10 -07:00
|
|
|
let neg = num < _0 || (negative_zero && _1 / num == Float::neg_infinity());
|
2014-04-17 15:28:14 -07:00
|
|
|
let mut buf = Vec::new();
|
2013-09-15 09:50:17 -07:00
|
|
|
let radix_gen: T = cast(radix as int).unwrap();
|
2013-02-15 03:29:36 +01:00
|
|
|
|
2014-01-16 18:24:03 -05:00
|
|
|
let (num, exp) = match exp_format {
|
|
|
|
|
ExpNone => (num, 0i32),
|
|
|
|
|
ExpDec | ExpBin => {
|
|
|
|
|
if num == _0 {
|
|
|
|
|
(num, 0i32)
|
|
|
|
|
} else {
|
|
|
|
|
let (exp, exp_base) = match exp_format {
|
|
|
|
|
ExpDec => (num.abs().log10().floor(), cast::<f64, T>(10.0f64).unwrap()),
|
|
|
|
|
ExpBin => (num.abs().log2().floor(), cast::<f64, T>(2.0f64).unwrap()),
|
|
|
|
|
ExpNone => unreachable!()
|
|
|
|
|
};
|
|
|
|
|
|
2014-04-18 13:49:37 +10:00
|
|
|
(num / exp_base.powf(exp), cast::<T, i32>(exp).unwrap())
|
2014-01-16 18:24:03 -05:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
2013-02-15 03:29:36 +01:00
|
|
|
// First emit the non-fractional part, looping at least once to make
|
|
|
|
|
// sure at least a `0` gets emitted.
|
2013-06-28 14:05:10 -07:00
|
|
|
let mut deccum = num.trunc();
|
2013-02-15 03:29:36 +01:00
|
|
|
loop {
|
|
|
|
|
// Calculate the absolute value of each digit instead of only
|
|
|
|
|
// doing it once for the whole number because a
|
|
|
|
|
// representable negative number doesn't necessary have an
|
|
|
|
|
// representable additive inverse of the same type
|
|
|
|
|
// (See twos complement). But we assume that for the
|
|
|
|
|
// numbers [-35 .. 0] we always have [0 .. 35].
|
2013-06-28 14:05:10 -07:00
|
|
|
let current_digit = (deccum % radix_gen).abs();
|
2013-02-15 03:29:36 +01:00
|
|
|
|
|
|
|
|
// Decrease the deccumulator one digit at a time
|
2013-06-15 20:26:59 -04:00
|
|
|
deccum = deccum / radix_gen;
|
2013-06-28 14:05:10 -07:00
|
|
|
deccum = deccum.trunc();
|
2013-02-15 03:29:36 +01:00
|
|
|
|
2013-09-15 09:50:17 -07:00
|
|
|
buf.push(char::from_digit(current_digit.to_int().unwrap() as uint, radix)
|
2013-04-08 16:50:34 -04:00
|
|
|
.unwrap() as u8);
|
2013-02-15 03:29:36 +01:00
|
|
|
|
|
|
|
|
// No more digits to calculate for the non-fractional part -> break
|
|
|
|
|
if deccum == _0 { break; }
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// If limited digits, calculate one digit more for rounding.
|
|
|
|
|
let (limit_digits, digit_count, exact) = match digits {
|
|
|
|
|
DigAll => (false, 0u, false),
|
|
|
|
|
DigMax(count) => (true, count+1, false),
|
|
|
|
|
DigExact(count) => (true, count+1, true)
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// Decide what sign to put in front
|
|
|
|
|
match sign {
|
|
|
|
|
SignNeg | SignAll if neg => {
|
2014-08-06 02:02:50 -04:00
|
|
|
buf.push(b'-');
|
2013-02-15 03:29:36 +01:00
|
|
|
}
|
|
|
|
|
SignAll => {
|
2014-08-06 02:02:50 -04:00
|
|
|
buf.push(b'+');
|
2013-02-15 03:29:36 +01:00
|
|
|
}
|
|
|
|
|
_ => ()
|
|
|
|
|
}
|
|
|
|
|
|
2013-06-29 02:54:03 +10:00
|
|
|
buf.reverse();
|
2013-02-15 03:29:36 +01:00
|
|
|
|
|
|
|
|
// Remember start of the fractional digits.
|
|
|
|
|
// Points one beyond end of buf if none get generated,
|
|
|
|
|
// or at the '.' otherwise.
|
|
|
|
|
let start_fractional_digits = buf.len();
|
|
|
|
|
|
|
|
|
|
// Now emit the fractional part, if any
|
2013-06-28 14:05:10 -07:00
|
|
|
deccum = num.fract();
|
2013-02-15 03:29:36 +01:00
|
|
|
if deccum != _0 || (limit_digits && exact && digit_count > 0) {
|
2014-08-06 02:02:50 -04:00
|
|
|
buf.push(b'.');
|
2013-02-15 03:29:36 +01:00
|
|
|
let mut dig = 0u;
|
|
|
|
|
|
|
|
|
|
// calculate new digits while
|
|
|
|
|
// - there is no limit and there are digits left
|
|
|
|
|
// - or there is a limit, it's not reached yet and
|
|
|
|
|
// - it's exact
|
|
|
|
|
// - or it's a maximum, and there are still digits left
|
|
|
|
|
while (!limit_digits && deccum != _0)
|
|
|
|
|
|| (limit_digits && dig < digit_count && (
|
|
|
|
|
exact
|
|
|
|
|
|| (!exact && deccum != _0)
|
|
|
|
|
)
|
|
|
|
|
) {
|
|
|
|
|
// Shift first fractional digit into the integer part
|
2013-06-15 20:26:59 -04:00
|
|
|
deccum = deccum * radix_gen;
|
2013-02-15 03:29:36 +01:00
|
|
|
|
|
|
|
|
// Calculate the absolute value of each digit.
|
|
|
|
|
// See note in first loop.
|
2013-06-28 14:05:10 -07:00
|
|
|
let current_digit = deccum.trunc().abs();
|
2013-02-15 03:29:36 +01:00
|
|
|
|
2013-04-08 16:50:34 -04:00
|
|
|
buf.push(char::from_digit(
|
2013-09-15 09:50:17 -07:00
|
|
|
current_digit.to_int().unwrap() as uint, radix).unwrap() as u8);
|
2013-02-15 03:29:36 +01:00
|
|
|
|
|
|
|
|
// Decrease the deccumulator one fractional digit at a time
|
2013-06-28 14:05:10 -07:00
|
|
|
deccum = deccum.fract();
|
2013-02-15 03:29:36 +01:00
|
|
|
dig += 1u;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// If digits are limited, and that limit has been reached,
|
|
|
|
|
// cut off the one extra digit, and depending on its value
|
|
|
|
|
// round the remaining ones.
|
|
|
|
|
if limit_digits && dig == digit_count {
|
|
|
|
|
let ascii2value = |chr: u8| {
|
2013-12-25 00:53:05 +01:00
|
|
|
char::to_digit(chr as char, radix).unwrap()
|
2013-02-15 03:29:36 +01:00
|
|
|
};
|
|
|
|
|
let value2ascii = |val: uint| {
|
|
|
|
|
char::from_digit(val, radix).unwrap() as u8
|
|
|
|
|
};
|
|
|
|
|
|
2013-12-23 16:20:52 +01:00
|
|
|
let extra_digit = ascii2value(buf.pop().unwrap());
|
2013-04-08 16:50:34 -04:00
|
|
|
if extra_digit >= radix / 2 { // -> need to round
|
|
|
|
|
let mut i: int = buf.len() as int - 1;
|
|
|
|
|
loop {
|
|
|
|
|
// If reached left end of number, have to
|
|
|
|
|
// insert additional digit:
|
|
|
|
|
if i < 0
|
2014-08-06 02:02:50 -04:00
|
|
|
|| *buf.get(i as uint) == b'-'
|
|
|
|
|
|| *buf.get(i as uint) == b'+' {
|
2013-04-08 16:50:34 -04:00
|
|
|
buf.insert((i + 1) as uint, value2ascii(1));
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Skip the '.'
|
2014-08-06 02:02:50 -04:00
|
|
|
if *buf.get(i as uint) == b'.' { i -= 1; continue; }
|
2013-04-08 16:50:34 -04:00
|
|
|
|
|
|
|
|
// Either increment the digit,
|
|
|
|
|
// or set to 0 if max and carry the 1.
|
2014-04-17 15:28:14 -07:00
|
|
|
let current_digit = ascii2value(*buf.get(i as uint));
|
2013-04-08 16:50:34 -04:00
|
|
|
if current_digit < (radix - 1) {
|
2014-04-17 15:28:14 -07:00
|
|
|
*buf.get_mut(i as uint) = value2ascii(current_digit+1);
|
2013-04-08 16:50:34 -04:00
|
|
|
break;
|
|
|
|
|
} else {
|
2014-04-17 15:28:14 -07:00
|
|
|
*buf.get_mut(i as uint) = value2ascii(0);
|
2013-04-08 16:50:34 -04:00
|
|
|
i -= 1;
|
2013-02-15 03:29:36 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// if number of digits is not exact, remove all trailing '0's up to
|
|
|
|
|
// and including the '.'
|
|
|
|
|
if !exact {
|
|
|
|
|
let buf_max_i = buf.len() - 1;
|
|
|
|
|
|
|
|
|
|
// index to truncate from
|
|
|
|
|
let mut i = buf_max_i;
|
|
|
|
|
|
|
|
|
|
// discover trailing zeros of fractional part
|
2014-08-06 02:02:50 -04:00
|
|
|
while i > start_fractional_digits && *buf.get(i) == b'0' {
|
2013-02-15 03:29:36 +01:00
|
|
|
i -= 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Only attempt to truncate digits if buf has fractional digits
|
|
|
|
|
if i >= start_fractional_digits {
|
|
|
|
|
// If buf ends with '.', cut that too.
|
2014-08-06 02:02:50 -04:00
|
|
|
if *buf.get(i) == b'.' { i -= 1 }
|
2013-02-15 03:29:36 +01:00
|
|
|
|
|
|
|
|
// only resize buf if we actually remove digits
|
|
|
|
|
if i < buf_max_i {
|
2014-04-17 15:28:14 -07:00
|
|
|
buf = Vec::from_slice(buf.slice(0, i + 1));
|
2013-02-15 03:29:36 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} // If exact and trailing '.', just cut that
|
|
|
|
|
else {
|
|
|
|
|
let max_i = buf.len() - 1;
|
2014-08-06 02:02:50 -04:00
|
|
|
if *buf.get(max_i) == b'.' {
|
2014-04-17 15:28:14 -07:00
|
|
|
buf = Vec::from_slice(buf.slice(0, max_i));
|
2013-02-15 03:29:36 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2014-01-16 18:24:03 -05:00
|
|
|
match exp_format {
|
|
|
|
|
ExpNone => (),
|
|
|
|
|
_ => {
|
|
|
|
|
buf.push(match exp_format {
|
|
|
|
|
ExpDec if exp_upper => 'E',
|
|
|
|
|
ExpDec if !exp_upper => 'e',
|
|
|
|
|
ExpBin if exp_upper => 'P',
|
|
|
|
|
ExpBin if !exp_upper => 'p',
|
|
|
|
|
_ => unreachable!()
|
|
|
|
|
} as u8);
|
|
|
|
|
|
|
|
|
|
int_to_str_bytes_common(exp, 10, sign, |c| buf.push(c));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2014-05-03 22:02:59 -07:00
|
|
|
(buf, false)
|
2013-02-15 03:29:36 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Converts a number to its string representation. This is a wrapper for
|
|
|
|
|
* `to_str_bytes_common()`, for details see there.
|
|
|
|
|
*/
|
2013-06-18 14:45:18 -07:00
|
|
|
#[inline]
|
2014-05-29 17:45:07 -07:00
|
|
|
pub fn float_to_str_common<T:NumCast+Zero+One+PartialEq+PartialOrd+NumStrConv+Float+
|
2013-06-28 14:05:10 -07:00
|
|
|
Div<T,T>+Neg<T>+Rem<T,T>+Mul<T,T>>(
|
|
|
|
|
num: T, radix: uint, negative_zero: bool,
|
2014-01-16 18:24:03 -05:00
|
|
|
sign: SignFormat, digits: SignificantDigits, exp_format: ExponentFormat, exp_capital: bool
|
2014-05-22 16:57:53 -07:00
|
|
|
) -> (String, bool) {
|
2013-06-28 14:05:10 -07:00
|
|
|
let (bytes, special) = float_to_str_bytes_common(num, radix,
|
2014-01-16 18:24:03 -05:00
|
|
|
negative_zero, sign, digits, exp_format, exp_capital);
|
2014-05-22 16:57:53 -07:00
|
|
|
(String::from_utf8(bytes).unwrap(), special)
|
2013-02-15 03:29:36 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Some constants for from_str_bytes_common's input validation,
|
|
|
|
|
// they define minimum radix values for which the character is a valid digit.
|
2013-08-06 23:03:31 -07:00
|
|
|
static DIGIT_P_RADIX: uint = ('p' as uint) - ('a' as uint) + 11u;
|
|
|
|
|
static DIGIT_I_RADIX: uint = ('i' as uint) - ('a' as uint) + 11u;
|
|
|
|
|
static DIGIT_E_RADIX: uint = ('e' as uint) - ('a' as uint) + 11u;
|
2013-02-15 03:29:36 +01:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Parses a byte slice as a number. This is meant to
|
|
|
|
|
* be a common base implementation for all numeric string conversion
|
|
|
|
|
* functions like `from_str()` or `from_str_radix()`.
|
|
|
|
|
*
|
|
|
|
|
* # Arguments
|
|
|
|
|
* - `buf` - The byte slice to parse.
|
|
|
|
|
* - `radix` - Which base to parse the number as. Accepts 2-36.
|
|
|
|
|
* - `negative` - Whether to accept negative numbers.
|
|
|
|
|
* - `fractional` - Whether to accept numbers with fractional parts.
|
|
|
|
|
* - `special` - Whether to accept special values like `inf`
|
|
|
|
|
* and `NaN`. Can conflict with `radix`, see Failure.
|
|
|
|
|
* - `exponent` - Which exponent format to accept. Options are:
|
|
|
|
|
* - `ExpNone`: No Exponent, accepts just plain numbers like `42` or
|
|
|
|
|
* `-8.2`.
|
|
|
|
|
* - `ExpDec`: Accepts numbers with a decimal exponent like `42e5` or
|
|
|
|
|
* `8.2E-2`. The exponent string itself is always base 10.
|
|
|
|
|
* Can conflict with `radix`, see Failure.
|
|
|
|
|
* - `ExpBin`: Accepts numbers with a binary exponent like `42P-8` or
|
|
|
|
|
* `FFp128`. The exponent string itself is always base 10.
|
|
|
|
|
* Can conflict with `radix`, see Failure.
|
2014-01-30 19:29:35 +01:00
|
|
|
* - `empty_zero` - Whether to accept an empty `buf` as a 0 or not.
|
2013-04-08 00:23:42 +10:00
|
|
|
* - `ignore_underscores` - Whether all underscores within the string should
|
|
|
|
|
* be ignored.
|
2013-02-15 03:29:36 +01:00
|
|
|
*
|
|
|
|
|
* # Return value
|
|
|
|
|
* Returns `Some(n)` if `buf` parses to a number n without overflowing, and
|
|
|
|
|
* `None` otherwise, depending on the constraints set by the remaining
|
|
|
|
|
* arguments.
|
|
|
|
|
*
|
|
|
|
|
* # Failure
|
|
|
|
|
* - Fails if `radix` < 2 or `radix` > 36.
|
|
|
|
|
* - Fails if `radix` > 14 and `exponent` is `ExpDec` due to conflict
|
|
|
|
|
* between digit and exponent sign `'e'`.
|
|
|
|
|
* - Fails if `radix` > 25 and `exponent` is `ExpBin` due to conflict
|
|
|
|
|
* between digit and exponent sign `'p'`.
|
|
|
|
|
* - Fails if `radix` > 18 and `special == true` due to conflict
|
|
|
|
|
* between digit and lowest first character in `inf` and `NaN`, the `'i'`.
|
|
|
|
|
*/
|
2014-05-29 17:45:07 -07:00
|
|
|
pub fn from_str_bytes_common<T:NumCast+Zero+One+PartialEq+PartialOrd+Div<T,T>+
|
2013-02-15 05:40:01 +01:00
|
|
|
Mul<T,T>+Sub<T,T>+Neg<T>+Add<T,T>+
|
2013-07-02 12:47:32 -07:00
|
|
|
NumStrConv+Clone>(
|
2013-02-15 03:29:36 +01:00
|
|
|
buf: &[u8], radix: uint, negative: bool, fractional: bool,
|
2013-04-08 00:23:42 +10:00
|
|
|
special: bool, exponent: ExponentFormat, empty_zero: bool,
|
|
|
|
|
ignore_underscores: bool
|
2013-02-15 03:29:36 +01:00
|
|
|
) -> Option<T> {
|
|
|
|
|
match exponent {
|
|
|
|
|
ExpDec if radix >= DIGIT_E_RADIX // decimal exponent 'e'
|
2014-02-27 20:37:40 -08:00
|
|
|
=> fail!("from_str_bytes_common: radix {} incompatible with \
|
2013-05-09 13:52:07 +02:00
|
|
|
use of 'e' as decimal exponent", radix),
|
2013-02-15 03:29:36 +01:00
|
|
|
ExpBin if radix >= DIGIT_P_RADIX // binary exponent 'p'
|
2014-02-27 20:37:40 -08:00
|
|
|
=> fail!("from_str_bytes_common: radix {} incompatible with \
|
2013-05-09 13:52:07 +02:00
|
|
|
use of 'p' as binary exponent", radix),
|
2013-02-15 03:29:36 +01:00
|
|
|
_ if special && radix >= DIGIT_I_RADIX // first digit of 'inf'
|
2014-02-27 20:37:40 -08:00
|
|
|
=> fail!("from_str_bytes_common: radix {} incompatible with \
|
2013-05-09 13:52:07 +02:00
|
|
|
special values 'inf' and 'NaN'", radix),
|
2013-03-20 13:24:09 -07:00
|
|
|
_ if (radix as int) < 2
|
2014-02-27 20:37:40 -08:00
|
|
|
=> fail!("from_str_bytes_common: radix {} to low, \
|
2013-05-09 13:52:07 +02:00
|
|
|
must lie in the range [2, 36]", radix),
|
2013-03-20 13:24:09 -07:00
|
|
|
_ if (radix as int) > 36
|
2014-02-27 20:37:40 -08:00
|
|
|
=> fail!("from_str_bytes_common: radix {} to high, \
|
2013-05-09 13:52:07 +02:00
|
|
|
must lie in the range [2, 36]", radix),
|
2013-02-15 03:29:36 +01:00
|
|
|
_ => ()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let _0: T = Zero::zero();
|
|
|
|
|
let _1: T = One::one();
|
2013-09-15 09:50:17 -07:00
|
|
|
let radix_gen: T = cast(radix as int).unwrap();
|
2013-02-15 03:29:36 +01:00
|
|
|
|
|
|
|
|
let len = buf.len();
|
|
|
|
|
|
|
|
|
|
if len == 0 {
|
|
|
|
|
if empty_zero {
|
|
|
|
|
return Some(_0);
|
|
|
|
|
} else {
|
|
|
|
|
return None;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if special {
|
2013-07-01 13:51:13 +10:00
|
|
|
if buf == INF_BUF || buf == POS_INF_BUF {
|
2013-02-15 05:20:36 +01:00
|
|
|
return NumStrConv::inf();
|
2013-07-01 13:51:13 +10:00
|
|
|
} else if buf == NEG_INF_BUF {
|
2013-02-15 03:29:36 +01:00
|
|
|
if negative {
|
2013-02-15 05:20:36 +01:00
|
|
|
return NumStrConv::neg_inf();
|
2013-02-15 03:29:36 +01:00
|
|
|
} else {
|
|
|
|
|
return None;
|
|
|
|
|
}
|
2013-07-01 13:51:13 +10:00
|
|
|
} else if buf == NAN_BUF {
|
2013-09-19 15:37:34 +10:00
|
|
|
return NumStrConv::nan();
|
2013-02-15 03:29:36 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2013-05-10 18:19:58 -07:00
|
|
|
let (start, accum_positive) = match buf[0] as char {
|
|
|
|
|
'-' if !negative => return None,
|
|
|
|
|
'-' => (1u, false),
|
|
|
|
|
'+' => (1u, true),
|
|
|
|
|
_ => (0u, true)
|
2013-02-15 03:29:36 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// Initialize accumulator with signed zero for floating point parsing to
|
|
|
|
|
// work
|
2013-07-02 12:47:32 -07:00
|
|
|
let mut accum = if accum_positive { _0.clone() } else { -_1 * _0};
|
|
|
|
|
let mut last_accum = accum.clone(); // Necessary to detect overflow
|
2013-02-15 03:29:36 +01:00
|
|
|
let mut i = start;
|
|
|
|
|
let mut exp_found = false;
|
|
|
|
|
|
|
|
|
|
// Parse integer part of number
|
|
|
|
|
while i < len {
|
|
|
|
|
let c = buf[i] as char;
|
|
|
|
|
|
|
|
|
|
match char::to_digit(c, radix) {
|
|
|
|
|
Some(digit) => {
|
|
|
|
|
// shift accum one digit left
|
2013-07-02 12:47:32 -07:00
|
|
|
accum = accum * radix_gen.clone();
|
2013-02-15 03:29:36 +01:00
|
|
|
|
|
|
|
|
// add/subtract current digit depending on sign
|
|
|
|
|
if accum_positive {
|
2013-09-15 09:50:17 -07:00
|
|
|
accum = accum + cast(digit as int).unwrap();
|
2013-02-15 03:29:36 +01:00
|
|
|
} else {
|
2013-09-15 09:50:17 -07:00
|
|
|
accum = accum - cast(digit as int).unwrap();
|
2013-02-15 03:29:36 +01:00
|
|
|
}
|
|
|
|
|
|
2013-04-08 01:26:51 +10:00
|
|
|
// Detect overflow by comparing to last value, except
|
|
|
|
|
// if we've not seen any non-zero digits.
|
|
|
|
|
if last_accum != _0 {
|
2013-08-30 17:45:20 -05:00
|
|
|
if accum_positive && accum <= last_accum { return NumStrConv::inf(); }
|
|
|
|
|
if !accum_positive && accum >= last_accum { return NumStrConv::neg_inf(); }
|
|
|
|
|
|
2014-06-08 13:22:49 -04:00
|
|
|
// Detect overflow by reversing the shift-and-add process
|
2013-08-30 17:45:20 -05:00
|
|
|
if accum_positive &&
|
2013-09-15 09:50:17 -07:00
|
|
|
(last_accum != ((accum - cast(digit as int).unwrap())/radix_gen.clone())) {
|
2013-08-30 17:45:20 -05:00
|
|
|
return NumStrConv::inf();
|
|
|
|
|
}
|
|
|
|
|
if !accum_positive &&
|
2013-09-15 09:50:17 -07:00
|
|
|
(last_accum != ((accum + cast(digit as int).unwrap())/radix_gen.clone())) {
|
2013-08-30 17:45:20 -05:00
|
|
|
return NumStrConv::neg_inf();
|
|
|
|
|
}
|
2013-04-08 01:26:51 +10:00
|
|
|
}
|
2013-07-02 12:47:32 -07:00
|
|
|
last_accum = accum.clone();
|
2013-02-15 03:29:36 +01:00
|
|
|
}
|
|
|
|
|
None => match c {
|
2013-04-08 00:23:42 +10:00
|
|
|
'_' if ignore_underscores => {}
|
2013-02-15 03:29:36 +01:00
|
|
|
'e' | 'E' | 'p' | 'P' => {
|
|
|
|
|
exp_found = true;
|
|
|
|
|
break; // start of exponent
|
|
|
|
|
}
|
|
|
|
|
'.' if fractional => {
|
|
|
|
|
i += 1u; // skip the '.'
|
|
|
|
|
break; // start of fractional part
|
|
|
|
|
}
|
|
|
|
|
_ => return None // invalid number
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
i += 1u;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Parse fractional part of number
|
|
|
|
|
// Skip if already reached start of exponent
|
|
|
|
|
if !exp_found {
|
2013-07-02 12:47:32 -07:00
|
|
|
let mut power = _1.clone();
|
2013-02-15 03:29:36 +01:00
|
|
|
|
|
|
|
|
while i < len {
|
|
|
|
|
let c = buf[i] as char;
|
|
|
|
|
|
|
|
|
|
match char::to_digit(c, radix) {
|
|
|
|
|
Some(digit) => {
|
|
|
|
|
// Decrease power one order of magnitude
|
2013-06-15 20:26:59 -04:00
|
|
|
power = power / radix_gen;
|
2013-02-15 03:29:36 +01:00
|
|
|
|
2013-09-15 09:50:17 -07:00
|
|
|
let digit_t: T = cast(digit).unwrap();
|
2013-02-15 03:29:36 +01:00
|
|
|
|
|
|
|
|
// add/subtract current digit depending on sign
|
|
|
|
|
if accum_positive {
|
2013-06-15 20:26:59 -04:00
|
|
|
accum = accum + digit_t * power;
|
2013-02-15 03:29:36 +01:00
|
|
|
} else {
|
2013-06-15 20:26:59 -04:00
|
|
|
accum = accum - digit_t * power;
|
2013-02-15 03:29:36 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Detect overflow by comparing to last value
|
2013-08-30 17:45:20 -05:00
|
|
|
if accum_positive && accum < last_accum { return NumStrConv::inf(); }
|
|
|
|
|
if !accum_positive && accum > last_accum { return NumStrConv::neg_inf(); }
|
2013-07-02 12:47:32 -07:00
|
|
|
last_accum = accum.clone();
|
2013-02-15 03:29:36 +01:00
|
|
|
}
|
|
|
|
|
None => match c {
|
2013-04-08 00:23:42 +10:00
|
|
|
'_' if ignore_underscores => {}
|
2013-02-15 03:29:36 +01:00
|
|
|
'e' | 'E' | 'p' | 'P' => {
|
|
|
|
|
exp_found = true;
|
|
|
|
|
break; // start of exponent
|
|
|
|
|
}
|
|
|
|
|
_ => return None // invalid number
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
i += 1u;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Special case: buf not empty, but does not contain any digit in front
|
|
|
|
|
// of the exponent sign -> number is empty string
|
|
|
|
|
if i == start {
|
|
|
|
|
if empty_zero {
|
|
|
|
|
return Some(_0);
|
|
|
|
|
} else {
|
|
|
|
|
return None;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2013-07-02 12:47:32 -07:00
|
|
|
let mut multiplier = _1.clone();
|
2013-02-15 03:29:36 +01:00
|
|
|
|
|
|
|
|
if exp_found {
|
|
|
|
|
let c = buf[i] as char;
|
2014-01-18 18:10:17 +01:00
|
|
|
let base: T = match (c, exponent) {
|
2013-04-08 00:23:42 +10:00
|
|
|
// c is never _ so don't need to handle specially
|
2014-01-18 18:10:17 +01:00
|
|
|
('e', ExpDec) | ('E', ExpDec) => cast(10u).unwrap(),
|
|
|
|
|
('p', ExpBin) | ('P', ExpBin) => cast(2u).unwrap(),
|
2013-02-15 03:29:36 +01:00
|
|
|
_ => return None // char doesn't fit given exponent format
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// parse remaining bytes as decimal integer,
|
|
|
|
|
// skipping the exponent char
|
|
|
|
|
let exp: Option<int> = from_str_bytes_common(
|
2014-10-02 11:48:07 -07:00
|
|
|
buf.slice(i+1, len), 10, true, false, false, ExpNone, false,
|
2013-04-08 00:23:42 +10:00
|
|
|
ignore_underscores);
|
2013-02-15 03:29:36 +01:00
|
|
|
|
|
|
|
|
match exp {
|
|
|
|
|
Some(exp_pow) => {
|
|
|
|
|
multiplier = if exp_pow < 0 {
|
2014-01-18 18:10:17 +01:00
|
|
|
_1 / num::pow(base, (-exp_pow.to_int().unwrap()) as uint)
|
2013-02-15 03:29:36 +01:00
|
|
|
} else {
|
2014-01-18 18:10:17 +01:00
|
|
|
num::pow(base, exp_pow.to_int().unwrap() as uint)
|
2013-02-15 03:29:36 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
None => return None // invalid exponent -> invalid number
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Some(accum * multiplier)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Parses a string as a number. This is a wrapper for
|
|
|
|
|
* `from_str_bytes_common()`, for details see there.
|
|
|
|
|
*/
|
2013-06-18 14:45:18 -07:00
|
|
|
#[inline]
|
2014-05-29 17:45:07 -07:00
|
|
|
pub fn from_str_common<T:NumCast+Zero+One+PartialEq+PartialOrd+Div<T,T>+Mul<T,T>+
|
2013-07-02 12:47:32 -07:00
|
|
|
Sub<T,T>+Neg<T>+Add<T,T>+NumStrConv+Clone>(
|
2013-02-15 03:29:36 +01:00
|
|
|
buf: &str, radix: uint, negative: bool, fractional: bool,
|
2013-04-08 00:23:42 +10:00
|
|
|
special: bool, exponent: ExponentFormat, empty_zero: bool,
|
|
|
|
|
ignore_underscores: bool
|
2013-02-15 03:29:36 +01:00
|
|
|
) -> Option<T> {
|
2013-06-11 13:10:37 +10:00
|
|
|
from_str_bytes_common(buf.as_bytes(), radix, negative,
|
2013-04-08 00:23:42 +10:00
|
|
|
fractional, special, exponent, empty_zero,
|
|
|
|
|
ignore_underscores)
|
2013-02-15 03:29:36 +01:00
|
|
|
}
|
2013-04-08 01:26:51 +10:00
|
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
|
mod test {
|
|
|
|
|
use super::*;
|
|
|
|
|
use option::*;
|
|
|
|
|
|
2013-04-08 00:23:42 +10:00
|
|
|
#[test]
|
|
|
|
|
fn from_str_ignore_underscores() {
|
|
|
|
|
let s : Option<u8> = from_str_common("__1__", 2, false, false, false,
|
|
|
|
|
ExpNone, false, true);
|
|
|
|
|
assert_eq!(s, Some(1u8));
|
|
|
|
|
|
|
|
|
|
let n : Option<u8> = from_str_common("__1__", 2, false, false, false,
|
|
|
|
|
ExpNone, false, false);
|
|
|
|
|
assert_eq!(n, None);
|
|
|
|
|
|
2013-04-23 11:10:37 +02:00
|
|
|
let f : Option<f32> = from_str_common("_1_._5_e_1_", 10, false, true, false,
|
2013-04-08 00:23:42 +10:00
|
|
|
ExpDec, false, true);
|
2013-04-23 11:10:37 +02:00
|
|
|
assert_eq!(f, Some(1.5e1f32));
|
2013-04-08 00:23:42 +10:00
|
|
|
}
|
|
|
|
|
|
2013-04-08 01:26:51 +10:00
|
|
|
#[test]
|
|
|
|
|
fn from_str_issue5770() {
|
|
|
|
|
// try to parse 0b1_1111_1111 = 511 as a u8. Caused problems
|
|
|
|
|
// since 255*2+1 == 255 (mod 256) so the overflow wasn't
|
|
|
|
|
// detected.
|
|
|
|
|
let n : Option<u8> = from_str_common("111111111", 2, false, false, false,
|
2013-04-08 00:23:42 +10:00
|
|
|
ExpNone, false, false);
|
2013-04-08 01:26:51 +10:00
|
|
|
assert_eq!(n, None);
|
|
|
|
|
}
|
2013-08-30 17:45:20 -05:00
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn from_str_issue7588() {
|
|
|
|
|
let u : Option<u8> = from_str_common("1000", 10, false, false, false,
|
|
|
|
|
ExpNone, false, false);
|
|
|
|
|
assert_eq!(u, None);
|
|
|
|
|
let s : Option<i16> = from_str_common("80000", 10, false, false, false,
|
|
|
|
|
ExpNone, false, false);
|
|
|
|
|
assert_eq!(s, None);
|
|
|
|
|
let f : Option<f32> = from_str_common(
|
|
|
|
|
"10000000000000000000000000000000000000000", 10, false, false, false,
|
|
|
|
|
ExpNone, false, false);
|
|
|
|
|
assert_eq!(f, NumStrConv::inf())
|
|
|
|
|
let fe : Option<f32> = from_str_common("1e40", 10, false, false, false,
|
|
|
|
|
ExpDec, false, false);
|
|
|
|
|
assert_eq!(fe, NumStrConv::inf())
|
|
|
|
|
}
|
2013-04-08 01:26:51 +10:00
|
|
|
}
|
2013-07-22 11:43:32 -07:00
|
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
|
mod bench {
|
2014-02-14 09:49:11 +08:00
|
|
|
extern crate test;
|
2014-02-22 03:52:32 +11:00
|
|
|
|
|
|
|
|
mod uint {
|
2014-04-01 09:16:35 +08:00
|
|
|
use super::test::Bencher;
|
std: Recreate a `rand` module
This commit shuffles around some of the `rand` code, along with some
reorganization. The new state of the world is as follows:
* The librand crate now only depends on libcore. This interface is experimental.
* The standard library has a new module, `std::rand`. This interface will
eventually become stable.
Unfortunately, this entailed more of a breaking change than just shuffling some
names around. The following breaking changes were made to the rand library:
* Rng::gen_vec() was removed. This has been replaced with Rng::gen_iter() which
will return an infinite stream of random values. Previous behavior can be
regained with `rng.gen_iter().take(n).collect()`
* Rng::gen_ascii_str() was removed. This has been replaced with
Rng::gen_ascii_chars() which will return an infinite stream of random ascii
characters. Similarly to gen_iter(), previous behavior can be emulated with
`rng.gen_ascii_chars().take(n).collect()`
* {IsaacRng, Isaac64Rng, XorShiftRng}::new() have all been removed. These all
relied on being able to use an OSRng for seeding, but this is no longer
available in librand (where these types are defined). To retain the same
functionality, these types now implement the `Rand` trait so they can be
generated with a random seed from another random number generator. This allows
the stdlib to use an OSRng to create seeded instances of these RNGs.
* Rand implementations for `Box<T>` and `@T` were removed. These seemed to be
pretty rare in the codebase, and it allows for librand to not depend on
liballoc. Additionally, other pointer types like Rc<T> and Arc<T> were not
supported. If this is undesirable, librand can depend on liballoc and regain
these implementations.
* The WeightedChoice structure is no longer built with a `Vec<Weighted<T>>`,
but rather a `&mut [Weighted<T>]`. This means that the WeightedChoice
structure now has a lifetime associated with it.
* The `sample` method on `Rng` has been moved to a top-level function in the
`rand` module due to its dependence on `Vec`.
cc #13851
[breaking-change]
2014-05-25 01:39:37 -07:00
|
|
|
use rand::{weak_rng, Rng};
|
2014-02-22 03:52:32 +11:00
|
|
|
use num::ToStrRadix;
|
|
|
|
|
|
|
|
|
|
#[bench]
|
2014-04-01 09:16:35 +08:00
|
|
|
fn to_str_bin(b: &mut Bencher) {
|
std: Recreate a `rand` module
This commit shuffles around some of the `rand` code, along with some
reorganization. The new state of the world is as follows:
* The librand crate now only depends on libcore. This interface is experimental.
* The standard library has a new module, `std::rand`. This interface will
eventually become stable.
Unfortunately, this entailed more of a breaking change than just shuffling some
names around. The following breaking changes were made to the rand library:
* Rng::gen_vec() was removed. This has been replaced with Rng::gen_iter() which
will return an infinite stream of random values. Previous behavior can be
regained with `rng.gen_iter().take(n).collect()`
* Rng::gen_ascii_str() was removed. This has been replaced with
Rng::gen_ascii_chars() which will return an infinite stream of random ascii
characters. Similarly to gen_iter(), previous behavior can be emulated with
`rng.gen_ascii_chars().take(n).collect()`
* {IsaacRng, Isaac64Rng, XorShiftRng}::new() have all been removed. These all
relied on being able to use an OSRng for seeding, but this is no longer
available in librand (where these types are defined). To retain the same
functionality, these types now implement the `Rand` trait so they can be
generated with a random seed from another random number generator. This allows
the stdlib to use an OSRng to create seeded instances of these RNGs.
* Rand implementations for `Box<T>` and `@T` were removed. These seemed to be
pretty rare in the codebase, and it allows for librand to not depend on
liballoc. Additionally, other pointer types like Rc<T> and Arc<T> were not
supported. If this is undesirable, librand can depend on liballoc and regain
these implementations.
* The WeightedChoice structure is no longer built with a `Vec<Weighted<T>>`,
but rather a `&mut [Weighted<T>]`. This means that the WeightedChoice
structure now has a lifetime associated with it.
* The `sample` method on `Rng` has been moved to a top-level function in the
`rand` module due to its dependence on `Vec`.
cc #13851
[breaking-change]
2014-05-25 01:39:37 -07:00
|
|
|
let mut rng = weak_rng();
|
2014-04-01 09:16:35 +08:00
|
|
|
b.iter(|| { rng.gen::<uint>().to_str_radix(2); })
|
2014-02-22 03:52:32 +11:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[bench]
|
2014-04-01 09:16:35 +08:00
|
|
|
fn to_str_oct(b: &mut Bencher) {
|
std: Recreate a `rand` module
This commit shuffles around some of the `rand` code, along with some
reorganization. The new state of the world is as follows:
* The librand crate now only depends on libcore. This interface is experimental.
* The standard library has a new module, `std::rand`. This interface will
eventually become stable.
Unfortunately, this entailed more of a breaking change than just shuffling some
names around. The following breaking changes were made to the rand library:
* Rng::gen_vec() was removed. This has been replaced with Rng::gen_iter() which
will return an infinite stream of random values. Previous behavior can be
regained with `rng.gen_iter().take(n).collect()`
* Rng::gen_ascii_str() was removed. This has been replaced with
Rng::gen_ascii_chars() which will return an infinite stream of random ascii
characters. Similarly to gen_iter(), previous behavior can be emulated with
`rng.gen_ascii_chars().take(n).collect()`
* {IsaacRng, Isaac64Rng, XorShiftRng}::new() have all been removed. These all
relied on being able to use an OSRng for seeding, but this is no longer
available in librand (where these types are defined). To retain the same
functionality, these types now implement the `Rand` trait so they can be
generated with a random seed from another random number generator. This allows
the stdlib to use an OSRng to create seeded instances of these RNGs.
* Rand implementations for `Box<T>` and `@T` were removed. These seemed to be
pretty rare in the codebase, and it allows for librand to not depend on
liballoc. Additionally, other pointer types like Rc<T> and Arc<T> were not
supported. If this is undesirable, librand can depend on liballoc and regain
these implementations.
* The WeightedChoice structure is no longer built with a `Vec<Weighted<T>>`,
but rather a `&mut [Weighted<T>]`. This means that the WeightedChoice
structure now has a lifetime associated with it.
* The `sample` method on `Rng` has been moved to a top-level function in the
`rand` module due to its dependence on `Vec`.
cc #13851
[breaking-change]
2014-05-25 01:39:37 -07:00
|
|
|
let mut rng = weak_rng();
|
2014-04-01 09:16:35 +08:00
|
|
|
b.iter(|| { rng.gen::<uint>().to_str_radix(8); })
|
2014-02-22 03:52:32 +11:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[bench]
|
2014-04-01 09:16:35 +08:00
|
|
|
fn to_str_dec(b: &mut Bencher) {
|
std: Recreate a `rand` module
This commit shuffles around some of the `rand` code, along with some
reorganization. The new state of the world is as follows:
* The librand crate now only depends on libcore. This interface is experimental.
* The standard library has a new module, `std::rand`. This interface will
eventually become stable.
Unfortunately, this entailed more of a breaking change than just shuffling some
names around. The following breaking changes were made to the rand library:
* Rng::gen_vec() was removed. This has been replaced with Rng::gen_iter() which
will return an infinite stream of random values. Previous behavior can be
regained with `rng.gen_iter().take(n).collect()`
* Rng::gen_ascii_str() was removed. This has been replaced with
Rng::gen_ascii_chars() which will return an infinite stream of random ascii
characters. Similarly to gen_iter(), previous behavior can be emulated with
`rng.gen_ascii_chars().take(n).collect()`
* {IsaacRng, Isaac64Rng, XorShiftRng}::new() have all been removed. These all
relied on being able to use an OSRng for seeding, but this is no longer
available in librand (where these types are defined). To retain the same
functionality, these types now implement the `Rand` trait so they can be
generated with a random seed from another random number generator. This allows
the stdlib to use an OSRng to create seeded instances of these RNGs.
* Rand implementations for `Box<T>` and `@T` were removed. These seemed to be
pretty rare in the codebase, and it allows for librand to not depend on
liballoc. Additionally, other pointer types like Rc<T> and Arc<T> were not
supported. If this is undesirable, librand can depend on liballoc and regain
these implementations.
* The WeightedChoice structure is no longer built with a `Vec<Weighted<T>>`,
but rather a `&mut [Weighted<T>]`. This means that the WeightedChoice
structure now has a lifetime associated with it.
* The `sample` method on `Rng` has been moved to a top-level function in the
`rand` module due to its dependence on `Vec`.
cc #13851
[breaking-change]
2014-05-25 01:39:37 -07:00
|
|
|
let mut rng = weak_rng();
|
2014-04-01 09:16:35 +08:00
|
|
|
b.iter(|| { rng.gen::<uint>().to_str_radix(10); })
|
2014-02-22 03:52:32 +11:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[bench]
|
2014-04-01 09:16:35 +08:00
|
|
|
fn to_str_hex(b: &mut Bencher) {
|
std: Recreate a `rand` module
This commit shuffles around some of the `rand` code, along with some
reorganization. The new state of the world is as follows:
* The librand crate now only depends on libcore. This interface is experimental.
* The standard library has a new module, `std::rand`. This interface will
eventually become stable.
Unfortunately, this entailed more of a breaking change than just shuffling some
names around. The following breaking changes were made to the rand library:
* Rng::gen_vec() was removed. This has been replaced with Rng::gen_iter() which
will return an infinite stream of random values. Previous behavior can be
regained with `rng.gen_iter().take(n).collect()`
* Rng::gen_ascii_str() was removed. This has been replaced with
Rng::gen_ascii_chars() which will return an infinite stream of random ascii
characters. Similarly to gen_iter(), previous behavior can be emulated with
`rng.gen_ascii_chars().take(n).collect()`
* {IsaacRng, Isaac64Rng, XorShiftRng}::new() have all been removed. These all
relied on being able to use an OSRng for seeding, but this is no longer
available in librand (where these types are defined). To retain the same
functionality, these types now implement the `Rand` trait so they can be
generated with a random seed from another random number generator. This allows
the stdlib to use an OSRng to create seeded instances of these RNGs.
* Rand implementations for `Box<T>` and `@T` were removed. These seemed to be
pretty rare in the codebase, and it allows for librand to not depend on
liballoc. Additionally, other pointer types like Rc<T> and Arc<T> were not
supported. If this is undesirable, librand can depend on liballoc and regain
these implementations.
* The WeightedChoice structure is no longer built with a `Vec<Weighted<T>>`,
but rather a `&mut [Weighted<T>]`. This means that the WeightedChoice
structure now has a lifetime associated with it.
* The `sample` method on `Rng` has been moved to a top-level function in the
`rand` module due to its dependence on `Vec`.
cc #13851
[breaking-change]
2014-05-25 01:39:37 -07:00
|
|
|
let mut rng = weak_rng();
|
2014-04-01 09:16:35 +08:00
|
|
|
b.iter(|| { rng.gen::<uint>().to_str_radix(16); })
|
2014-02-22 03:52:32 +11:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[bench]
|
2014-04-01 09:16:35 +08:00
|
|
|
fn to_str_base_36(b: &mut Bencher) {
|
std: Recreate a `rand` module
This commit shuffles around some of the `rand` code, along with some
reorganization. The new state of the world is as follows:
* The librand crate now only depends on libcore. This interface is experimental.
* The standard library has a new module, `std::rand`. This interface will
eventually become stable.
Unfortunately, this entailed more of a breaking change than just shuffling some
names around. The following breaking changes were made to the rand library:
* Rng::gen_vec() was removed. This has been replaced with Rng::gen_iter() which
will return an infinite stream of random values. Previous behavior can be
regained with `rng.gen_iter().take(n).collect()`
* Rng::gen_ascii_str() was removed. This has been replaced with
Rng::gen_ascii_chars() which will return an infinite stream of random ascii
characters. Similarly to gen_iter(), previous behavior can be emulated with
`rng.gen_ascii_chars().take(n).collect()`
* {IsaacRng, Isaac64Rng, XorShiftRng}::new() have all been removed. These all
relied on being able to use an OSRng for seeding, but this is no longer
available in librand (where these types are defined). To retain the same
functionality, these types now implement the `Rand` trait so they can be
generated with a random seed from another random number generator. This allows
the stdlib to use an OSRng to create seeded instances of these RNGs.
* Rand implementations for `Box<T>` and `@T` were removed. These seemed to be
pretty rare in the codebase, and it allows for librand to not depend on
liballoc. Additionally, other pointer types like Rc<T> and Arc<T> were not
supported. If this is undesirable, librand can depend on liballoc and regain
these implementations.
* The WeightedChoice structure is no longer built with a `Vec<Weighted<T>>`,
but rather a `&mut [Weighted<T>]`. This means that the WeightedChoice
structure now has a lifetime associated with it.
* The `sample` method on `Rng` has been moved to a top-level function in the
`rand` module due to its dependence on `Vec`.
cc #13851
[breaking-change]
2014-05-25 01:39:37 -07:00
|
|
|
let mut rng = weak_rng();
|
2014-04-01 09:16:35 +08:00
|
|
|
b.iter(|| { rng.gen::<uint>().to_str_radix(36); })
|
2014-02-22 03:52:32 +11:00
|
|
|
}
|
2013-07-22 11:43:32 -07:00
|
|
|
}
|
|
|
|
|
|
2014-02-22 03:52:32 +11:00
|
|
|
mod int {
|
2014-04-01 09:16:35 +08:00
|
|
|
use super::test::Bencher;
|
std: Recreate a `rand` module
This commit shuffles around some of the `rand` code, along with some
reorganization. The new state of the world is as follows:
* The librand crate now only depends on libcore. This interface is experimental.
* The standard library has a new module, `std::rand`. This interface will
eventually become stable.
Unfortunately, this entailed more of a breaking change than just shuffling some
names around. The following breaking changes were made to the rand library:
* Rng::gen_vec() was removed. This has been replaced with Rng::gen_iter() which
will return an infinite stream of random values. Previous behavior can be
regained with `rng.gen_iter().take(n).collect()`
* Rng::gen_ascii_str() was removed. This has been replaced with
Rng::gen_ascii_chars() which will return an infinite stream of random ascii
characters. Similarly to gen_iter(), previous behavior can be emulated with
`rng.gen_ascii_chars().take(n).collect()`
* {IsaacRng, Isaac64Rng, XorShiftRng}::new() have all been removed. These all
relied on being able to use an OSRng for seeding, but this is no longer
available in librand (where these types are defined). To retain the same
functionality, these types now implement the `Rand` trait so they can be
generated with a random seed from another random number generator. This allows
the stdlib to use an OSRng to create seeded instances of these RNGs.
* Rand implementations for `Box<T>` and `@T` were removed. These seemed to be
pretty rare in the codebase, and it allows for librand to not depend on
liballoc. Additionally, other pointer types like Rc<T> and Arc<T> were not
supported. If this is undesirable, librand can depend on liballoc and regain
these implementations.
* The WeightedChoice structure is no longer built with a `Vec<Weighted<T>>`,
but rather a `&mut [Weighted<T>]`. This means that the WeightedChoice
structure now has a lifetime associated with it.
* The `sample` method on `Rng` has been moved to a top-level function in the
`rand` module due to its dependence on `Vec`.
cc #13851
[breaking-change]
2014-05-25 01:39:37 -07:00
|
|
|
use rand::{weak_rng, Rng};
|
2014-02-22 03:52:32 +11:00
|
|
|
use num::ToStrRadix;
|
|
|
|
|
|
|
|
|
|
#[bench]
|
2014-04-01 09:16:35 +08:00
|
|
|
fn to_str_bin(b: &mut Bencher) {
|
std: Recreate a `rand` module
This commit shuffles around some of the `rand` code, along with some
reorganization. The new state of the world is as follows:
* The librand crate now only depends on libcore. This interface is experimental.
* The standard library has a new module, `std::rand`. This interface will
eventually become stable.
Unfortunately, this entailed more of a breaking change than just shuffling some
names around. The following breaking changes were made to the rand library:
* Rng::gen_vec() was removed. This has been replaced with Rng::gen_iter() which
will return an infinite stream of random values. Previous behavior can be
regained with `rng.gen_iter().take(n).collect()`
* Rng::gen_ascii_str() was removed. This has been replaced with
Rng::gen_ascii_chars() which will return an infinite stream of random ascii
characters. Similarly to gen_iter(), previous behavior can be emulated with
`rng.gen_ascii_chars().take(n).collect()`
* {IsaacRng, Isaac64Rng, XorShiftRng}::new() have all been removed. These all
relied on being able to use an OSRng for seeding, but this is no longer
available in librand (where these types are defined). To retain the same
functionality, these types now implement the `Rand` trait so they can be
generated with a random seed from another random number generator. This allows
the stdlib to use an OSRng to create seeded instances of these RNGs.
* Rand implementations for `Box<T>` and `@T` were removed. These seemed to be
pretty rare in the codebase, and it allows for librand to not depend on
liballoc. Additionally, other pointer types like Rc<T> and Arc<T> were not
supported. If this is undesirable, librand can depend on liballoc and regain
these implementations.
* The WeightedChoice structure is no longer built with a `Vec<Weighted<T>>`,
but rather a `&mut [Weighted<T>]`. This means that the WeightedChoice
structure now has a lifetime associated with it.
* The `sample` method on `Rng` has been moved to a top-level function in the
`rand` module due to its dependence on `Vec`.
cc #13851
[breaking-change]
2014-05-25 01:39:37 -07:00
|
|
|
let mut rng = weak_rng();
|
2014-04-01 09:16:35 +08:00
|
|
|
b.iter(|| { rng.gen::<int>().to_str_radix(2); })
|
2014-02-22 03:52:32 +11:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[bench]
|
2014-04-01 09:16:35 +08:00
|
|
|
fn to_str_oct(b: &mut Bencher) {
|
std: Recreate a `rand` module
This commit shuffles around some of the `rand` code, along with some
reorganization. The new state of the world is as follows:
* The librand crate now only depends on libcore. This interface is experimental.
* The standard library has a new module, `std::rand`. This interface will
eventually become stable.
Unfortunately, this entailed more of a breaking change than just shuffling some
names around. The following breaking changes were made to the rand library:
* Rng::gen_vec() was removed. This has been replaced with Rng::gen_iter() which
will return an infinite stream of random values. Previous behavior can be
regained with `rng.gen_iter().take(n).collect()`
* Rng::gen_ascii_str() was removed. This has been replaced with
Rng::gen_ascii_chars() which will return an infinite stream of random ascii
characters. Similarly to gen_iter(), previous behavior can be emulated with
`rng.gen_ascii_chars().take(n).collect()`
* {IsaacRng, Isaac64Rng, XorShiftRng}::new() have all been removed. These all
relied on being able to use an OSRng for seeding, but this is no longer
available in librand (where these types are defined). To retain the same
functionality, these types now implement the `Rand` trait so they can be
generated with a random seed from another random number generator. This allows
the stdlib to use an OSRng to create seeded instances of these RNGs.
* Rand implementations for `Box<T>` and `@T` were removed. These seemed to be
pretty rare in the codebase, and it allows for librand to not depend on
liballoc. Additionally, other pointer types like Rc<T> and Arc<T> were not
supported. If this is undesirable, librand can depend on liballoc and regain
these implementations.
* The WeightedChoice structure is no longer built with a `Vec<Weighted<T>>`,
but rather a `&mut [Weighted<T>]`. This means that the WeightedChoice
structure now has a lifetime associated with it.
* The `sample` method on `Rng` has been moved to a top-level function in the
`rand` module due to its dependence on `Vec`.
cc #13851
[breaking-change]
2014-05-25 01:39:37 -07:00
|
|
|
let mut rng = weak_rng();
|
2014-04-01 09:16:35 +08:00
|
|
|
b.iter(|| { rng.gen::<int>().to_str_radix(8); })
|
2014-02-22 03:52:32 +11:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[bench]
|
2014-04-01 09:16:35 +08:00
|
|
|
fn to_str_dec(b: &mut Bencher) {
|
std: Recreate a `rand` module
This commit shuffles around some of the `rand` code, along with some
reorganization. The new state of the world is as follows:
* The librand crate now only depends on libcore. This interface is experimental.
* The standard library has a new module, `std::rand`. This interface will
eventually become stable.
Unfortunately, this entailed more of a breaking change than just shuffling some
names around. The following breaking changes were made to the rand library:
* Rng::gen_vec() was removed. This has been replaced with Rng::gen_iter() which
will return an infinite stream of random values. Previous behavior can be
regained with `rng.gen_iter().take(n).collect()`
* Rng::gen_ascii_str() was removed. This has been replaced with
Rng::gen_ascii_chars() which will return an infinite stream of random ascii
characters. Similarly to gen_iter(), previous behavior can be emulated with
`rng.gen_ascii_chars().take(n).collect()`
* {IsaacRng, Isaac64Rng, XorShiftRng}::new() have all been removed. These all
relied on being able to use an OSRng for seeding, but this is no longer
available in librand (where these types are defined). To retain the same
functionality, these types now implement the `Rand` trait so they can be
generated with a random seed from another random number generator. This allows
the stdlib to use an OSRng to create seeded instances of these RNGs.
* Rand implementations for `Box<T>` and `@T` were removed. These seemed to be
pretty rare in the codebase, and it allows for librand to not depend on
liballoc. Additionally, other pointer types like Rc<T> and Arc<T> were not
supported. If this is undesirable, librand can depend on liballoc and regain
these implementations.
* The WeightedChoice structure is no longer built with a `Vec<Weighted<T>>`,
but rather a `&mut [Weighted<T>]`. This means that the WeightedChoice
structure now has a lifetime associated with it.
* The `sample` method on `Rng` has been moved to a top-level function in the
`rand` module due to its dependence on `Vec`.
cc #13851
[breaking-change]
2014-05-25 01:39:37 -07:00
|
|
|
let mut rng = weak_rng();
|
2014-04-01 09:16:35 +08:00
|
|
|
b.iter(|| { rng.gen::<int>().to_str_radix(10); })
|
2014-02-22 03:52:32 +11:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[bench]
|
2014-04-01 09:16:35 +08:00
|
|
|
fn to_str_hex(b: &mut Bencher) {
|
std: Recreate a `rand` module
This commit shuffles around some of the `rand` code, along with some
reorganization. The new state of the world is as follows:
* The librand crate now only depends on libcore. This interface is experimental.
* The standard library has a new module, `std::rand`. This interface will
eventually become stable.
Unfortunately, this entailed more of a breaking change than just shuffling some
names around. The following breaking changes were made to the rand library:
* Rng::gen_vec() was removed. This has been replaced with Rng::gen_iter() which
will return an infinite stream of random values. Previous behavior can be
regained with `rng.gen_iter().take(n).collect()`
* Rng::gen_ascii_str() was removed. This has been replaced with
Rng::gen_ascii_chars() which will return an infinite stream of random ascii
characters. Similarly to gen_iter(), previous behavior can be emulated with
`rng.gen_ascii_chars().take(n).collect()`
* {IsaacRng, Isaac64Rng, XorShiftRng}::new() have all been removed. These all
relied on being able to use an OSRng for seeding, but this is no longer
available in librand (where these types are defined). To retain the same
functionality, these types now implement the `Rand` trait so they can be
generated with a random seed from another random number generator. This allows
the stdlib to use an OSRng to create seeded instances of these RNGs.
* Rand implementations for `Box<T>` and `@T` were removed. These seemed to be
pretty rare in the codebase, and it allows for librand to not depend on
liballoc. Additionally, other pointer types like Rc<T> and Arc<T> were not
supported. If this is undesirable, librand can depend on liballoc and regain
these implementations.
* The WeightedChoice structure is no longer built with a `Vec<Weighted<T>>`,
but rather a `&mut [Weighted<T>]`. This means that the WeightedChoice
structure now has a lifetime associated with it.
* The `sample` method on `Rng` has been moved to a top-level function in the
`rand` module due to its dependence on `Vec`.
cc #13851
[breaking-change]
2014-05-25 01:39:37 -07:00
|
|
|
let mut rng = weak_rng();
|
2014-04-01 09:16:35 +08:00
|
|
|
b.iter(|| { rng.gen::<int>().to_str_radix(16); })
|
2014-02-22 03:52:32 +11:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[bench]
|
2014-04-01 09:16:35 +08:00
|
|
|
fn to_str_base_36(b: &mut Bencher) {
|
std: Recreate a `rand` module
This commit shuffles around some of the `rand` code, along with some
reorganization. The new state of the world is as follows:
* The librand crate now only depends on libcore. This interface is experimental.
* The standard library has a new module, `std::rand`. This interface will
eventually become stable.
Unfortunately, this entailed more of a breaking change than just shuffling some
names around. The following breaking changes were made to the rand library:
* Rng::gen_vec() was removed. This has been replaced with Rng::gen_iter() which
will return an infinite stream of random values. Previous behavior can be
regained with `rng.gen_iter().take(n).collect()`
* Rng::gen_ascii_str() was removed. This has been replaced with
Rng::gen_ascii_chars() which will return an infinite stream of random ascii
characters. Similarly to gen_iter(), previous behavior can be emulated with
`rng.gen_ascii_chars().take(n).collect()`
* {IsaacRng, Isaac64Rng, XorShiftRng}::new() have all been removed. These all
relied on being able to use an OSRng for seeding, but this is no longer
available in librand (where these types are defined). To retain the same
functionality, these types now implement the `Rand` trait so they can be
generated with a random seed from another random number generator. This allows
the stdlib to use an OSRng to create seeded instances of these RNGs.
* Rand implementations for `Box<T>` and `@T` were removed. These seemed to be
pretty rare in the codebase, and it allows for librand to not depend on
liballoc. Additionally, other pointer types like Rc<T> and Arc<T> were not
supported. If this is undesirable, librand can depend on liballoc and regain
these implementations.
* The WeightedChoice structure is no longer built with a `Vec<Weighted<T>>`,
but rather a `&mut [Weighted<T>]`. This means that the WeightedChoice
structure now has a lifetime associated with it.
* The `sample` method on `Rng` has been moved to a top-level function in the
`rand` module due to its dependence on `Vec`.
cc #13851
[breaking-change]
2014-05-25 01:39:37 -07:00
|
|
|
let mut rng = weak_rng();
|
2014-04-01 09:16:35 +08:00
|
|
|
b.iter(|| { rng.gen::<int>().to_str_radix(36); })
|
2014-02-22 03:52:32 +11:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
mod f64 {
|
2014-04-01 09:16:35 +08:00
|
|
|
use super::test::Bencher;
|
std: Recreate a `rand` module
This commit shuffles around some of the `rand` code, along with some
reorganization. The new state of the world is as follows:
* The librand crate now only depends on libcore. This interface is experimental.
* The standard library has a new module, `std::rand`. This interface will
eventually become stable.
Unfortunately, this entailed more of a breaking change than just shuffling some
names around. The following breaking changes were made to the rand library:
* Rng::gen_vec() was removed. This has been replaced with Rng::gen_iter() which
will return an infinite stream of random values. Previous behavior can be
regained with `rng.gen_iter().take(n).collect()`
* Rng::gen_ascii_str() was removed. This has been replaced with
Rng::gen_ascii_chars() which will return an infinite stream of random ascii
characters. Similarly to gen_iter(), previous behavior can be emulated with
`rng.gen_ascii_chars().take(n).collect()`
* {IsaacRng, Isaac64Rng, XorShiftRng}::new() have all been removed. These all
relied on being able to use an OSRng for seeding, but this is no longer
available in librand (where these types are defined). To retain the same
functionality, these types now implement the `Rand` trait so they can be
generated with a random seed from another random number generator. This allows
the stdlib to use an OSRng to create seeded instances of these RNGs.
* Rand implementations for `Box<T>` and `@T` were removed. These seemed to be
pretty rare in the codebase, and it allows for librand to not depend on
liballoc. Additionally, other pointer types like Rc<T> and Arc<T> were not
supported. If this is undesirable, librand can depend on liballoc and regain
these implementations.
* The WeightedChoice structure is no longer built with a `Vec<Weighted<T>>`,
but rather a `&mut [Weighted<T>]`. This means that the WeightedChoice
structure now has a lifetime associated with it.
* The `sample` method on `Rng` has been moved to a top-level function in the
`rand` module due to its dependence on `Vec`.
cc #13851
[breaking-change]
2014-05-25 01:39:37 -07:00
|
|
|
use rand::{weak_rng, Rng};
|
2014-02-22 03:52:32 +11:00
|
|
|
use f64;
|
|
|
|
|
|
|
|
|
|
#[bench]
|
2014-06-21 03:39:03 -07:00
|
|
|
fn float_to_string(b: &mut Bencher) {
|
std: Recreate a `rand` module
This commit shuffles around some of the `rand` code, along with some
reorganization. The new state of the world is as follows:
* The librand crate now only depends on libcore. This interface is experimental.
* The standard library has a new module, `std::rand`. This interface will
eventually become stable.
Unfortunately, this entailed more of a breaking change than just shuffling some
names around. The following breaking changes were made to the rand library:
* Rng::gen_vec() was removed. This has been replaced with Rng::gen_iter() which
will return an infinite stream of random values. Previous behavior can be
regained with `rng.gen_iter().take(n).collect()`
* Rng::gen_ascii_str() was removed. This has been replaced with
Rng::gen_ascii_chars() which will return an infinite stream of random ascii
characters. Similarly to gen_iter(), previous behavior can be emulated with
`rng.gen_ascii_chars().take(n).collect()`
* {IsaacRng, Isaac64Rng, XorShiftRng}::new() have all been removed. These all
relied on being able to use an OSRng for seeding, but this is no longer
available in librand (where these types are defined). To retain the same
functionality, these types now implement the `Rand` trait so they can be
generated with a random seed from another random number generator. This allows
the stdlib to use an OSRng to create seeded instances of these RNGs.
* Rand implementations for `Box<T>` and `@T` were removed. These seemed to be
pretty rare in the codebase, and it allows for librand to not depend on
liballoc. Additionally, other pointer types like Rc<T> and Arc<T> were not
supported. If this is undesirable, librand can depend on liballoc and regain
these implementations.
* The WeightedChoice structure is no longer built with a `Vec<Weighted<T>>`,
but rather a `&mut [Weighted<T>]`. This means that the WeightedChoice
structure now has a lifetime associated with it.
* The `sample` method on `Rng` has been moved to a top-level function in the
`rand` module due to its dependence on `Vec`.
cc #13851
[breaking-change]
2014-05-25 01:39:37 -07:00
|
|
|
let mut rng = weak_rng();
|
2014-06-21 03:39:03 -07:00
|
|
|
b.iter(|| { f64::to_string(rng.gen()); })
|
2014-02-22 03:52:32 +11:00
|
|
|
}
|
2013-07-22 11:43:32 -07:00
|
|
|
}
|
2013-08-04 01:59:24 +02:00
|
|
|
}
|