diff options
Diffstat (limited to 'libgo/go/strconv/atof.go')
-rw-r--r-- | libgo/go/strconv/atof.go | 156 |
1 files changed, 86 insertions, 70 deletions
diff --git a/libgo/go/strconv/atof.go b/libgo/go/strconv/atof.go index 4dbe68b..1f1d5ae 100644 --- a/libgo/go/strconv/atof.go +++ b/libgo/go/strconv/atof.go @@ -15,51 +15,61 @@ import "runtime" var optimize = true // set to false to force slow-path conversions for testing -func equalIgnoreCase(s1, s2 string) bool { - if len(s1) != len(s2) { - return false - } - for i := 0; i < len(s1); i++ { - c1 := s1[i] - if 'A' <= c1 && c1 <= 'Z' { - c1 += 'a' - 'A' +// commonPrefixLenIgnoreCase returns the length of the common +// prefix of s and prefix, with the character case of s ignored. +// The prefix argument must be all lower-case. +func commonPrefixLenIgnoreCase(s, prefix string) int { + n := len(prefix) + if n > len(s) { + n = len(s) + } + for i := 0; i < n; i++ { + c := s[i] + if 'A' <= c && c <= 'Z' { + c += 'a' - 'A' } - c2 := s2[i] - if 'A' <= c2 && c2 <= 'Z' { - c2 += 'a' - 'A' - } - if c1 != c2 { - return false + if c != prefix[i] { + return i } } - return true + return n } -func special(s string) (f float64, ok bool) { +// special returns the floating-point value for the special, +// possibly signed floating-point representations inf, infinity, +// and NaN. The result is ok if a prefix of s contains one +// of these representations and n is the length of that prefix. +// The character case is ignored. +func special(s string) (f float64, n int, ok bool) { if len(s) == 0 { - return + return 0, 0, false } + sign := 1 + nsign := 0 switch s[0] { - default: - return - case '+': - if equalIgnoreCase(s, "+inf") || equalIgnoreCase(s, "+infinity") { - return math.Inf(1), true + case '+', '-': + if s[0] == '-' { + sign = -1 } - case '-': - if equalIgnoreCase(s, "-inf") || equalIgnoreCase(s, "-infinity") { - return math.Inf(-1), true + nsign = 1 + s = s[1:] + fallthrough + case 'i', 'I': + n := commonPrefixLenIgnoreCase(s, "infinity") + // Anything longer than "inf" is ok, but if we + // don't have "infinity", only consume "inf". + if 3 < n && n < 8 { + n = 3 } - case 'n', 'N': - if equalIgnoreCase(s, "nan") { - return math.NaN(), true + if n == 3 || n == 8 { + return math.Inf(sign), nsign + n, true } - case 'i', 'I': - if equalIgnoreCase(s, "inf") || equalIgnoreCase(s, "infinity") { - return math.Inf(1), true + case 'n', 'N': + if commonPrefixLenIgnoreCase(s, "nan") == 3 { + return math.NaN(), 3, true } } - return + return 0, 0, false } func (b *decimal) set(s string) (ok bool) { @@ -159,11 +169,11 @@ func (b *decimal) set(s string) (ok bool) { return } -// readFloat reads a decimal mantissa and exponent from a float -// string representation. It returns ok==false if the number -// is invalid. -func readFloat(s string) (mantissa uint64, exp int, neg, trunc, hex, ok bool) { - i := 0 +// readFloat reads a decimal or hexadecimal mantissa and exponent from a float +// string representation in s; the number may be followed by other characters. +// readFloat reports the number of bytes consumed (i), and whether the number +// is valid (ok). +func readFloat(s string) (mantissa uint64, exp int, neg, trunc, hex bool, i int, ok bool) { underscores := false // optional sign @@ -194,6 +204,7 @@ func readFloat(s string) (mantissa uint64, exp int, neg, trunc, hex, ok bool) { nd := 0 ndMant := 0 dp := 0 +loop: for ; i < len(s); i++ { switch c := s[i]; true { case c == '_': @@ -202,7 +213,7 @@ func readFloat(s string) (mantissa uint64, exp int, neg, trunc, hex, ok bool) { case c == '.': if sawdot { - return + break loop } sawdot = true dp = nd @@ -286,15 +297,11 @@ func readFloat(s string) (mantissa uint64, exp int, neg, trunc, hex, ok bool) { return } - if i != len(s) { - return - } - if mantissa != 0 { exp = dp - ndMant } - if underscores && !underscoreOK(s) { + if underscores && !underscoreOK(s[:i]) { return } @@ -560,26 +567,26 @@ func atofHex(s string, flt *floatInfo, mantissa uint64, exp int, neg, trunc bool const fnParseFloat = "ParseFloat" -func atof32(s string) (f float32, err error) { - if val, ok := special(s); ok { - return float32(val), nil +func atof32(s string) (f float32, n int, err error) { + if val, n, ok := special(s); ok { + return float32(val), n, nil } - mantissa, exp, neg, trunc, hex, ok := readFloat(s) + mantissa, exp, neg, trunc, hex, n, ok := readFloat(s) if !ok { - return 0, syntaxError(fnParseFloat, s) + return 0, n, syntaxError(fnParseFloat, s) } if hex { - f, err := atofHex(s, &float32info, mantissa, exp, neg, trunc) - return float32(f), err + f, err := atofHex(s[:n], &float32info, mantissa, exp, neg, trunc) + return float32(f), n, err } if optimize { // Try pure floating-point arithmetic conversion. if !trunc { if f, ok := atof32exact(mantissa, exp, neg); ok { - return f, nil + return f, n, nil } } // Try another fast path. @@ -590,42 +597,43 @@ func atof32(s string) (f float32, err error) { if ovf { err = rangeError(fnParseFloat, s) } - return f, err + return f, n, err } } // Slow fallback. var d decimal - if !d.set(s) { - return 0, syntaxError(fnParseFloat, s) + if !d.set(s[:n]) { + return 0, n, syntaxError(fnParseFloat, s) } b, ovf := d.floatBits(&float32info) f = math.Float32frombits(uint32(b)) if ovf { err = rangeError(fnParseFloat, s) } - return f, err + return f, n, err } -func atof64(s string) (f float64, err error) { - if val, ok := special(s); ok { - return val, nil +func atof64(s string) (f float64, n int, err error) { + if val, n, ok := special(s); ok { + return val, n, nil } - mantissa, exp, neg, trunc, hex, ok := readFloat(s) + mantissa, exp, neg, trunc, hex, n, ok := readFloat(s) if !ok { - return 0, syntaxError(fnParseFloat, s) + return 0, n, syntaxError(fnParseFloat, s) } if hex { - return atofHex(s, &float64info, mantissa, exp, neg, trunc) + f, err := atofHex(s[:n], &float64info, mantissa, exp, neg, trunc) + return f, n, err } if optimize { // Try pure floating-point arithmetic conversion. if !trunc { if f, ok := atof64exact(mantissa, exp, neg); ok { - return f, nil + return f, n, nil } } // Try another fast path. @@ -636,21 +644,21 @@ func atof64(s string) (f float64, err error) { if ovf { err = rangeError(fnParseFloat, s) } - return f, err + return f, n, err } } // Slow fallback. var d decimal - if !d.set(s) { - return 0, syntaxError(fnParseFloat, s) + if !d.set(s[:n]) { + return 0, n, syntaxError(fnParseFloat, s) } b, ovf := d.floatBits(&float64info) f = math.Float64frombits(b) if ovf { err = rangeError(fnParseFloat, s) } - return f, err + return f, n, err } // ParseFloat converts the string s to a floating-point number @@ -675,12 +683,20 @@ func atof64(s string) (f float64, err error) { // away from the largest floating point number of the given size, // ParseFloat returns f = ±Inf, err.Err = ErrRange. // -// ParseFloat recognizes the strings "NaN", "+Inf", and "-Inf" as their -// respective special floating point values. It ignores case when matching. +// ParseFloat recognizes the strings "NaN", and the (possibly signed) strings "Inf" and "Infinity" +// as their respective special floating point values. It ignores case when matching. func ParseFloat(s string, bitSize int) (float64, error) { + f, n, err := parseFloatPrefix(s, bitSize) + if err == nil && n != len(s) { + return 0, syntaxError(fnParseFloat, s) + } + return f, err +} + +func parseFloatPrefix(s string, bitSize int) (float64, int, error) { if bitSize == 32 { - f, err := atof32(s) - return float64(f), err + f, n, err := atof32(s) + return float64(f), n, err } return atof64(s) } |