aboutsummaryrefslogtreecommitdiff
path: root/libgo/go/strconv
diff options
context:
space:
mode:
authorIan Lance Taylor <iant@golang.org>2019-09-06 18:12:46 +0000
committerIan Lance Taylor <ian@gcc.gnu.org>2019-09-06 18:12:46 +0000
commitaa8901e9bb0399d2c16f988ba2fe46eb0c0c5d13 (patch)
tree7e63b06d1eec92beec6997c9d3ab47a5d6a835be /libgo/go/strconv
parent920ea3b8ba3164b61ac9490dfdfceb6936eda6dd (diff)
downloadgcc-aa8901e9bb0399d2c16f988ba2fe46eb0c0c5d13.zip
gcc-aa8901e9bb0399d2c16f988ba2fe46eb0c0c5d13.tar.gz
gcc-aa8901e9bb0399d2c16f988ba2fe46eb0c0c5d13.tar.bz2
libgo: update to Go 1.13beta1 release
Reviewed-on: https://go-review.googlesource.com/c/gofrontend/+/193497 From-SVN: r275473
Diffstat (limited to 'libgo/go/strconv')
-rw-r--r--libgo/go/strconv/atof.go230
-rw-r--r--libgo/go/strconv/atof_test.go213
-rw-r--r--libgo/go/strconv/atoi.go109
-rw-r--r--libgo/go/strconv/atoi_test.go120
-rw-r--r--libgo/go/strconv/example_test.go29
-rw-r--r--libgo/go/strconv/extfloat.go15
-rw-r--r--libgo/go/strconv/ftoa.go161
-rw-r--r--libgo/go/strconv/ftoa_test.go31
-rw-r--r--libgo/go/strconv/isprint.go94
-rw-r--r--libgo/go/strconv/quote.go12
-rw-r--r--libgo/go/strconv/strconv_test.go10
11 files changed, 874 insertions, 150 deletions
diff --git a/libgo/go/strconv/atof.go b/libgo/go/strconv/atof.go
index fdcb8b3..eff1379 100644
--- a/libgo/go/strconv/atof.go
+++ b/libgo/go/strconv/atof.go
@@ -13,7 +13,7 @@ package strconv
import "math"
import "runtime"
-var optimize = true // can change for testing
+var optimize = true // set to false to force slow-path conversions for testing
func equalIgnoreCase(s1, s2 string) bool {
if len(s1) != len(s2) {
@@ -84,6 +84,9 @@ func (b *decimal) set(s string) (ok bool) {
sawdigits := false
for ; i < len(s); i++ {
switch {
+ case s[i] == '_':
+ // underscoreOK already called
+ continue
case s[i] == '.':
if sawdot {
return
@@ -120,7 +123,7 @@ func (b *decimal) set(s string) (ok bool) {
// just be sure to move the decimal point by
// a lot (say, 100000). it doesn't matter if it's
// not the exact number.
- if i < len(s) && (s[i] == 'e' || s[i] == 'E') {
+ if i < len(s) && lower(s[i]) == 'e' {
i++
if i >= len(s) {
return
@@ -136,7 +139,11 @@ func (b *decimal) set(s string) (ok bool) {
return
}
e := 0
- for ; i < len(s) && '0' <= s[i] && s[i] <= '9'; i++ {
+ for ; i < len(s) && ('0' <= s[i] && s[i] <= '9' || s[i] == '_'); i++ {
+ if s[i] == '_' {
+ // underscoreOK already called
+ continue
+ }
if e < 10000 {
e = e*10 + int(s[i]) - '0'
}
@@ -153,10 +160,9 @@ func (b *decimal) set(s string) (ok bool) {
}
// readFloat reads a decimal mantissa and exponent from a float
-// string representation. It sets ok to false if the number could
+// string representation. It returns ok==false if the number could
// not fit return types or is invalid.
-func readFloat(s string) (mantissa uint64, exp int, neg, trunc, ok bool) {
- const uint64digits = 19
+func readFloat(s string) (mantissa uint64, exp int, neg, trunc, hex, ok bool) {
i := 0
// optional sign
@@ -172,6 +178,16 @@ func readFloat(s string) (mantissa uint64, exp int, neg, trunc, ok bool) {
}
// digits
+ base := uint64(10)
+ maxMantDigits := 19 // 10^19 fits in uint64
+ expChar := byte('e')
+ if i+2 < len(s) && s[i] == '0' && lower(s[i+1]) == 'x' {
+ base = 16
+ maxMantDigits = 16 // 16^16 fits in uint64
+ i += 2
+ expChar = 'p'
+ hex = true
+ }
sawdot := false
sawdigits := false
nd := 0
@@ -179,6 +195,10 @@ func readFloat(s string) (mantissa uint64, exp int, neg, trunc, ok bool) {
dp := 0
for ; i < len(s); i++ {
switch c := s[i]; true {
+ case c == '_':
+ // underscoreOK already called
+ continue
+
case c == '.':
if sawdot {
return
@@ -194,11 +214,23 @@ func readFloat(s string) (mantissa uint64, exp int, neg, trunc, ok bool) {
continue
}
nd++
- if ndMant < uint64digits {
- mantissa *= 10
+ if ndMant < maxMantDigits {
+ mantissa *= base
mantissa += uint64(c - '0')
ndMant++
- } else if s[i] != '0' {
+ } else if c != '0' {
+ trunc = true
+ }
+ continue
+
+ case base == 16 && 'a' <= lower(c) && lower(c) <= 'f':
+ sawdigits = true
+ nd++
+ if ndMant < maxMantDigits {
+ mantissa *= 16
+ mantissa += uint64(lower(c) - 'a' + 10)
+ ndMant++
+ } else {
trunc = true
}
continue
@@ -212,12 +244,17 @@ func readFloat(s string) (mantissa uint64, exp int, neg, trunc, ok bool) {
dp = nd
}
+ if base == 16 {
+ dp *= 4
+ ndMant *= 4
+ }
+
// optional exponent moves decimal point.
// if we read a very large, very long number,
// just be sure to move the decimal point by
// a lot (say, 100000). it doesn't matter if it's
// not the exact number.
- if i < len(s) && (s[i] == 'e' || s[i] == 'E') {
+ if i < len(s) && lower(s[i]) == expChar {
i++
if i >= len(s) {
return
@@ -233,12 +270,19 @@ func readFloat(s string) (mantissa uint64, exp int, neg, trunc, ok bool) {
return
}
e := 0
- for ; i < len(s) && '0' <= s[i] && s[i] <= '9'; i++ {
+ for ; i < len(s) && ('0' <= s[i] && s[i] <= '9' || s[i] == '_'); i++ {
+ if s[i] == '_' {
+ // underscoreOK already called
+ continue
+ }
if e < 10000 {
e = e*10 + int(s[i]) - '0'
}
}
dp += e * esign
+ } else if base == 16 {
+ // Must have exponent.
+ return
}
if i != len(s) {
@@ -250,7 +294,6 @@ func readFloat(s string) (mantissa uint64, exp int, neg, trunc, ok bool) {
}
ok = true
return
-
}
// decimal power of ten to binary power of two.
@@ -439,6 +482,76 @@ func atof32exact(mantissa uint64, exp int, neg bool) (f float32, ok bool) {
return
}
+// atofHex converts the hex floating-point string s
+// to a rounded float32 or float64 value (depending on flt==&float32info or flt==&float64info)
+// and returns it as a float64.
+// The string s has already been parsed into a mantissa, exponent, and sign (neg==true for negative).
+// If trunc is true, trailing non-zero bits have been omitted from the mantissa.
+func atofHex(s string, flt *floatInfo, mantissa uint64, exp int, neg, trunc bool) (float64, error) {
+ maxExp := 1<<flt.expbits + flt.bias - 2
+ minExp := flt.bias + 1
+ exp += int(flt.mantbits) // mantissa now implicitly divided by 2^mantbits.
+
+ // Shift mantissa and exponent to bring representation into float range.
+ // Eventually we want a mantissa with a leading 1-bit followed by mantbits other bits.
+ // For rounding, we need two more, where the bottom bit represents
+ // whether that bit or any later bit was non-zero.
+ // (If the mantissa has already lost non-zero bits, trunc is true,
+ // and we OR in a 1 below after shifting left appropriately.)
+ for mantissa != 0 && mantissa>>(flt.mantbits+2) == 0 {
+ mantissa <<= 1
+ exp--
+ }
+ if trunc {
+ mantissa |= 1
+ }
+ for mantissa>>(1+flt.mantbits+2) != 0 {
+ mantissa = mantissa>>1 | mantissa&1
+ exp++
+ }
+
+ // If exponent is too negative,
+ // denormalize in hopes of making it representable.
+ // (The -2 is for the rounding bits.)
+ for mantissa > 1 && exp < minExp-2 {
+ mantissa = mantissa>>1 | mantissa&1
+ exp++
+ }
+
+ // Round using two bottom bits.
+ round := mantissa & 3
+ mantissa >>= 2
+ round |= mantissa & 1 // round to even (round up if mantissa is odd)
+ exp += 2
+ if round == 3 {
+ mantissa++
+ if mantissa == 1<<(1+flt.mantbits) {
+ mantissa >>= 1
+ exp++
+ }
+ }
+
+ if mantissa>>flt.mantbits == 0 { // Denormal or zero.
+ exp = flt.bias
+ }
+ var err error
+ if exp > maxExp { // infinity and range error
+ mantissa = 1 << flt.mantbits
+ exp = maxExp + 1
+ err = rangeError(fnParseFloat, s)
+ }
+
+ bits := mantissa & (1<<flt.mantbits - 1)
+ bits |= uint64((exp-flt.bias)&(1<<flt.expbits-1)) << flt.mantbits
+ if neg {
+ bits |= 1 << flt.mantbits << flt.expbits
+ }
+ if flt == &float32info {
+ return float64(math.Float32frombits(uint32(bits))), err
+ }
+ return math.Float64frombits(bits), err
+}
+
const fnParseFloat = "ParseFloat"
func atof32(s string) (f float32, err error) {
@@ -446,28 +559,32 @@ func atof32(s string) (f float32, err error) {
return float32(val), nil
}
- if optimize {
- // Parse mantissa and exponent.
- mantissa, exp, neg, trunc, ok := readFloat(s)
- if ok {
- // Try pure floating-point arithmetic conversion.
- if !trunc {
- if f, ok := atof32exact(mantissa, exp, neg); ok {
- return f, nil
- }
+ mantissa, exp, neg, trunc, hex, ok := readFloat(s)
+ if hex && ok {
+ f, err := atofHex(s, &float32info, mantissa, exp, neg, trunc)
+ return float32(f), err
+ }
+
+ if optimize && ok {
+ // Try pure floating-point arithmetic conversion.
+ if !trunc {
+ if f, ok := atof32exact(mantissa, exp, neg); ok {
+ return f, nil
}
- // Try another fast path.
- ext := new(extFloat)
- if ok := ext.AssignDecimal(mantissa, exp, neg, trunc, &float32info); ok {
- b, ovf := ext.floatBits(&float32info)
- f = math.Float32frombits(uint32(b))
- if ovf {
- err = rangeError(fnParseFloat, s)
- }
- return f, err
+ }
+ // Try another fast path.
+ ext := new(extFloat)
+ if ok := ext.AssignDecimal(mantissa, exp, neg, trunc, &float32info); ok {
+ b, ovf := ext.floatBits(&float32info)
+ f = math.Float32frombits(uint32(b))
+ if ovf {
+ err = rangeError(fnParseFloat, s)
}
+ return f, err
}
}
+
+ // Slow fallback.
var d decimal
if !d.set(s) {
return 0, syntaxError(fnParseFloat, s)
@@ -485,28 +602,31 @@ func atof64(s string) (f float64, err error) {
return val, nil
}
- if optimize {
- // Parse mantissa and exponent.
- mantissa, exp, neg, trunc, ok := readFloat(s)
- if ok {
- // Try pure floating-point arithmetic conversion.
- if !trunc {
- if f, ok := atof64exact(mantissa, exp, neg); ok {
- return f, nil
- }
+ mantissa, exp, neg, trunc, hex, ok := readFloat(s)
+ if hex && ok {
+ return atofHex(s, &float64info, mantissa, exp, neg, trunc)
+ }
+
+ if optimize && ok {
+ // Try pure floating-point arithmetic conversion.
+ if !trunc {
+ if f, ok := atof64exact(mantissa, exp, neg); ok {
+ return f, nil
}
- // Try another fast path.
- ext := new(extFloat)
- if ok := ext.AssignDecimal(mantissa, exp, neg, trunc, &float64info); ok {
- b, ovf := ext.floatBits(&float64info)
- f = math.Float64frombits(b)
- if ovf {
- err = rangeError(fnParseFloat, s)
- }
- return f, err
+ }
+ // Try another fast path.
+ ext := new(extFloat)
+ if ok := ext.AssignDecimal(mantissa, exp, neg, trunc, &float64info); ok {
+ b, ovf := ext.floatBits(&float64info)
+ f = math.Float64frombits(b)
+ if ovf {
+ err = rangeError(fnParseFloat, s)
}
+ return f, err
}
}
+
+ // Slow fallback.
var d decimal
if !d.set(s) {
return 0, syntaxError(fnParseFloat, s)
@@ -524,9 +644,13 @@ func atof64(s string) (f float64, err error) {
// When bitSize=32, the result still has type float64, but it will be
// convertible to float32 without changing its value.
//
-// If s is well-formed and near a valid floating point number,
-// ParseFloat returns the nearest floating point number rounded
+// ParseFloat accepts decimal and hexadecimal floating-point number syntax.
+// If s is well-formed and near a valid floating-point number,
+// ParseFloat returns the nearest floating-point number rounded
// using IEEE754 unbiased rounding.
+// (Parsing a hexadecimal floating-point value only rounds when
+// there are more bits in the hexadecimal representatiton than
+// will fit in the mantissa.)
//
// The errors that ParseFloat returns have concrete type *NumError
// and include err.Num = s.
@@ -536,7 +660,13 @@ func atof64(s string) (f float64, err error) {
// If s is syntactically well-formed but is more than 1/2 ULP
// 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.
func ParseFloat(s string, bitSize int) (float64, error) {
+ if !underscoreOK(s) {
+ return 0, syntaxError(fnParseFloat, s)
+ }
if bitSize == 32 {
f, err := atof32(s)
return float64(f), err
diff --git a/libgo/go/strconv/atof_test.go b/libgo/go/strconv/atof_test.go
index cf4d47c..abe6c64 100644
--- a/libgo/go/strconv/atof_test.go
+++ b/libgo/go/strconv/atof_test.go
@@ -43,6 +43,23 @@ var atoftests = []atofTest{
{"1e-20", "1e-20", nil},
{"625e-3", "0.625", nil},
+ // Hexadecimal floating-point.
+ {"0x1p0", "1", nil},
+ {"0x1p1", "2", nil},
+ {"0x1p-1", "0.5", nil},
+ {"0x1ep-1", "15", nil},
+ {"-0x1ep-1", "-15", nil},
+ {"-0x1_ep-1", "-15", nil},
+ {"0x1p-200", "6.223015277861142e-61", nil},
+ {"0x1p200", "1.6069380442589903e+60", nil},
+ {"0x1fFe2.p0", "131042", nil},
+ {"0x1fFe2.P0", "131042", nil},
+ {"-0x2p3", "-16", nil},
+ {"0x0.fp4", "15", nil},
+ {"0x0.fp0", "0.9375", nil},
+ {"0x1e2", "0", ErrSyntax},
+ {"1p2", "0", ErrSyntax},
+
// zeros
{"0", "0", nil},
{"0e0", "0", nil},
@@ -58,6 +75,11 @@ var atoftests = []atofTest{
{"0.00e-01234567890123456789", "0", nil},
{"-0e+01234567890123456789", "-0", nil},
{"-0.00e-01234567890123456789", "-0", nil},
+ {"0x0p+01234567890123456789", "0", nil},
+ {"0x0.00p-01234567890123456789", "0", nil},
+ {"-0x0p+01234567890123456789", "-0", nil},
+ {"-0x0.00p-01234567890123456789", "-0", nil},
+
{"0e291", "0", nil}, // issue 15364
{"0e292", "0", nil}, // issue 15364
{"0e347", "0", nil}, // issue 15364
@@ -66,6 +88,26 @@ var atoftests = []atofTest{
{"-0e292", "-0", nil},
{"-0e347", "-0", nil},
{"-0e348", "-0", nil},
+ {"0x0p126", "0", nil},
+ {"0x0p127", "0", nil},
+ {"0x0p128", "0", nil},
+ {"0x0p129", "0", nil},
+ {"0x0p130", "0", nil},
+ {"0x0p1022", "0", nil},
+ {"0x0p1023", "0", nil},
+ {"0x0p1024", "0", nil},
+ {"0x0p1025", "0", nil},
+ {"0x0p1026", "0", nil},
+ {"-0x0p126", "-0", nil},
+ {"-0x0p127", "-0", nil},
+ {"-0x0p128", "-0", nil},
+ {"-0x0p129", "-0", nil},
+ {"-0x0p130", "-0", nil},
+ {"-0x0p1022", "-0", nil},
+ {"-0x0p1023", "-0", nil},
+ {"-0x0p1024", "-0", nil},
+ {"-0x0p1025", "-0", nil},
+ {"-0x0p1026", "-0", nil},
// NaNs
{"nan", "NaN", nil},
@@ -83,21 +125,46 @@ var atoftests = []atofTest{
// largest float64
{"1.7976931348623157e308", "1.7976931348623157e+308", nil},
{"-1.7976931348623157e308", "-1.7976931348623157e+308", nil},
+ {"0x1.fffffffffffffp1023", "1.7976931348623157e+308", nil},
+ {"-0x1.fffffffffffffp1023", "-1.7976931348623157e+308", nil},
+ {"0x1fffffffffffffp+971", "1.7976931348623157e+308", nil},
+ {"-0x1fffffffffffffp+971", "-1.7976931348623157e+308", nil},
+ {"0x.1fffffffffffffp1027", "1.7976931348623157e+308", nil},
+ {"-0x.1fffffffffffffp1027", "-1.7976931348623157e+308", nil},
+
// next float64 - too large
{"1.7976931348623159e308", "+Inf", ErrRange},
{"-1.7976931348623159e308", "-Inf", ErrRange},
+ {"0x1p1024", "+Inf", ErrRange},
+ {"-0x1p1024", "-Inf", ErrRange},
+ {"0x2p1023", "+Inf", ErrRange},
+ {"-0x2p1023", "-Inf", ErrRange},
+ {"0x.1p1028", "+Inf", ErrRange},
+ {"-0x.1p1028", "-Inf", ErrRange},
+ {"0x.2p1027", "+Inf", ErrRange},
+ {"-0x.2p1027", "-Inf", ErrRange},
+
// the border is ...158079
// borderline - okay
{"1.7976931348623158e308", "1.7976931348623157e+308", nil},
{"-1.7976931348623158e308", "-1.7976931348623157e+308", nil},
+ {"0x1.fffffffffffff7fffp1023", "1.7976931348623157e+308", nil},
+ {"-0x1.fffffffffffff7fffp1023", "-1.7976931348623157e+308", nil},
// borderline - too large
{"1.797693134862315808e308", "+Inf", ErrRange},
{"-1.797693134862315808e308", "-Inf", ErrRange},
+ {"0x1.fffffffffffff8p1023", "+Inf", ErrRange},
+ {"-0x1.fffffffffffff8p1023", "-Inf", ErrRange},
+ {"0x1fffffffffffff.8p+971", "+Inf", ErrRange},
+ {"-0x1fffffffffffff8p+967", "-Inf", ErrRange},
+ {"0x.1fffffffffffff8p1027", "+Inf", ErrRange},
+ {"-0x.1fffffffffffff9p1027", "-Inf", ErrRange},
// a little too large
{"1e308", "1e+308", nil},
{"2e308", "+Inf", ErrRange},
{"1e309", "+Inf", ErrRange},
+ {"0x1p1025", "+Inf", ErrRange},
// way too large
{"1e310", "+Inf", ErrRange},
@@ -106,6 +173,12 @@ var atoftests = []atofTest{
{"-1e400", "-Inf", ErrRange},
{"1e400000", "+Inf", ErrRange},
{"-1e400000", "-Inf", ErrRange},
+ {"0x1p1030", "+Inf", ErrRange},
+ {"0x1p2000", "+Inf", ErrRange},
+ {"0x1p2000000000", "+Inf", ErrRange},
+ {"-0x1p1030", "-Inf", ErrRange},
+ {"-0x1p2000", "-Inf", ErrRange},
+ {"-0x1p2000000000", "-Inf", ErrRange},
// denormalized
{"1e-305", "1e-305", nil},
@@ -125,17 +198,75 @@ var atoftests = []atofTest{
{"1e-350", "0", nil},
{"1e-400000", "0", nil},
+ // Near denormals and denormals.
+ {"0x2.00000000000000p-1010", "1.8227805048890994e-304", nil}, // 0x00e0000000000000
+ {"0x1.fffffffffffff0p-1010", "1.8227805048890992e-304", nil}, // 0x00dfffffffffffff
+ {"0x1.fffffffffffff7p-1010", "1.8227805048890992e-304", nil}, // rounded down
+ {"0x1.fffffffffffff8p-1010", "1.8227805048890994e-304", nil}, // rounded up
+ {"0x1.fffffffffffff9p-1010", "1.8227805048890994e-304", nil}, // rounded up
+
+ {"0x2.00000000000000p-1022", "4.450147717014403e-308", nil}, // 0x0020000000000000
+ {"0x1.fffffffffffff0p-1022", "4.4501477170144023e-308", nil}, // 0x001fffffffffffff
+ {"0x1.fffffffffffff7p-1022", "4.4501477170144023e-308", nil}, // rounded down
+ {"0x1.fffffffffffff8p-1022", "4.450147717014403e-308", nil}, // rounded up
+ {"0x1.fffffffffffff9p-1022", "4.450147717014403e-308", nil}, // rounded up
+
+ {"0x1.00000000000000p-1022", "2.2250738585072014e-308", nil}, // 0x0010000000000000
+ {"0x0.fffffffffffff0p-1022", "2.225073858507201e-308", nil}, // 0x000fffffffffffff
+ {"0x0.ffffffffffffe0p-1022", "2.2250738585072004e-308", nil}, // 0x000ffffffffffffe
+ {"0x0.ffffffffffffe7p-1022", "2.2250738585072004e-308", nil}, // rounded down
+ {"0x1.ffffffffffffe8p-1023", "2.225073858507201e-308", nil}, // rounded up
+ {"0x1.ffffffffffffe9p-1023", "2.225073858507201e-308", nil}, // rounded up
+
+ {"0x0.00000003fffff0p-1022", "2.072261e-317", nil}, // 0x00000000003fffff
+ {"0x0.00000003456780p-1022", "1.694649e-317", nil}, // 0x0000000000345678
+ {"0x0.00000003456787p-1022", "1.694649e-317", nil}, // rounded down
+ {"0x0.00000003456788p-1022", "1.694649e-317", nil}, // rounded down (half to even)
+ {"0x0.00000003456790p-1022", "1.6946496e-317", nil}, // 0x0000000000345679
+ {"0x0.00000003456789p-1022", "1.6946496e-317", nil}, // rounded up
+
+ {"0x0.0000000345678800000000000000000000000001p-1022", "1.6946496e-317", nil}, // rounded up
+
+ {"0x0.000000000000f0p-1022", "7.4e-323", nil}, // 0x000000000000000f
+ {"0x0.00000000000060p-1022", "3e-323", nil}, // 0x0000000000000006
+ {"0x0.00000000000058p-1022", "3e-323", nil}, // rounded up
+ {"0x0.00000000000057p-1022", "2.5e-323", nil}, // rounded down
+ {"0x0.00000000000050p-1022", "2.5e-323", nil}, // 0x0000000000000005
+
+ {"0x0.00000000000010p-1022", "5e-324", nil}, // 0x0000000000000001
+ {"0x0.000000000000081p-1022", "5e-324", nil}, // rounded up
+ {"0x0.00000000000008p-1022", "0", nil}, // rounded down
+ {"0x0.00000000000007fp-1022", "0", nil}, // rounded down
+
// try to overflow exponent
{"1e-4294967296", "0", nil},
{"1e+4294967296", "+Inf", ErrRange},
{"1e-18446744073709551616", "0", nil},
{"1e+18446744073709551616", "+Inf", ErrRange},
+ {"0x1p-4294967296", "0", nil},
+ {"0x1p+4294967296", "+Inf", ErrRange},
+ {"0x1p-18446744073709551616", "0", nil},
+ {"0x1p+18446744073709551616", "+Inf", ErrRange},
// Parse errors
{"1e", "0", ErrSyntax},
{"1e-", "0", ErrSyntax},
{".e-1", "0", ErrSyntax},
{"1\x00.2", "0", ErrSyntax},
+ {"0x", "0", ErrSyntax},
+ {"0x.", "0", ErrSyntax},
+ {"0x1", "0", ErrSyntax},
+ {"0x.1", "0", ErrSyntax},
+ {"0x1p", "0", ErrSyntax},
+ {"0x.1p", "0", ErrSyntax},
+ {"0x1p+", "0", ErrSyntax},
+ {"0x.1p+", "0", ErrSyntax},
+ {"0x1p-", "0", ErrSyntax},
+ {"0x.1p-", "0", ErrSyntax},
+ {"0x1p+2", "4", nil},
+ {"0x.1p+2", "0.25", nil},
+ {"0x1p-2", "0.25", nil},
+ {"0x.1p-2", "0.015625", nil},
// https://www.exploringbinary.com/java-hangs-when-converting-2-2250738585072012e-308/
{"2.2250738585072012e-308", "2.2250738585072014e-308", nil},
@@ -148,42 +279,109 @@ var atoftests = []atofTest{
// A different kind of very large number.
{"22.222222222222222", "22.22222222222222", nil},
{"2." + strings.Repeat("2", 4000) + "e+1", "22.22222222222222", nil},
+ {"0x1.1111111111111p222", "7.18931911124017e+66", nil},
+ {"0x2.2222222222222p221", "7.18931911124017e+66", nil},
+ {"0x2." + strings.Repeat("2", 4000) + "p221", "7.18931911124017e+66", nil},
// Exactly halfway between 1 and math.Nextafter(1, 2).
// Round to even (down).
{"1.00000000000000011102230246251565404236316680908203125", "1", nil},
+ {"0x1.00000000000008p0", "1", nil},
// Slightly lower; still round down.
{"1.00000000000000011102230246251565404236316680908203124", "1", nil},
+ {"0x1.00000000000007Fp0", "1", nil},
// Slightly higher; round up.
{"1.00000000000000011102230246251565404236316680908203126", "1.0000000000000002", nil},
+ {"0x1.000000000000081p0", "1.0000000000000002", nil},
+ {"0x1.00000000000009p0", "1.0000000000000002", nil},
// Slightly higher, but you have to read all the way to the end.
{"1.00000000000000011102230246251565404236316680908203125" + strings.Repeat("0", 10000) + "1", "1.0000000000000002", nil},
+ {"0x1.00000000000008" + strings.Repeat("0", 10000) + "1p0", "1.0000000000000002", nil},
+
+ // Halfway between x := math.Nextafter(1, 2) and math.Nextafter(x, 2)
+ // Round to even (up).
+ {"1.00000000000000033306690738754696212708950042724609375", "1.0000000000000004", nil},
+ {"0x1.00000000000018p0", "1.0000000000000004", nil},
+
+ // Underscores.
+ {"1_23.50_0_0e+1_2", "1.235e+14", nil},
+ {"-_123.5e+12", "0", ErrSyntax},
+ {"+_123.5e+12", "0", ErrSyntax},
+ {"_123.5e+12", "0", ErrSyntax},
+ {"1__23.5e+12", "0", ErrSyntax},
+ {"123_.5e+12", "0", ErrSyntax},
+ {"123._5e+12", "0", ErrSyntax},
+ {"123.5_e+12", "0", ErrSyntax},
+ {"123.5__0e+12", "0", ErrSyntax},
+ {"123.5e_+12", "0", ErrSyntax},
+ {"123.5e+_12", "0", ErrSyntax},
+ {"123.5e_-12", "0", ErrSyntax},
+ {"123.5e-_12", "0", ErrSyntax},
+ {"123.5e+1__2", "0", ErrSyntax},
+ {"123.5e+12_", "0", ErrSyntax},
+
+ {"0x_1_2.3_4_5p+1_2", "74565", nil},
+ {"-_0x12.345p+12", "0", ErrSyntax},
+ {"+_0x12.345p+12", "0", ErrSyntax},
+ {"_0x12.345p+12", "0", ErrSyntax},
+ {"0x__12.345p+12", "0", ErrSyntax},
+ {"0x1__2.345p+12", "0", ErrSyntax},
+ {"0x12_.345p+12", "0", ErrSyntax},
+ {"0x12._345p+12", "0", ErrSyntax},
+ {"0x12.3__45p+12", "0", ErrSyntax},
+ {"0x12.345_p+12", "0", ErrSyntax},
+ {"0x12.345p_+12", "0", ErrSyntax},
+ {"0x12.345p+_12", "0", ErrSyntax},
+ {"0x12.345p_-12", "0", ErrSyntax},
+ {"0x12.345p-_12", "0", ErrSyntax},
+ {"0x12.345p+1__2", "0", ErrSyntax},
+ {"0x12.345p+12_", "0", ErrSyntax},
}
var atof32tests = []atofTest{
+ // Hex
+ {"0x1p-100", "7.888609e-31", nil},
+ {"0x1p100", "1.2676506e+30", nil},
+
// Exactly halfway between 1 and the next float32.
// Round to even (down).
{"1.000000059604644775390625", "1", nil},
+ {"0x1.000001p0", "1", nil},
// Slightly lower.
{"1.000000059604644775390624", "1", nil},
+ {"0x1.0000008p0", "1", nil},
+ {"0x1.000000fp0", "1", nil},
// Slightly higher.
{"1.000000059604644775390626", "1.0000001", nil},
+ {"0x1.000002p0", "1.0000001", nil},
+ {"0x1.0000018p0", "1.0000001", nil},
+ {"0x1.0000011p0", "1.0000001", nil},
// Slightly higher, but you have to read all the way to the end.
{"1.000000059604644775390625" + strings.Repeat("0", 10000) + "1", "1.0000001", nil},
+ {"0x1.000001" + strings.Repeat("0", 10000) + "1p0", "1.0000001", nil},
// largest float32: (1<<128) * (1 - 2^-24)
{"340282346638528859811704183484516925440", "3.4028235e+38", nil},
{"-340282346638528859811704183484516925440", "-3.4028235e+38", nil},
+ {"0x.ffffffp128", "3.4028235e+38", nil},
+ {"-340282346638528859811704183484516925440", "-3.4028235e+38", nil},
+ {"-0x.ffffffp128", "-3.4028235e+38", nil},
// next float32 - too large
{"3.4028236e38", "+Inf", ErrRange},
{"-3.4028236e38", "-Inf", ErrRange},
+ {"0x1.0p128", "+Inf", ErrRange},
+ {"-0x1.0p128", "-Inf", ErrRange},
// the border is 3.40282356779...e+38
// borderline - okay
{"3.402823567e38", "3.4028235e+38", nil},
{"-3.402823567e38", "-3.4028235e+38", nil},
+ {"0x.ffffff7fp128", "3.4028235e+38", nil},
+ {"-0x.ffffff7fp128", "-3.4028235e+38", nil},
// borderline - too large
{"3.4028235678e38", "+Inf", ErrRange},
{"-3.4028235678e38", "-Inf", ErrRange},
+ {"0x.ffffff8p128", "+Inf", ErrRange},
+ {"-0x.ffffff8p128", "-Inf", ErrRange},
// Denormals: less than 2^-126
{"1e-38", "1e-38", nil},
@@ -195,9 +393,24 @@ var atof32tests = []atofTest{
{"1e-44", "1e-44", nil},
{"6e-45", "6e-45", nil}, // 4p-149 = 5.6e-45
{"5e-45", "6e-45", nil},
+
// Smallest denormal
{"1e-45", "1e-45", nil}, // 1p-149 = 1.4e-45
{"2e-45", "1e-45", nil},
+ {"3e-45", "3e-45", nil},
+
+ // Near denormals and denormals.
+ {"0x0.89aBcDp-125", "1.2643093e-38", nil}, // 0x0089abcd
+ {"0x0.8000000p-125", "1.1754944e-38", nil}, // 0x00800000
+ {"0x0.1234560p-125", "1.671814e-39", nil}, // 0x00123456
+ {"0x0.1234567p-125", "1.671814e-39", nil}, // rounded down
+ {"0x0.1234568p-125", "1.671814e-39", nil}, // rounded down
+ {"0x0.1234569p-125", "1.671815e-39", nil}, // rounded up
+ {"0x0.1234570p-125", "1.671815e-39", nil}, // 0x00123457
+ {"0x0.0000010p-125", "1e-45", nil}, // 0x00000001
+ {"0x0.00000081p-125", "1e-45", nil}, // rounded up
+ {"0x0.0000008p-125", "0", nil}, // rounded down
+ {"0x0.0000007p-125", "0", nil}, // rounded down
// 2^92 = 8388608p+69 = 4951760157141521099596496896 (4.9517602e27)
// is an exact power of two that needs 8 decimal digits to be correctly
diff --git a/libgo/go/strconv/atoi.go b/libgo/go/strconv/atoi.go
index ff33d55..31774d0 100644
--- a/libgo/go/strconv/atoi.go
+++ b/libgo/go/strconv/atoi.go
@@ -6,6 +6,14 @@ package strconv
import "errors"
+// lower(c) is a lower-case letter if and only if
+// c is either that lower-case letter or the equivalent upper-case letter.
+// Instead of writing c == 'x' || c == 'X' one can write lower(c) == 'x'.
+// Note that lower of non-letters can produce other non-letters.
+func lower(c byte) byte {
+ return c | ('x' - 'X')
+}
+
// ErrRange indicates that a value is out of range for the target type.
var ErrRange = errors.New("value out of range")
@@ -50,10 +58,12 @@ const maxUint64 = 1<<64 - 1
func ParseUint(s string, base int, bitSize int) (uint64, error) {
const fnParseUint = "ParseUint"
- if len(s) == 0 {
+ if s == "" || !underscoreOK(s) {
return 0, syntaxError(fnParseUint, s)
}
+ base0 := base == 0
+
s0 := s
switch {
case 2 <= base && base <= 36:
@@ -61,18 +71,22 @@ func ParseUint(s string, base int, bitSize int) (uint64, error) {
case base == 0:
// Look for octal, hex prefix.
- switch {
- case s[0] == '0' && len(s) > 1 && (s[1] == 'x' || s[1] == 'X'):
- if len(s) < 3 {
- return 0, syntaxError(fnParseUint, s0)
+ base = 10
+ if s[0] == '0' {
+ switch {
+ case len(s) >= 3 && lower(s[1]) == 'b':
+ base = 2
+ s = s[2:]
+ case len(s) >= 3 && lower(s[1]) == 'o':
+ base = 8
+ s = s[2:]
+ case len(s) >= 3 && lower(s[1]) == 'x':
+ base = 16
+ s = s[2:]
+ default:
+ base = 8
+ s = s[1:]
}
- base = 16
- s = s[2:]
- case s[0] == '0':
- base = 8
- s = s[1:]
- default:
- base = 10
}
default:
@@ -103,12 +117,13 @@ func ParseUint(s string, base int, bitSize int) (uint64, error) {
for _, c := range []byte(s) {
var d byte
switch {
+ case c == '_' && base0:
+ // underscoreOK already called
+ continue
case '0' <= c && c <= '9':
d = c - '0'
- case 'a' <= c && c <= 'z':
- d = c - 'a' + 10
- case 'A' <= c && c <= 'Z':
- d = c - 'A' + 10
+ case 'a' <= lower(c) && lower(c) <= 'z':
+ d = lower(c) - 'a' + 10
default:
return 0, syntaxError(fnParseUint, s0)
}
@@ -138,13 +153,14 @@ func ParseUint(s string, base int, bitSize int) (uint64, error) {
// bit size (0 to 64) and returns the corresponding value i.
//
// If base == 0, the base is implied by the string's prefix:
-// base 16 for "0x", base 8 for "0", and base 10 otherwise.
-// For bases 1, below 0 or above 36 an error is returned.
+// base 2 for "0b", base 8 for "0" or "0o", base 16 for "0x",
+// and base 10 otherwise.
+// If base is below 0, is 1, or is above 36, an error is returned.
//
// The bitSize argument specifies the integer type
// that the result must fit into. Bit sizes 0, 8, 16, 32, and 64
// correspond to int, int8, int16, int32, and int64.
-// For a bitSize below 0 or above 64 an error is returned.
+// If bitSize is below 0 or above 64, an error is returned.
//
// The errors that ParseInt returns have concrete type *NumError
// and include err.Num = s. If s is empty or contains invalid
@@ -156,8 +172,7 @@ func ParseUint(s string, base int, bitSize int) (uint64, error) {
func ParseInt(s string, base int, bitSize int) (i int64, err error) {
const fnParseInt = "ParseInt"
- // Empty string bad.
- if len(s) == 0 {
+ if s == "" {
return 0, syntaxError(fnParseInt, s)
}
@@ -228,10 +243,60 @@ func Atoi(s string) (int, error) {
return n, nil
}
- // Slow path for invalid or big integers.
+ // Slow path for invalid, big, or underscored integers.
i64, err := ParseInt(s, 10, 0)
if nerr, ok := err.(*NumError); ok {
nerr.Func = fnAtoi
}
return int(i64), err
}
+
+// underscoreOK reports whether the underscores in s are allowed.
+// Checking them in this one function lets all the parsers skip over them simply.
+// Underscore must appear only between digits or between a base prefix and a digit.
+func underscoreOK(s string) bool {
+ // saw tracks the last character (class) we saw:
+ // ^ for beginning of number,
+ // 0 for a digit or base prefix,
+ // _ for an underscore,
+ // ! for none of the above.
+ saw := '^'
+ i := 0
+
+ // Optional sign.
+ if len(s) >= 1 && (s[0] == '-' || s[0] == '+') {
+ s = s[1:]
+ }
+
+ // Optional base prefix.
+ hex := false
+ if len(s) >= 2 && s[0] == '0' && (lower(s[1]) == 'b' || lower(s[1]) == 'o' || lower(s[1]) == 'x') {
+ i = 2
+ saw = '0' // base prefix counts as a digit for "underscore as digit separator"
+ hex = lower(s[1]) == 'x'
+ }
+
+ // Number proper.
+ for ; i < len(s); i++ {
+ // Digits are always okay.
+ if '0' <= s[i] && s[i] <= '9' || hex && 'a' <= lower(s[i]) && lower(s[i]) <= 'f' {
+ saw = '0'
+ continue
+ }
+ // Underscore must follow digit.
+ if s[i] == '_' {
+ if saw != '0' {
+ return false
+ }
+ saw = '_'
+ continue
+ }
+ // Underscore must also be followed by digit.
+ if saw == '_' {
+ return false
+ }
+ // Saw non-digit, non-underscore.
+ saw = '!'
+ }
+ return saw != '_'
+}
diff --git a/libgo/go/strconv/atoi_test.go b/libgo/go/strconv/atoi_test.go
index e2f505a..b167c96 100644
--- a/libgo/go/strconv/atoi_test.go
+++ b/libgo/go/strconv/atoi_test.go
@@ -29,6 +29,10 @@ var parseUint64Tests = []parseUint64Test{
{"18446744073709551615", 1<<64 - 1, nil},
{"18446744073709551616", 1<<64 - 1, ErrRange},
{"18446744073709551620", 1<<64 - 1, ErrRange},
+ {"1_2_3_4_5", 0, ErrSyntax}, // base=10 so no underscores allowed
+ {"_12345", 0, ErrSyntax},
+ {"1__2345", 0, ErrSyntax},
+ {"12345_", 0, ErrSyntax},
}
type parseUint64BaseTest struct {
@@ -61,6 +65,69 @@ var parseUint64BaseTests = []parseUint64BaseTest{
{"01777777777777777777778", 0, 0, ErrSyntax},
{"02000000000000000000000", 0, 1<<64 - 1, ErrRange},
{"0200000000000000000000", 0, 1 << 61, nil},
+ {"0b", 0, 0, ErrSyntax},
+ {"0B", 0, 0, ErrSyntax},
+ {"0b101", 0, 5, nil},
+ {"0B101", 0, 5, nil},
+ {"0o", 0, 0, ErrSyntax},
+ {"0O", 0, 0, ErrSyntax},
+ {"0o377", 0, 255, nil},
+ {"0O377", 0, 255, nil},
+
+ // underscores allowed with base == 0 only
+ {"1_2_3_4_5", 0, 12345, nil}, // base 0 => 10
+ {"_12345", 0, 0, ErrSyntax},
+ {"1__2345", 0, 0, ErrSyntax},
+ {"12345_", 0, 0, ErrSyntax},
+
+ {"1_2_3_4_5", 10, 0, ErrSyntax}, // base 10
+ {"_12345", 10, 0, ErrSyntax},
+ {"1__2345", 10, 0, ErrSyntax},
+ {"12345_", 10, 0, ErrSyntax},
+
+ {"0x_1_2_3_4_5", 0, 0x12345, nil}, // base 0 => 16
+ {"_0x12345", 0, 0, ErrSyntax},
+ {"0x__12345", 0, 0, ErrSyntax},
+ {"0x1__2345", 0, 0, ErrSyntax},
+ {"0x1234__5", 0, 0, ErrSyntax},
+ {"0x12345_", 0, 0, ErrSyntax},
+
+ {"1_2_3_4_5", 16, 0, ErrSyntax}, // base 16
+ {"_12345", 16, 0, ErrSyntax},
+ {"1__2345", 16, 0, ErrSyntax},
+ {"1234__5", 16, 0, ErrSyntax},
+ {"12345_", 16, 0, ErrSyntax},
+
+ {"0_1_2_3_4_5", 0, 012345, nil}, // base 0 => 8 (0377)
+ {"_012345", 0, 0, ErrSyntax},
+ {"0__12345", 0, 0, ErrSyntax},
+ {"01234__5", 0, 0, ErrSyntax},
+ {"012345_", 0, 0, ErrSyntax},
+
+ {"0o_1_2_3_4_5", 0, 012345, nil}, // base 0 => 8 (0o377)
+ {"_0o12345", 0, 0, ErrSyntax},
+ {"0o__12345", 0, 0, ErrSyntax},
+ {"0o1234__5", 0, 0, ErrSyntax},
+ {"0o12345_", 0, 0, ErrSyntax},
+
+ {"0_1_2_3_4_5", 8, 0, ErrSyntax}, // base 8
+ {"_012345", 8, 0, ErrSyntax},
+ {"0__12345", 8, 0, ErrSyntax},
+ {"01234__5", 8, 0, ErrSyntax},
+ {"012345_", 8, 0, ErrSyntax},
+
+ {"0b_1_0_1", 0, 5, nil}, // base 0 => 2 (0b101)
+ {"_0b101", 0, 0, ErrSyntax},
+ {"0b__101", 0, 0, ErrSyntax},
+ {"0b1__01", 0, 0, ErrSyntax},
+ {"0b10__1", 0, 0, ErrSyntax},
+ {"0b101_", 0, 0, ErrSyntax},
+
+ {"1_0_1", 2, 0, ErrSyntax}, // base 2
+ {"_101", 2, 0, ErrSyntax},
+ {"1_01", 2, 0, ErrSyntax},
+ {"10_1", 2, 0, ErrSyntax},
+ {"101_", 2, 0, ErrSyntax},
}
type parseInt64Test struct {
@@ -87,6 +154,11 @@ var parseInt64Tests = []parseInt64Test{
{"-9223372036854775808", -1 << 63, nil},
{"9223372036854775809", 1<<63 - 1, ErrRange},
{"-9223372036854775809", -1 << 63, ErrRange},
+ {"-1_2_3_4_5", 0, ErrSyntax}, // base=10 so no underscores allowed
+ {"-_12345", 0, ErrSyntax},
+ {"_12345", 0, ErrSyntax},
+ {"1__2345", 0, ErrSyntax},
+ {"12345_", 0, ErrSyntax},
}
type parseInt64BaseTest struct {
@@ -144,6 +216,26 @@ var parseInt64BaseTests = []parseInt64BaseTest{
{"10", 16, 16, nil},
{"-123456789abcdef", 16, -0x123456789abcdef, nil},
{"7fffffffffffffff", 16, 1<<63 - 1, nil},
+
+ // underscores
+ {"-0x_1_2_3_4_5", 0, -0x12345, nil},
+ {"0x_1_2_3_4_5", 0, 0x12345, nil},
+ {"-_0x12345", 0, 0, ErrSyntax},
+ {"_-0x12345", 0, 0, ErrSyntax},
+ {"_0x12345", 0, 0, ErrSyntax},
+ {"0x__12345", 0, 0, ErrSyntax},
+ {"0x1__2345", 0, 0, ErrSyntax},
+ {"0x1234__5", 0, 0, ErrSyntax},
+ {"0x12345_", 0, 0, ErrSyntax},
+
+ {"-0_1_2_3_4_5", 0, -012345, nil}, // octal
+ {"0_1_2_3_4_5", 0, 012345, nil}, // octal
+ {"-_012345", 0, 0, ErrSyntax},
+ {"_-012345", 0, 0, ErrSyntax},
+ {"_012345", 0, 0, ErrSyntax},
+ {"0__12345", 0, 0, ErrSyntax},
+ {"01234__5", 0, 0, ErrSyntax},
+ {"012345_", 0, 0, ErrSyntax},
}
type parseUint32Test struct {
@@ -162,6 +254,11 @@ var parseUint32Tests = []parseUint32Test{
{"987654321", 987654321, nil},
{"4294967295", 1<<32 - 1, nil},
{"4294967296", 1<<32 - 1, ErrRange},
+ {"1_2_3_4_5", 0, ErrSyntax}, // base=10 so no underscores allowed
+ {"_12345", 0, ErrSyntax},
+ {"_12345", 0, ErrSyntax},
+ {"1__2345", 0, ErrSyntax},
+ {"12345_", 0, ErrSyntax},
}
type parseInt32Test struct {
@@ -190,6 +287,11 @@ var parseInt32Tests = []parseInt32Test{
{"-2147483648", -1 << 31, nil},
{"2147483649", 1<<31 - 1, ErrRange},
{"-2147483649", -1 << 31, ErrRange},
+ {"-1_2_3_4_5", 0, ErrSyntax}, // base=10 so no underscores allowed
+ {"-_12345", 0, ErrSyntax},
+ {"_12345", 0, ErrSyntax},
+ {"1__2345", 0, ErrSyntax},
+ {"12345_", 0, ErrSyntax},
}
type numErrorTest struct {
@@ -419,12 +521,22 @@ var parseBaseTests = []parseErrorTest{
{37, baseErrStub},
}
+func equalError(a, b error) bool {
+ if a == nil {
+ return b == nil
+ }
+ if b == nil {
+ return a == nil
+ }
+ return a.Error() == b.Error()
+}
+
func TestParseIntBitSize(t *testing.T) {
for i := range parseBitSizeTests {
test := &parseBitSizeTests[i]
testErr := test.errStub("ParseInt", test.arg)
_, err := ParseInt("0", 0, test.arg)
- if !reflect.DeepEqual(testErr, err) {
+ if !equalError(testErr, err) {
t.Errorf("ParseInt(\"0\", 0, %v) = 0, %v want 0, %v",
test.arg, err, testErr)
}
@@ -436,7 +548,7 @@ func TestParseUintBitSize(t *testing.T) {
test := &parseBitSizeTests[i]
testErr := test.errStub("ParseUint", test.arg)
_, err := ParseUint("0", 0, test.arg)
- if !reflect.DeepEqual(testErr, err) {
+ if !equalError(testErr, err) {
t.Errorf("ParseUint(\"0\", 0, %v) = 0, %v want 0, %v",
test.arg, err, testErr)
}
@@ -448,7 +560,7 @@ func TestParseIntBase(t *testing.T) {
test := &parseBaseTests[i]
testErr := test.errStub("ParseInt", test.arg)
_, err := ParseInt("0", test.arg, 0)
- if !reflect.DeepEqual(testErr, err) {
+ if !equalError(testErr, err) {
t.Errorf("ParseInt(\"0\", %v, 0) = 0, %v want 0, %v",
test.arg, err, testErr)
}
@@ -460,7 +572,7 @@ func TestParseUintBase(t *testing.T) {
test := &parseBaseTests[i]
testErr := test.errStub("ParseUint", test.arg)
_, err := ParseUint("0", test.arg, 0)
- if !reflect.DeepEqual(testErr, err) {
+ if !equalError(testErr, err) {
t.Errorf("ParseUint(\"0\", %v, 0) = 0, %v want 0, %v",
test.arg, err, testErr)
}
diff --git a/libgo/go/strconv/example_test.go b/libgo/go/strconv/example_test.go
index 2d1a2a9..50f6b20 100644
--- a/libgo/go/strconv/example_test.go
+++ b/libgo/go/strconv/example_test.go
@@ -222,10 +222,39 @@ func ExampleParseFloat() {
if s, err := strconv.ParseFloat(v, 64); err == nil {
fmt.Printf("%T, %v\n", s, s)
}
+ if s, err := strconv.ParseFloat("NaN", 32); err == nil {
+ fmt.Printf("%T, %v\n", s, s)
+ }
+ // ParseFloat is case insensitive
+ if s, err := strconv.ParseFloat("nan", 32); err == nil {
+ fmt.Printf("%T, %v\n", s, s)
+ }
+ if s, err := strconv.ParseFloat("inf", 32); err == nil {
+ fmt.Printf("%T, %v\n", s, s)
+ }
+ if s, err := strconv.ParseFloat("+Inf", 32); err == nil {
+ fmt.Printf("%T, %v\n", s, s)
+ }
+ if s, err := strconv.ParseFloat("-Inf", 32); err == nil {
+ fmt.Printf("%T, %v\n", s, s)
+ }
+ if s, err := strconv.ParseFloat("-0", 32); err == nil {
+ fmt.Printf("%T, %v\n", s, s)
+ }
+ if s, err := strconv.ParseFloat("+0", 32); err == nil {
+ fmt.Printf("%T, %v\n", s, s)
+ }
// Output:
// float64, 3.1415927410125732
// float64, 3.1415926535
+ // float64, NaN
+ // float64, NaN
+ // float64, +Inf
+ // float64, +Inf
+ // float64, -Inf
+ // float64, -0
+ // float64, 0
}
func ExampleParseInt() {
diff --git a/libgo/go/strconv/extfloat.go b/libgo/go/strconv/extfloat.go
index 32d3340..2a2dd7a 100644
--- a/libgo/go/strconv/extfloat.go
+++ b/libgo/go/strconv/extfloat.go
@@ -214,20 +214,9 @@ func (f *extFloat) Normalize() uint {
// Multiply sets f to the product f*g: the result is correctly rounded,
// but not normalized.
func (f *extFloat) Multiply(g extFloat) {
- fhi, flo := f.mant>>32, uint64(uint32(f.mant))
- ghi, glo := g.mant>>32, uint64(uint32(g.mant))
-
- // Cross products.
- cross1 := fhi * glo
- cross2 := flo * ghi
-
- // f.mant*g.mant is fhi*ghi << 64 + (cross1+cross2) << 32 + flo*glo
- f.mant = fhi*ghi + (cross1 >> 32) + (cross2 >> 32)
- rem := uint64(uint32(cross1)) + uint64(uint32(cross2)) + ((flo * glo) >> 32)
+ hi, lo := bits.Mul64(f.mant, g.mant)
// Round up.
- rem += (1 << 31)
-
- f.mant += (rem >> 32)
+ f.mant = hi + (lo >> 63)
f.exp = f.exp + g.exp + 64
}
diff --git a/libgo/go/strconv/ftoa.go b/libgo/go/strconv/ftoa.go
index a7ccbe6..8ce6ef3 100644
--- a/libgo/go/strconv/ftoa.go
+++ b/libgo/go/strconv/ftoa.go
@@ -32,12 +32,14 @@ var float64info = floatInfo{52, 11, -1023}
// 'e' (-d.dddde±dd, a decimal exponent),
// 'E' (-d.ddddE±dd, a decimal exponent),
// 'f' (-ddd.dddd, no exponent),
-// 'g' ('e' for large exponents, 'f' otherwise), or
-// 'G' ('E' for large exponents, 'f' otherwise).
+// 'g' ('e' for large exponents, 'f' otherwise),
+// 'G' ('E' for large exponents, 'f' otherwise),
+// 'x' (-0xd.ddddp±ddd, a hexadecimal fraction and binary exponent), or
+// 'X' (-0Xd.ddddP±ddd, a hexadecimal fraction and binary exponent).
//
// The precision prec controls the number of digits (excluding the exponent)
-// printed by the 'e', 'E', 'f', 'g', and 'G' formats.
-// For 'e', 'E', and 'f' it is the number of digits after the decimal point.
+// printed by the 'e', 'E', 'f', 'g', 'G', 'x', and 'X' formats.
+// For 'e', 'E', 'f', 'x', and 'X', it is the number of digits after the decimal point.
// For 'g' and 'G' it is the maximum number of significant digits (trailing
// zeros are removed).
// The special precision -1 uses the smallest number of digits
@@ -94,10 +96,13 @@ func genericFtoa(dst []byte, val float64, fmt byte, prec, bitSize int) []byte {
}
exp += flt.bias
- // Pick off easy binary format.
+ // Pick off easy binary, hex formats.
if fmt == 'b' {
return fmtB(dst, neg, mant, exp, flt)
}
+ if fmt == 'x' || fmt == 'X' {
+ return fmtX(dst, prec, fmt, neg, mant, exp, flt)
+ }
if !optimize {
return bigFtoa(dst, prec, fmt, neg, mant, exp, flt)
@@ -284,39 +289,80 @@ func roundShortest(d *decimal, mant uint64, exp int, flt *floatInfo) {
// would round to the original mantissa and not the neighbors.
inclusive := mant%2 == 0
+ // As we walk the digits we want to know whether rounding up would fall
+ // within the upper bound. This is tracked by upperdelta:
+ //
+ // If upperdelta == 0, the digits of d and upper are the same so far.
+ //
+ // If upperdelta == 1, we saw a difference of 1 between d and upper on a
+ // previous digit and subsequently only 9s for d and 0s for upper.
+ // (Thus rounding up may fall outside the bound, if it is exclusive.)
+ //
+ // If upperdelta == 2, then the difference is greater than 1
+ // and we know that rounding up falls within the bound.
+ var upperdelta uint8
+
// Now we can figure out the minimum number of digits required.
// Walk along until d has distinguished itself from upper and lower.
- for i := 0; i < d.nd; i++ {
+ for ui := 0; ; ui++ {
+ // lower, d, and upper may have the decimal points at different
+ // places. In this case upper is the longest, so we iterate from
+ // ui==0 and start li and mi at (possibly) -1.
+ mi := ui - upper.dp + d.dp
+ if mi >= d.nd {
+ break
+ }
+ li := ui - upper.dp + lower.dp
l := byte('0') // lower digit
- if i < lower.nd {
- l = lower.d[i]
+ if li >= 0 && li < lower.nd {
+ l = lower.d[li]
+ }
+ m := byte('0') // middle digit
+ if mi >= 0 {
+ m = d.d[mi]
}
- m := d.d[i] // middle digit
u := byte('0') // upper digit
- if i < upper.nd {
- u = upper.d[i]
+ if ui < upper.nd {
+ u = upper.d[ui]
}
// Okay to round down (truncate) if lower has a different digit
// or if lower is inclusive and is exactly the result of rounding
// down (i.e., and we have reached the final digit of lower).
- okdown := l != m || inclusive && i+1 == lower.nd
+ okdown := l != m || inclusive && li+1 == lower.nd
+ switch {
+ case upperdelta == 0 && m+1 < u:
+ // Example:
+ // m = 12345xxx
+ // u = 12347xxx
+ upperdelta = 2
+ case upperdelta == 0 && m != u:
+ // Example:
+ // m = 12345xxx
+ // u = 12346xxx
+ upperdelta = 1
+ case upperdelta == 1 && (m != '9' || u != '0'):
+ // Example:
+ // m = 1234598x
+ // u = 1234600x
+ upperdelta = 2
+ }
// Okay to round up if upper has a different digit and either upper
// is inclusive or upper is bigger than the result of rounding up.
- okup := m != u && (inclusive || m+1 < u || i+1 < upper.nd)
+ okup := upperdelta > 0 && (inclusive || upperdelta > 1 || ui+1 < upper.nd)
// If it's okay to do either, then round to the nearest one.
// If it's okay to do only one, do it.
switch {
case okdown && okup:
- d.Round(i + 1)
+ d.Round(mi + 1)
return
case okdown:
- d.RoundDown(i + 1)
+ d.RoundDown(mi + 1)
return
case okup:
- d.RoundUp(i + 1)
+ d.RoundUp(mi + 1)
return
}
}
@@ -439,6 +485,89 @@ func fmtB(dst []byte, neg bool, mant uint64, exp int, flt *floatInfo) []byte {
return dst
}
+// %x: -0x1.yyyyyyyyp±ddd or -0x0p+0. (y is hex digit, d is decimal digit)
+func fmtX(dst []byte, prec int, fmt byte, neg bool, mant uint64, exp int, flt *floatInfo) []byte {
+ if mant == 0 {
+ exp = 0
+ }
+
+ // Shift digits so leading 1 (if any) is at bit 1<<60.
+ mant <<= 60 - flt.mantbits
+ for mant != 0 && mant&(1<<60) == 0 {
+ mant <<= 1
+ exp--
+ }
+
+ // Round if requested.
+ if prec >= 0 && prec < 15 {
+ shift := uint(prec * 4)
+ extra := (mant << shift) & (1<<60 - 1)
+ mant >>= 60 - shift
+ if extra|(mant&1) > 1<<59 {
+ mant++
+ }
+ mant <<= 60 - shift
+ if mant&(1<<61) != 0 {
+ // Wrapped around.
+ mant >>= 1
+ exp++
+ }
+ }
+
+ hex := lowerhex
+ if fmt == 'X' {
+ hex = upperhex
+ }
+
+ // sign, 0x, leading digit
+ if neg {
+ dst = append(dst, '-')
+ }
+ dst = append(dst, '0', fmt, '0'+byte((mant>>60)&1))
+
+ // .fraction
+ mant <<= 4 // remove leading 0 or 1
+ if prec < 0 && mant != 0 {
+ dst = append(dst, '.')
+ for mant != 0 {
+ dst = append(dst, hex[(mant>>60)&15])
+ mant <<= 4
+ }
+ } else if prec > 0 {
+ dst = append(dst, '.')
+ for i := 0; i < prec; i++ {
+ dst = append(dst, hex[(mant>>60)&15])
+ mant <<= 4
+ }
+ }
+
+ // p±
+ ch := byte('P')
+ if fmt == lower(fmt) {
+ ch = 'p'
+ }
+ dst = append(dst, ch)
+ if exp < 0 {
+ ch = '-'
+ exp = -exp
+ } else {
+ ch = '+'
+ }
+ dst = append(dst, ch)
+
+ // dd or ddd or dddd
+ switch {
+ case exp < 100:
+ dst = append(dst, byte(exp/10)+'0', byte(exp%10)+'0')
+ case exp < 1000:
+ dst = append(dst, byte(exp/100)+'0', byte((exp/10)%10)+'0', byte(exp%10)+'0')
+ default:
+ dst = append(dst, byte(exp/1000)+'0', byte(exp/100)%10+'0', byte((exp/10)%10)+'0', byte(exp%10)+'0')
+ }
+
+ return dst
+}
+
func min(a, b int) int {
if a < b {
return a
diff --git a/libgo/go/strconv/ftoa_test.go b/libgo/go/strconv/ftoa_test.go
index 1d3030b..755c986 100644
--- a/libgo/go/strconv/ftoa_test.go
+++ b/libgo/go/strconv/ftoa_test.go
@@ -30,9 +30,15 @@ var ftoatests = []ftoaTest{
{1, 'f', 5, "1.00000"},
{1, 'g', 5, "1"},
{1, 'g', -1, "1"},
+ {1, 'x', -1, "0x1p+00"},
+ {1, 'x', 5, "0x1.00000p+00"},
{20, 'g', -1, "20"},
+ {20, 'x', -1, "0x1.4p+04"},
{1234567.8, 'g', -1, "1.2345678e+06"},
+ {1234567.8, 'x', -1, "0x1.2d687cccccccdp+20"},
{200000, 'g', -1, "200000"},
+ {200000, 'x', -1, "0x1.86ap+17"},
+ {200000, 'X', -1, "0X1.86AP+17"},
{2000000, 'g', -1, "2e+06"},
// g conversion and zero suppression
@@ -50,6 +56,7 @@ var ftoatests = []ftoaTest{
{0, 'f', 5, "0.00000"},
{0, 'g', 5, "0"},
{0, 'g', -1, "0"},
+ {0, 'x', 5, "0x0.00000p+00"},
{-1, 'e', 5, "-1.00000e+00"},
{-1, 'f', 5, "-1.00000"},
@@ -100,7 +107,8 @@ var ftoatests = []ftoaTest{
{32, 'g', -1, "32"},
{32, 'g', 0, "3e+01"},
- {100, 'x', -1, "%x"},
+ {100, 'x', -1, "0x1.9p+06"},
+ {100, 'y', -1, "%y"},
{math.NaN(), 'g', -1, "NaN"},
{-math.NaN(), 'g', -1, "NaN"},
@@ -128,6 +136,27 @@ var ftoatests = []ftoaTest{
// Issue 2625.
{383260575764816448, 'f', 0, "383260575764816448"},
{383260575764816448, 'g', -1, "3.8326057576481645e+17"},
+
+ // Issue 29491.
+ {498484681984085570, 'f', -1, "498484681984085570"},
+ {-5.8339553793802237e+23, 'g', -1, "-5.8339553793802237e+23"},
+
+ // rounding
+ {2.275555555555555, 'x', -1, "0x1.23456789abcdep+01"},
+ {2.275555555555555, 'x', 0, "0x1p+01"},
+ {2.275555555555555, 'x', 2, "0x1.23p+01"},
+ {2.275555555555555, 'x', 16, "0x1.23456789abcde000p+01"},
+ {2.275555555555555, 'x', 21, "0x1.23456789abcde00000000p+01"},
+ {2.2755555510520935, 'x', -1, "0x1.2345678p+01"},
+ {2.2755555510520935, 'x', 6, "0x1.234568p+01"},
+ {2.275555431842804, 'x', -1, "0x1.2345668p+01"},
+ {2.275555431842804, 'x', 6, "0x1.234566p+01"},
+ {3.999969482421875, 'x', -1, "0x1.ffffp+01"},
+ {3.999969482421875, 'x', 4, "0x1.ffffp+01"},
+ {3.999969482421875, 'x', 3, "0x1.000p+02"},
+ {3.999969482421875, 'x', 2, "0x1.00p+02"},
+ {3.999969482421875, 'x', 1, "0x1.0p+02"},
+ {3.999969482421875, 'x', 0, "0x1p+02"},
}
func TestFtoa(t *testing.T) {
diff --git a/libgo/go/strconv/isprint.go b/libgo/go/strconv/isprint.go
index f537ba4..a8dfdb2 100644
--- a/libgo/go/strconv/isprint.go
+++ b/libgo/go/strconv/isprint.go
@@ -6,7 +6,7 @@
package strconv
-// (456+140+86)*2 + (396)*4 = 2948 bytes
+// (448+137+90)*2 + (418)*4 = 3022 bytes
var isPrint16 = []uint16{
0x0020, 0x007e,
@@ -16,17 +16,17 @@ var isPrint16 = []uint16{
0x0559, 0x058a,
0x058d, 0x05c7,
0x05d0, 0x05ea,
- 0x05f0, 0x05f4,
+ 0x05ef, 0x05f4,
0x0606, 0x061b,
0x061e, 0x070d,
0x0710, 0x074a,
0x074d, 0x07b1,
0x07c0, 0x07fa,
- 0x0800, 0x082d,
+ 0x07fd, 0x082d,
0x0830, 0x085b,
0x085e, 0x086a,
0x08a0, 0x08bd,
- 0x08d4, 0x098c,
+ 0x08d3, 0x098c,
0x098f, 0x0990,
0x0993, 0x09b2,
0x09b6, 0x09b9,
@@ -35,7 +35,7 @@ var isPrint16 = []uint16{
0x09cb, 0x09ce,
0x09d7, 0x09d7,
0x09dc, 0x09e3,
- 0x09e6, 0x09fd,
+ 0x09e6, 0x09fe,
0x0a01, 0x0a0a,
0x0a0f, 0x0a10,
0x0a13, 0x0a39,
@@ -44,7 +44,7 @@ var isPrint16 = []uint16{
0x0a4b, 0x0a4d,
0x0a51, 0x0a51,
0x0a59, 0x0a5e,
- 0x0a66, 0x0a75,
+ 0x0a66, 0x0a76,
0x0a81, 0x0ab9,
0x0abc, 0x0acd,
0x0ad0, 0x0ad0,
@@ -126,7 +126,7 @@ var isPrint16 = []uint16{
0x17f0, 0x17f9,
0x1800, 0x180d,
0x1810, 0x1819,
- 0x1820, 0x1877,
+ 0x1820, 0x1878,
0x1880, 0x18aa,
0x18b0, 0x18f5,
0x1900, 0x192b,
@@ -149,7 +149,8 @@ var isPrint16 = []uint16{
0x1bfc, 0x1c37,
0x1c3b, 0x1c49,
0x1c4d, 0x1c88,
- 0x1cc0, 0x1cc7,
+ 0x1c90, 0x1cba,
+ 0x1cbd, 0x1cc7,
0x1cd0, 0x1cf9,
0x1d00, 0x1f15,
0x1f18, 0x1f1d,
@@ -170,38 +171,33 @@ var isPrint16 = []uint16{
0x2440, 0x244a,
0x2460, 0x2b73,
0x2b76, 0x2b95,
- 0x2b98, 0x2bb9,
- 0x2bbd, 0x2bd2,
- 0x2bec, 0x2bef,
- 0x2c00, 0x2cf3,
+ 0x2b98, 0x2cf3,
0x2cf9, 0x2d27,
0x2d2d, 0x2d2d,
0x2d30, 0x2d67,
0x2d6f, 0x2d70,
0x2d7f, 0x2d96,
- 0x2da0, 0x2e49,
+ 0x2da0, 0x2e4e,
0x2e80, 0x2ef3,
0x2f00, 0x2fd5,
0x2ff0, 0x2ffb,
0x3001, 0x3096,
0x3099, 0x30ff,
- 0x3105, 0x312e,
- 0x3131, 0x31ba,
+ 0x3105, 0x31ba,
0x31c0, 0x31e3,
0x31f0, 0x4db5,
- 0x4dc0, 0x9fea,
+ 0x4dc0, 0x9fef,
0xa000, 0xa48c,
0xa490, 0xa4c6,
0xa4d0, 0xa62b,
0xa640, 0xa6f7,
- 0xa700, 0xa7b7,
+ 0xa700, 0xa7b9,
0xa7f7, 0xa82b,
0xa830, 0xa839,
0xa840, 0xa877,
0xa880, 0xa8c5,
0xa8ce, 0xa8d9,
- 0xa8e0, 0xa8fd,
- 0xa900, 0xa953,
+ 0xa8e0, 0xa953,
0xa95f, 0xa97c,
0xa980, 0xa9d9,
0xa9de, 0xaa36,
@@ -245,8 +241,6 @@ var isNotPrint16 = []uint16{
0x038d,
0x03a2,
0x0530,
- 0x0560,
- 0x0588,
0x0590,
0x06dd,
0x083f,
@@ -283,14 +277,12 @@ var isNotPrint16 = []uint16{
0x0b9b,
0x0b9d,
0x0bc9,
- 0x0c04,
0x0c0d,
0x0c11,
0x0c29,
0x0c45,
0x0c49,
0x0c57,
- 0x0c84,
0x0c8d,
0x0c91,
0x0ca9,
@@ -350,6 +342,7 @@ var isNotPrint16 = []uint16{
0x1ff5,
0x208f,
0x2bc9,
+ 0x2bff,
0x2c2f,
0x2c5f,
0x2d26,
@@ -363,10 +356,10 @@ var isNotPrint16 = []uint16{
0x2ddf,
0x2e9a,
0x3040,
+ 0x3130,
0x318f,
0x321f,
0x32ff,
- 0xa7af,
0xa9ce,
0xa9ff,
0xab27,
@@ -421,9 +414,9 @@ var isPrint32 = []uint32{
0x010980, 0x0109b7,
0x0109bc, 0x0109cf,
0x0109d2, 0x010a06,
- 0x010a0c, 0x010a33,
+ 0x010a0c, 0x010a35,
0x010a38, 0x010a3a,
- 0x010a3f, 0x010a47,
+ 0x010a3f, 0x010a48,
0x010a50, 0x010a58,
0x010a60, 0x010a9f,
0x010ac0, 0x010ae6,
@@ -437,14 +430,17 @@ var isPrint32 = []uint32{
0x010c00, 0x010c48,
0x010c80, 0x010cb2,
0x010cc0, 0x010cf2,
- 0x010cfa, 0x010cff,
+ 0x010cfa, 0x010d27,
+ 0x010d30, 0x010d39,
0x010e60, 0x010e7e,
+ 0x010f00, 0x010f27,
+ 0x010f30, 0x010f59,
0x011000, 0x01104d,
0x011052, 0x01106f,
0x01107f, 0x0110c1,
0x0110d0, 0x0110e8,
0x0110f0, 0x0110f9,
- 0x011100, 0x011143,
+ 0x011100, 0x011146,
0x011150, 0x011176,
0x011180, 0x0111cd,
0x0111d0, 0x0111f4,
@@ -454,8 +450,7 @@ var isPrint32 = []uint32{
0x0112f0, 0x0112f9,
0x011300, 0x01130c,
0x01130f, 0x011310,
- 0x011313, 0x011339,
- 0x01133c, 0x011344,
+ 0x011313, 0x011344,
0x011347, 0x011348,
0x01134b, 0x01134d,
0x011350, 0x011350,
@@ -463,7 +458,7 @@ var isPrint32 = []uint32{
0x01135d, 0x011363,
0x011366, 0x01136c,
0x011370, 0x011374,
- 0x011400, 0x01145d,
+ 0x011400, 0x01145e,
0x011480, 0x0114c7,
0x0114d0, 0x0114d9,
0x011580, 0x0115b5,
@@ -473,9 +468,10 @@ var isPrint32 = []uint32{
0x011660, 0x01166c,
0x011680, 0x0116b7,
0x0116c0, 0x0116c9,
- 0x011700, 0x011719,
+ 0x011700, 0x01171a,
0x01171d, 0x01172b,
0x011730, 0x01173f,
+ 0x011800, 0x01183b,
0x0118a0, 0x0118f2,
0x0118ff, 0x0118ff,
0x011a00, 0x011a47,
@@ -489,6 +485,9 @@ var isPrint32 = []uint32{
0x011d00, 0x011d36,
0x011d3a, 0x011d47,
0x011d50, 0x011d59,
+ 0x011d60, 0x011d98,
+ 0x011da0, 0x011da9,
+ 0x011ee0, 0x011ef8,
0x012000, 0x012399,
0x012400, 0x012474,
0x012480, 0x012543,
@@ -502,11 +501,12 @@ var isPrint32 = []uint32{
0x016b00, 0x016b45,
0x016b50, 0x016b77,
0x016b7d, 0x016b8f,
+ 0x016e40, 0x016e9a,
0x016f00, 0x016f44,
0x016f50, 0x016f7e,
0x016f8f, 0x016f9f,
0x016fe0, 0x016fe1,
- 0x017000, 0x0187ec,
+ 0x017000, 0x0187f1,
0x018800, 0x018af2,
0x01b000, 0x01b11e,
0x01b170, 0x01b2fb,
@@ -520,8 +520,9 @@ var isPrint32 = []uint32{
0x01d129, 0x01d172,
0x01d17b, 0x01d1e8,
0x01d200, 0x01d245,
+ 0x01d2e0, 0x01d2f3,
0x01d300, 0x01d356,
- 0x01d360, 0x01d371,
+ 0x01d360, 0x01d378,
0x01d400, 0x01d49f,
0x01d4a2, 0x01d4a2,
0x01d4a5, 0x01d4a6,
@@ -538,6 +539,7 @@ var isPrint32 = []uint32{
0x01e900, 0x01e94a,
0x01e950, 0x01e959,
0x01e95e, 0x01e95f,
+ 0x01ec71, 0x01ecb4,
0x01ee00, 0x01ee24,
0x01ee27, 0x01ee3b,
0x01ee42, 0x01ee42,
@@ -560,20 +562,22 @@ var isPrint32 = []uint32{
0x01f260, 0x01f265,
0x01f300, 0x01f6d4,
0x01f6e0, 0x01f6ec,
- 0x01f6f0, 0x01f6f8,
+ 0x01f6f0, 0x01f6f9,
0x01f700, 0x01f773,
- 0x01f780, 0x01f7d4,
+ 0x01f780, 0x01f7d8,
0x01f800, 0x01f80b,
0x01f810, 0x01f847,
0x01f850, 0x01f859,
0x01f860, 0x01f887,
0x01f890, 0x01f8ad,
0x01f900, 0x01f90b,
- 0x01f910, 0x01f94c,
- 0x01f950, 0x01f96b,
- 0x01f980, 0x01f997,
- 0x01f9c0, 0x01f9c0,
- 0x01f9d0, 0x01f9e6,
+ 0x01f910, 0x01f970,
+ 0x01f973, 0x01f976,
+ 0x01f97a, 0x01f9a2,
+ 0x01f9b0, 0x01f9b9,
+ 0x01f9c0, 0x01f9c2,
+ 0x01f9d0, 0x01f9ff,
+ 0x01fa60, 0x01fa6d,
0x020000, 0x02a6d6,
0x02a700, 0x02b734,
0x02b740, 0x02b81d,
@@ -609,9 +613,9 @@ var isNotPrint32 = []uint16{ // add 0x10000 to each entry
0x1329,
0x1331,
0x1334,
+ 0x133a,
0x145a,
0x145c,
- 0x1a9d,
0x1c09,
0x1c37,
0x1ca8,
@@ -619,6 +623,10 @@ var isNotPrint32 = []uint16{ // add 0x10000 to each entry
0x1d0a,
0x1d3b,
0x1d3e,
+ 0x1d66,
+ 0x1d69,
+ 0x1d8f,
+ 0x1d92,
0x246f,
0x6a5f,
0x6b5a,
@@ -668,8 +676,8 @@ var isNotPrint32 = []uint16{ // add 0x10000 to each entry
0xeeaa,
0xf0c0,
0xf0d0,
- 0xf12f,
0xf93f,
+ 0xf97b,
}
// isGraphic lists the graphic runes not matched by IsPrint.
diff --git a/libgo/go/strconv/quote.go b/libgo/go/strconv/quote.go
index 6cd2f93..b50496a 100644
--- a/libgo/go/strconv/quote.go
+++ b/libgo/go/strconv/quote.go
@@ -11,7 +11,10 @@ import (
"unicode/utf8"
)
-const lowerhex = "0123456789abcdef"
+const (
+ lowerhex = "0123456789abcdef"
+ upperhex = "0123456789ABCDEF"
+)
func quoteWith(s string, quote byte, ASCIIonly, graphicOnly bool) string {
return string(appendQuotedWith(make([]byte, 0, 3*len(s)/2), s, quote, ASCIIonly, graphicOnly))
@@ -22,6 +25,13 @@ func quoteRuneWith(r rune, quote byte, ASCIIonly, graphicOnly bool) string {
}
func appendQuotedWith(buf []byte, s string, quote byte, ASCIIonly, graphicOnly bool) []byte {
+ // Often called with big strings, so preallocate. If there's quoting,
+ // this is conservative but still helps a lot.
+ if cap(buf)-len(buf) < len(s) {
+ nBuf := make([]byte, len(buf), len(buf)+1+len(s)+1)
+ copy(nBuf, buf)
+ buf = nBuf
+ }
buf = append(buf, quote)
for width := 0; len(s) > 0; s = s[width:] {
r := rune(s[0])
diff --git a/libgo/go/strconv/strconv_test.go b/libgo/go/strconv/strconv_test.go
index ebec0cc..7619f90 100644
--- a/libgo/go/strconv/strconv_test.go
+++ b/libgo/go/strconv/strconv_test.go
@@ -30,6 +30,9 @@ var (
AppendFloat(localBuf[:0], 1.23, 'g', 5, 64)
}},
{0, `AppendFloat(globalBuf[:0], 1.23, 'g', 5, 64)`, func() { AppendFloat(globalBuf[:0], 1.23, 'g', 5, 64) }},
+ // In practice we see 7 for the next one, but allow some slop.
+ // Before pre-allocation in appendQuotedWith, we saw 39.
+ {10, `AppendQuoteToASCII(nil, oneMB)`, func() { AppendQuoteToASCII(nil, string(oneMB)) }},
{0, `ParseFloat("123.45", 64)`, func() { ParseFloat("123.45", 64) }},
{0, `ParseFloat("123.456789123456789", 64)`, func() { ParseFloat("123.456789123456789", 64) }},
{0, `ParseFloat("1.000000000000000111022302462515654042363166809082031251", 64)`, func() {
@@ -41,6 +44,8 @@ var (
}
)
+var oneMB []byte // Will be allocated to 1MB of random data by TestCountMallocs.
+
func TestCountMallocs(t *testing.T) {
if runtime.Compiler == "gccgo" {
t.Skip("skipping on gccgo until escape analysis is turned on")
@@ -51,6 +56,11 @@ func TestCountMallocs(t *testing.T) {
if runtime.GOMAXPROCS(0) > 1 {
t.Skip("skipping; GOMAXPROCS>1")
}
+ // Allocate a big messy buffer for AppendQuoteToASCII's test.
+ oneMB = make([]byte, 1e6)
+ for i := range oneMB {
+ oneMB[i] = byte(i)
+ }
for _, mt := range mallocTest {
allocs := testing.AllocsPerRun(100, mt.fn)
if max := float64(mt.count); allocs > max {