diff options
author | Christopher Speller <crspeller@gmail.com> | 2017-09-29 12:46:30 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2017-09-29 12:46:30 -0700 |
commit | b84736e9b6401df0c6eeab9950bef09458a6aefd (patch) | |
tree | d9175208de3236db75a33879750a57b3000ba096 /vendor/golang.org/x/text/internal/number | |
parent | 8b9dbb86133ff0fd6002a391268383d1593918ca (diff) | |
download | chat-b84736e9b6401df0c6eeab9950bef09458a6aefd.tar.gz chat-b84736e9b6401df0c6eeab9950bef09458a6aefd.tar.bz2 chat-b84736e9b6401df0c6eeab9950bef09458a6aefd.zip |
Updating server dependancies. (#7538)
Diffstat (limited to 'vendor/golang.org/x/text/internal/number')
-rw-r--r-- | vendor/golang.org/x/text/internal/number/decimal.go | 185 | ||||
-rw-r--r-- | vendor/golang.org/x/text/internal/number/decimal_test.go | 63 | ||||
-rwxr-xr-x | vendor/golang.org/x/text/internal/number/format.go | 176 | ||||
-rwxr-xr-x | vendor/golang.org/x/text/internal/number/format_test.go | 70 | ||||
-rw-r--r-- | vendor/golang.org/x/text/internal/number/pattern.go | 92 | ||||
-rw-r--r-- | vendor/golang.org/x/text/internal/number/pattern_test.go | 333 | ||||
-rw-r--r-- | vendor/golang.org/x/text/internal/number/tables.go | 378 |
7 files changed, 778 insertions, 519 deletions
diff --git a/vendor/golang.org/x/text/internal/number/decimal.go b/vendor/golang.org/x/text/internal/number/decimal.go index 199c7e416..62074e7d7 100644 --- a/vendor/golang.org/x/text/internal/number/decimal.go +++ b/vendor/golang.org/x/text/internal/number/decimal.go @@ -25,22 +25,39 @@ const ( numModes ) -// A RoundingContext indicates how a number should be converted to digits. -type RoundingContext struct { - Mode RoundingMode - Increment int32 // if > 0, round to Increment * 10^-Scale +const maxIntDigits = 20 + +// A Decimal represents a floating point number in decimal format. +// Digits represents a number [0, 1.0), and the absolute value represented by +// Decimal is Digits * 10^Exp. Leading and trailing zeros may be omitted and Exp +// may point outside a valid position in Digits. +// +// Examples: +// Number Decimal +// 12345 Digits: [1, 2, 3, 4, 5], Exp: 5 +// 12.345 Digits: [1, 2, 3, 4, 5], Exp: 2 +// 12000 Digits: [1, 2], Exp: 5 +// 12000.00 Digits: [1, 2], Exp: 5 +// 0.00123 Digits: [1, 2, 3], Exp: -2 +// 0 Digits: [], Exp: 0 +type Decimal struct { + digits - Precision int32 // maximum number of significant digits. - Scale int32 // maximum number of decimals after the dot. + buf [maxIntDigits]byte } -const maxIntDigits = 20 +type digits struct { + Digits []byte // mantissa digits, big-endian + Exp int32 // exponent + Neg bool + Inf bool // Takes precedence over Digits and Exp. + NaN bool // Takes precedence over Inf. +} -// A Decimal represents floating point number represented in digits of the base -// in which a number is to be displayed. Digits represents a number [0, 1.0), -// and the absolute value represented by Decimal is Digits * 10^Exp. -// Leading and trailing zeros may be omitted and Exp may point outside a valid -// position in Digits. +// Digits represents a floating point number represented in digits of the +// base in which a number is to be displayed. It is similar to Decimal, but +// keeps track of trailing fraction zeros and the comma placement for +// engineering notation. Digits must have at least one digit. // // Examples: // Number Decimal @@ -51,25 +68,31 @@ const maxIntDigits = 20 // 12000.00 Digits: [1, 2], Exp: 5 End: 7 // 0.00123 Digits: [1, 2, 3], Exp: -2 End: 3 // 0 Digits: [], Exp: 0 End: 1 -// scientific: -// 0 Digits: [], Exp: 0, End: 1, Comma: 0 +// scientific (actual exp is Exp - Comma) +// 0e0 Digits: [0], Exp: 1, End: 1, Comma: 1 +// .0e0 Digits: [0], Exp: 0, End: 1, Comma: 0 +// 0.0e0 Digits: [0], Exp: 1, End: 2, Comma: 1 // 1.23e4 Digits: [1, 2, 3], Exp: 5, End: 3, Comma: 1 +// .123e5 Digits: [1, 2, 3], Exp: 5, End: 3, Comma: 0 // engineering // 12.3e3 Digits: [1, 2, 3], Exp: 5, End: 3, Comma: 2 -type Decimal struct { - Digits []byte // mantissa digits, big-endian - Exp int32 // exponent +type Digits struct { + digits // End indicates the end position of the number. End int32 // For decimals Exp <= End. For scientific len(Digits) <= End. // Comma is used for the comma position for scientific (always 0 or 1) and // engineering notation (always 0, 1, 2, or 3). Comma uint8 + // IsScientific indicates whether this number is to be rendered as a + // scientific number. + IsScientific bool +} - Neg bool - Inf bool // Takes precedence over Digits and Exp. - NaN bool // Takes precedence over Inf. - - buf [maxIntDigits]byte +func (d *Digits) NumFracDigits() int { + if d.Exp >= d.End { + return 0 + } + return int(d.End - d.Exp) } // normalize returns a new Decimal with leading and trailing zeros removed. @@ -151,7 +174,7 @@ func appendZeros(buf []byte, n int) []byte { return buf } -func (d *Decimal) round(mode RoundingMode, n int) { +func (d *digits) round(mode RoundingMode, n int) { if n >= len(d.Digits) { return } @@ -227,7 +250,7 @@ func (r RoundingMode) roundFloat(x float64) float64 { return i } -func (x *Decimal) roundUp(n int) { +func (x *digits) roundUp(n int) { if n < 0 || n >= len(x.Digits) { return // nothing to do } @@ -248,7 +271,7 @@ func (x *Decimal) roundUp(n int) { // x already trimmed } -func (x *Decimal) roundDown(n int) { +func (x *digits) roundDown(n int) { if n < 0 || n >= len(x.Digits) { return // nothing to do } @@ -258,7 +281,7 @@ func (x *Decimal) roundDown(n int) { // trim cuts off any trailing zeros from x's mantissa; // they are meaningless for the value of x. -func trim(x *Decimal) { +func trim(x *digits) { i := len(x.Digits) for i > 0 && x.Digits[i-1] == 0 { i-- @@ -272,7 +295,7 @@ func trim(x *Decimal) { // A Converter converts a number into decimals according to the given rounding // criteria. type Converter interface { - Convert(d *Decimal, r *RoundingContext) + Convert(d *Decimal, r RoundingContext) } const ( @@ -282,7 +305,7 @@ const ( // Convert converts the given number to the decimal representation using the // supplied RoundingContext. -func (d *Decimal) Convert(r *RoundingContext, number interface{}) { +func (d *Decimal) Convert(r RoundingContext, number interface{}) { switch f := number.(type) { case Converter: d.clear() @@ -312,6 +335,8 @@ func (d *Decimal) Convert(r *RoundingContext, number interface{}) { case uint64: d.ConvertInt(r, unsigned, f) + default: + d.NaN = true // TODO: // case string: if produced by strconv, allows for easy arbitrary pos. // case reflect.Value: @@ -324,7 +349,7 @@ func (d *Decimal) Convert(r *RoundingContext, number interface{}) { } // ConvertInt converts an integer to decimals. -func (d *Decimal) ConvertInt(r *RoundingContext, signed bool, x uint64) { +func (d *Decimal) ConvertInt(r RoundingContext, signed bool, x uint64) { if r.Increment > 0 { // TODO: if uint64 is too large, fall back to float64 if signed { @@ -344,12 +369,30 @@ func (d *Decimal) ConvertInt(r *RoundingContext, signed bool, x uint64) { } // ConvertFloat converts a floating point number to decimals. -func (d *Decimal) ConvertFloat(r *RoundingContext, x float64, size int) { +func (d *Decimal) ConvertFloat(r RoundingContext, x float64, size int) { d.clear() if math.IsNaN(x) { d.NaN = true return } + // Simple case: decimal notation + if r.Increment > 0 { + scale := int(r.IncrementScale) + mult := 1.0 + if scale > len(scales) { + mult = math.Pow(10, float64(scale)) + } else { + mult = scales[scale] + } + // We multiply x instead of dividing inc as it gives less rounding + // issues. + x *= mult + x /= float64(r.Increment) + x = r.Mode.roundFloat(x) + x *= float64(r.Increment) + x /= mult + } + abs := x if x < 0 { d.Neg = true @@ -359,63 +402,59 @@ func (d *Decimal) ConvertFloat(r *RoundingContext, x float64, size int) { d.Inf = true return } - // Simple case: decimal notation - if r.Scale > 0 || r.Increment > 0 || r.Precision == 0 { - if int(r.Scale) > len(scales) { - x *= math.Pow(10, float64(r.Scale)) - } else { - x *= scales[r.Scale] - } - if r.Increment > 0 { - inc := float64(r.Increment) - x /= float64(inc) - x = r.Mode.roundFloat(x) - x *= inc - } else { - x = r.Mode.roundFloat(x) - } - d.fillIntDigits(uint64(math.Abs(x))) - d.Exp = int32(len(d.Digits)) - r.Scale - return - } - // Nasty case (for non-decimal notation). - // Asides from being inefficient, this result is also wrong as it will - // apply ToNearestEven rounding regardless of the user setting. - // TODO: expose functionality in strconv so we can avoid this hack. + // By default we get the exact decimal representation. + verb := byte('g') + prec := -1 + // Determine rounding, if possible. As the strconv API does not return the + // rounding accuracy (exact/rounded up|down), we can only round using + // ToNearestEven. // Something like this would work: // AppendDigits(dst []byte, x float64, base, size, prec int) (digits []byte, exp, accuracy int) - // TODO: This only supports the nearest even rounding mode. - - prec := int(r.Precision) - if prec > 0 { - prec-- - } - b := strconv.AppendFloat(d.Digits, abs, 'e', prec, size) + // + // TODO: At this point strconv's rounding is imprecise to the point that it + // is not useable for this purpose. + // See https://github.com/golang/go/issues/21714 + // if r.Mode == ToNearestEven { + // if n := r.RoundSignificantDigits(); n >= 0 { + // prec = n + // } else if n = r.RoundFractionDigits(); n >= 0 { + // prec = n + // verb = 'f' + // } + // } + + b := strconv.AppendFloat(d.Digits[:0], abs, verb, prec, size) i := 0 k := 0 - // No need to check i < len(b) as we always have an 'e'. - for { + beforeDot := 1 + for i < len(b) { if c := b[i]; '0' <= c && c <= '9' { b[k] = c - '0' k++ - } else if c != '.' { + d.Exp += int32(beforeDot) + } else if c == '.' { + beforeDot = 0 + d.Exp = int32(k) + } else { break } i++ } d.Digits = b[:k] - i += len("e") - pSign := i - exp := 0 - for i++; i < len(b); i++ { - exp *= 10 - exp += int(b[i] - '0') - } - if b[pSign] == '-' { - exp = -exp + if i != len(b) { + i += len("e") + pSign := i + exp := 0 + for i++; i < len(b); i++ { + exp *= 10 + exp += int(b[i] - '0') + } + if b[pSign] == '-' { + exp = -exp + } + d.Exp = int32(exp) + 1 } - d.Exp = int32(exp) + 1 } func (d *Decimal) fillIntDigits(x uint64) { diff --git a/vendor/golang.org/x/text/internal/number/decimal_test.go b/vendor/golang.org/x/text/internal/number/decimal_test.go index 5c8170049..04aa8b2c8 100644 --- a/vendor/golang.org/x/text/internal/number/decimal_test.go +++ b/vendor/golang.org/x/text/internal/number/decimal_test.go @@ -22,6 +22,15 @@ func mkfloat(num string) float64 { // digits are shifted. Numbers may have an additional exponent or be the special // value NaN, Inf, or -Inf. func mkdec(num string) (d Decimal) { + var r RoundingContext + d.Convert(r, dec(num)) + return +} + +type dec string + +func (s dec) Convert(d *Decimal, _ RoundingContext) { + num := string(s) if num[0] == '-' { d.Neg = true num = num[1:] @@ -52,7 +61,7 @@ func mkdec(num string) (d Decimal) { for i := range d.Digits { d.Digits[i] -= '0' } - return d.normalize() + *d = d.normalize() } func byteNum(s string) []byte { @@ -77,11 +86,11 @@ func TestDecimalString(t *testing.T) { want string }{ {want: "0"}, - {Decimal{Digits: nil, Exp: 1000}, "0"}, // exponent of 1000 is ignored - {Decimal{Digits: byteNum("12345"), Exp: 0}, "0.12345"}, - {Decimal{Digits: byteNum("12345"), Exp: -3}, "0.00012345"}, - {Decimal{Digits: byteNum("12345"), Exp: +3}, "123.45"}, - {Decimal{Digits: byteNum("12345"), Exp: +10}, "1234500000"}, + {Decimal{digits: digits{Digits: nil, Exp: 1000}}, "0"}, // exponent of 1000 is ignored + {Decimal{digits: digits{Digits: byteNum("12345"), Exp: 0}}, "0.12345"}, + {Decimal{digits: digits{Digits: byteNum("12345"), Exp: -3}}, "0.00012345"}, + {Decimal{digits: digits{Digits: byteNum("12345"), Exp: +3}}, "123.45"}, + {Decimal{digits: digits{Digits: byteNum("12345"), Exp: +10}}, "1234500000"}, } { if got := test.x.String(); got != test.want { t.Errorf("%v == %q; want %q", test.x, got, test.want) @@ -232,16 +241,28 @@ func TestRounding(t *testing.T) { } func TestConvert(t *testing.T) { - scale2 := &RoundingContext{Scale: 2} - scale2away := &RoundingContext{Scale: 2, Mode: AwayFromZero} - inc0_05 := &RoundingContext{Increment: 5, Scale: 2} - inc50 := &RoundingContext{Increment: 50} - prec3 := &RoundingContext{Precision: 3} + scale2 := RoundingContext{} + scale2.SetScale(2) + scale2away := RoundingContext{Mode: AwayFromZero} + scale2away.SetScale(2) + inc0_05 := RoundingContext{Increment: 5, IncrementScale: 2} + inc0_05.SetScale(2) + inc50 := RoundingContext{Increment: 50} + prec3 := RoundingContext{} + prec3.SetPrecision(3) + roundShift := RoundingContext{DigitShift: 2, MaxFractionDigits: 2} testCases := []struct { x interface{} - rc *RoundingContext + rc RoundingContext out string }{ + // TODO: uncommented tests can be restored when convert does its own + // rounding. + // {-0.001, scale2, "-0.00"}, // not normalized + // {0.1234, prec3, "0.123"}, + // {1234.0, prec3, "1230"}, + // {1.2345e10, prec3, "12300000000"}, + {int8(-34), scale2, "-34"}, {int16(-234), scale2, "-234"}, {int32(-234), scale2, "-234"}, @@ -252,25 +273,25 @@ func TestConvert(t *testing.T) { {uint32(234), scale2, "234"}, {uint64(234), scale2, "234"}, {uint(234), scale2, "234"}, - {-0.001, scale2, "-0"}, - {-1e9, scale2, "-1000000000.00"}, - {0.234, scale2, "0.23"}, - {0.234, scale2away, "0.24"}, - {0.1234, prec3, "0.123"}, - {1234.0, prec3, "1230"}, - {1.2345e10, prec3, "12300000000"}, + {-1e9, scale2, "-1000000000"}, + {0.234, scale2away, "0.234"}, // rounding postponed as not ToNearestEven {0.03, inc0_05, "0.05"}, {0.025, inc0_05, "0"}, - {0.075, inc0_05, "0.10"}, + {0.075, inc0_05, "0.1"}, {325, inc50, "300"}, {375, inc50, "400"}, + // Here the scale is 2, but the digits get shifted left. As we use + // AppendFloat to do the rounding an exta 0 gets added. + {0.123, roundShift, "0.123"}, + {converter(3), scale2, "100"}, {math.Inf(1), inc50, "Inf"}, {math.Inf(-1), inc50, "-Inf"}, {math.NaN(), inc50, "NaN"}, + {"clearly not a number", scale2, "NaN"}, } for _, tc := range testCases { var d Decimal @@ -285,7 +306,7 @@ func TestConvert(t *testing.T) { type converter int -func (c converter) Convert(d *Decimal, r *RoundingContext) { +func (c converter) Convert(d *Decimal, r RoundingContext) { d.Digits = append(d.Digits, 1, 0, 0) d.Exp = 3 } diff --git a/vendor/golang.org/x/text/internal/number/format.go b/vendor/golang.org/x/text/internal/number/format.go index 533a85a28..910bdeb02 100755 --- a/vendor/golang.org/x/text/internal/number/format.go +++ b/vendor/golang.org/x/text/internal/number/format.go @@ -16,6 +16,13 @@ import ( // - allow user-defined superscript notation (such as <sup>4</sup>) // - same for non-breaking spaces, like +// A VisibleDigits computes digits, comma placement and trailing zeros as they +// will be shown to the user. +type VisibleDigits interface { + Digits(buf []byte, t language.Tag, scale int) Digits + // TODO: Do we also need to add the verb or pass a format.State? +} + // Formatting proceeds along the following lines: // 0) Compose rounding information from format and context. // 1) Convert a number into a Decimal. @@ -28,7 +35,6 @@ import ( type Formatter struct { Pattern Info - RoundingContext } func (f *Formatter) init(t language.Tag, index []uint8) { @@ -57,12 +63,16 @@ func (f *Formatter) InitDecimal(t language.Tag) { // given language. func (f *Formatter) InitScientific(t language.Tag) { f.init(t, tagToScientific) + f.Pattern.MinFractionDigits = 0 + f.Pattern.MaxFractionDigits = -1 } // InitEngineering initializes a Formatter using the default Pattern for the // given language. func (f *Formatter) InitEngineering(t language.Tag) { f.init(t, tagToScientific) + f.Pattern.MinFractionDigits = 0 + f.Pattern.MaxFractionDigits = -1 f.Pattern.MaxIntegerDigits = 3 f.Pattern.MinIntegerDigits = 1 } @@ -82,17 +92,29 @@ func (f *Formatter) InitPerMille(t language.Tag) { func (f *Formatter) Append(dst []byte, x interface{}) []byte { var d Decimal - d.Convert(&f.RoundingContext, x) - return f.Format(dst, &d) + r := f.RoundingContext + d.Convert(r, x) + return f.Render(dst, FormatDigits(&d, r)) +} + +func FormatDigits(d *Decimal, r RoundingContext) Digits { + if r.isScientific() { + return scientificVisibleDigits(r, d) + } + return decimalVisibleDigits(r, d) } func (f *Formatter) Format(dst []byte, d *Decimal) []byte { + return f.Render(dst, FormatDigits(d, f.RoundingContext)) +} + +func (f *Formatter) Render(dst []byte, d Digits) []byte { var result []byte var postPrefix, preSuffix int - if f.MinExponentDigits > 0 { - result, postPrefix, preSuffix = appendScientific(dst, f, d) + if d.IsScientific { + result, postPrefix, preSuffix = appendScientific(dst, f, &d) } else { - result, postPrefix, preSuffix = appendDecimal(dst, f, d) + result, postPrefix, preSuffix = appendDecimal(dst, f, &d) } if f.PadRune == 0 { return result @@ -131,80 +153,79 @@ func (f *Formatter) Format(dst []byte, d *Decimal) []byte { return result } -// TODO: just return visible digits. -func decimalVisibleDigits(f *Formatter, d *Decimal) Decimal { +// decimalVisibleDigits converts d according to the RoundingContext. Note that +// the exponent may change as a result of this operation. +func decimalVisibleDigits(r RoundingContext, d *Decimal) Digits { if d.NaN || d.Inf { - return *d + return Digits{digits: digits{Neg: d.Neg, NaN: d.NaN, Inf: d.Inf}} } - n := d.normalize() - if maxSig := int(f.MaxSignificantDigits); maxSig > 0 { - // TODO: really round to zero? - n.round(ToZero, maxSig) - } - digits := n.Digits + n := Digits{digits: d.normalize().digits} + exp := n.Exp - exp += int32(f.Pattern.DigitShift) + exp += int32(r.DigitShift) // Cap integer digits. Remove *most-significant* digits. - if f.MaxIntegerDigits > 0 { - if p := int(exp) - int(f.MaxIntegerDigits); p > 0 { - if p > len(digits) { - p = len(digits) + if r.MaxIntegerDigits > 0 { + if p := int(exp) - int(r.MaxIntegerDigits); p > 0 { + if p > len(n.Digits) { + p = len(n.Digits) } - if digits = digits[p:]; len(digits) == 0 { + if n.Digits = n.Digits[p:]; len(n.Digits) == 0 { exp = 0 } else { exp -= int32(p) } // Strip leading zeros. - for len(digits) > 0 && digits[0] == 0 { - digits = digits[1:] + for len(n.Digits) > 0 && n.Digits[0] == 0 { + n.Digits = n.Digits[1:] exp-- } } } - // Rounding usually is done by convert, but we don't rely on it. - numFrac := len(digits) - int(exp) - if f.MaxSignificantDigits == 0 && int(f.MaxFractionDigits) < numFrac { - p := int(exp) + int(f.MaxFractionDigits) - if p <= 0 { + // Rounding if not already done by Convert. + p := len(n.Digits) + if maxSig := int(r.MaxSignificantDigits); maxSig > 0 { + p = maxSig + } + if maxFrac := int(r.MaxFractionDigits); maxFrac >= 0 { + if cap := int(exp) + maxFrac; cap < p { + p = int(exp) + maxFrac + } + if p < 0 { p = 0 - } else if p >= len(digits) { - p = len(digits) } - digits = digits[:p] // TODO: round } + n.round(r.Mode, p) // set End (trailing zeros) - n.End = int32(len(digits)) - if len(digits) == 0 { - if f.MinFractionDigits > 0 { - n.End = int32(f.MinFractionDigits) + n.End = int32(len(n.Digits)) + if n.End == 0 { + exp = 0 + if r.MinFractionDigits > 0 { + n.End = int32(r.MinFractionDigits) } - if p := int32(f.MinSignificantDigits) - 1; p > n.End { + if p := int32(r.MinSignificantDigits) - 1; p > n.End { n.End = p } } else { - if end := exp + int32(f.MinFractionDigits); end > n.End { + if end := exp + int32(r.MinFractionDigits); end > n.End { n.End = end } - if n.End < int32(f.MinSignificantDigits) { - n.End = int32(f.MinSignificantDigits) + if n.End < int32(r.MinSignificantDigits) { + n.End = int32(r.MinSignificantDigits) } } - n.Digits = digits n.Exp = exp return n } // appendDecimal appends a formatted number to dst. It returns two possible // insertion points for padding. -func appendDecimal(dst []byte, f *Formatter, d *Decimal) (b []byte, postPre, preSuf int) { - if dst, ok := f.renderSpecial(dst, d); ok { +func appendDecimal(dst []byte, f *Formatter, n *Digits) (b []byte, postPre, preSuf int) { + if dst, ok := f.renderSpecial(dst, n); ok { return dst, 0, len(dst) } - n := decimalVisibleDigits(f, d) digits := n.Digits exp := n.Exp @@ -224,7 +245,7 @@ func appendDecimal(dst []byte, f *Formatter, d *Decimal) (b []byte, postPre, pre fracDigits = digits } - neg := d.Neg + neg := n.Neg affix, suffix := f.getAffixes(neg) dst = appendAffix(dst, f, affix, neg) savedLen := len(dst) @@ -257,7 +278,7 @@ func appendDecimal(dst []byte, f *Formatter, d *Decimal) (b []byte, postPre, pre if numFrac > 0 || f.Flags&AlwaysDecimalSeparator != 0 { dst = append(dst, f.Symbol(SymDecimal)...) } - // Add leading zeros + // Add trailing zeros i = 0 for n := -int(n.Exp); i < n; i++ { dst = f.AppendDigit(dst, 0) @@ -272,69 +293,65 @@ func appendDecimal(dst []byte, f *Formatter, d *Decimal) (b []byte, postPre, pre return appendAffix(dst, f, suffix, neg), savedLen, len(dst) } -func scientificVisibleDigits(f *Formatter, d *Decimal) Decimal { +func scientificVisibleDigits(r RoundingContext, d *Decimal) Digits { if d.NaN || d.Inf { - return *d + return Digits{digits: digits{Neg: d.Neg, NaN: d.NaN, Inf: d.Inf}} + } + n := Digits{digits: d.normalize().digits, IsScientific: true} + + // Normalize to have at least one digit. This simplifies engineering + // notation. + if len(n.Digits) == 0 { + n.Digits = append(n.Digits, 0) + n.Exp = 1 } - n := d.normalize() // Significant digits are transformed by the parser for scientific notation // and do not need to be handled here. - maxInt, numInt := int(f.MaxIntegerDigits), int(f.MinIntegerDigits) + maxInt, numInt := int(r.MaxIntegerDigits), int(r.MinIntegerDigits) if numInt == 0 { numInt = 1 } - maxSig := int(f.MaxFractionDigits) + numInt - minSig := int(f.MinFractionDigits) + numInt - - if maxSig > 0 { - // TODO: really round to zero? - n.round(ToZero, maxSig) - } - digits := n.Digits - exp := n.Exp // If a maximum number of integers is specified, the minimum must be 1 // and the exponent is grouped by this number (e.g. for engineering) - if len(digits) == 0 { - exp = 0 - } else if maxInt > numInt { + if maxInt > numInt { // Correct the exponent to reflect a single integer digit. - exp-- numInt = 1 // engineering // 0.01234 ([12345]e-1) -> 1.2345e-2 12.345e-3 // 12345 ([12345]e+5) -> 1.2345e4 12.345e3 - d := int(exp) % maxInt + d := int(n.Exp-1) % maxInt if d < 0 { d += maxInt } - exp -= int32(d) numInt += d - } else { - exp -= int32(numInt) } + p := len(n.Digits) + if maxSig := int(r.MaxSignificantDigits); maxSig > 0 { + p = maxSig + } + if maxFrac := int(r.MaxFractionDigits); maxFrac >= 0 && numInt+maxFrac < p { + p = numInt + maxFrac + } + n.round(r.Mode, p) + n.Comma = uint8(numInt) - n.End = int32(len(digits)) - if n.End < int32(minSig) { - n.End = int32(minSig) + n.End = int32(len(n.Digits)) + if minSig := int32(r.MinFractionDigits) + int32(numInt); n.End < minSig { + n.End = minSig } - n.Digits = digits - n.Exp = exp return n } // appendScientific appends a formatted number to dst. It returns two possible // insertion points for padding. -func appendScientific(dst []byte, f *Formatter, d *Decimal) (b []byte, postPre, preSuf int) { - if dst, ok := f.renderSpecial(dst, d); ok { +func appendScientific(dst []byte, f *Formatter, n *Digits) (b []byte, postPre, preSuf int) { + if dst, ok := f.renderSpecial(dst, n); ok { return dst, 0, 0 } - // n := d.normalize() - n := scientificVisibleDigits(f, d) digits := n.Digits - exp := n.Exp numInt := int(n.Comma) numFrac := int(n.End) - int(n.Comma) @@ -345,7 +362,7 @@ func appendScientific(dst []byte, f *Formatter, d *Decimal) (b []byte, postPre, } else { intDigits = digits } - neg := d.Neg + neg := n.Neg affix, suffix := f.getAffixes(neg) dst = appendAffix(dst, f, affix, neg) savedLen := len(dst) @@ -379,6 +396,7 @@ func appendScientific(dst []byte, f *Formatter, d *Decimal) (b []byte, postPre, buf := [12]byte{} // TODO: use exponential if superscripting is not available (no Latin // numbers or no tags) and use exponential in all other cases. + exp := n.Exp - int32(n.Comma) exponential := f.Symbol(SymExponential) if exponential == "E" { dst = append(dst, "\u202f"...) // NARROW NO-BREAK SPACE @@ -463,7 +481,7 @@ func (f *Formatter) getAffixes(neg bool) (affix, suffix string) { return affix, suffix } -func (f *Formatter) renderSpecial(dst []byte, d *Decimal) (b []byte, ok bool) { +func (f *Formatter) renderSpecial(dst []byte, d *Digits) (b []byte, ok bool) { if d.NaN { return fmtNaN(dst, f), true } @@ -477,7 +495,7 @@ func fmtNaN(dst []byte, f *Formatter) []byte { return append(dst, f.Symbol(SymNan)...) } -func fmtInfinite(dst []byte, f *Formatter, d *Decimal) []byte { +func fmtInfinite(dst []byte, f *Formatter, d *Digits) []byte { affix, suffix := f.getAffixes(d.Neg) dst = appendAffix(dst, f, affix, d.Neg) dst = append(dst, f.Symbol(SymInfinity)...) diff --git a/vendor/golang.org/x/text/internal/number/format_test.go b/vendor/golang.org/x/text/internal/number/format_test.go index 4c47bc568..01a089430 100755 --- a/vendor/golang.org/x/text/internal/number/format_test.go +++ b/vendor/golang.org/x/text/internal/number/format_test.go @@ -112,7 +112,7 @@ func TestAppendDecimal(t *testing.T) { test: pairs{ "0": "0", "1234.5678": "1234.5678", - "0.123456789": "0.123456", + "0.123456789": "0.123457", "NaN": "NaN", "Inf": "∞", }, @@ -142,7 +142,7 @@ func TestAppendDecimal(t *testing.T) { pattern: "#,##0.###", test: pairs{ "0": "0", - "1234.5678": "1,234.567", + "1234.5678": "1,234.568", "0.123456789": "0.123", }, }, { @@ -157,7 +157,7 @@ func TestAppendDecimal(t *testing.T) { test: pairs{ "0": "0,00,000", "123456789012": "1,23,45,67,89,012", - "12.3456789": "0,00,012.345", + "12.3456789": "0,00,012.346", "0.123456789": "0,00,000.123", }, @@ -193,7 +193,9 @@ func TestAppendDecimal(t *testing.T) { }, { pattern: "#,max_int=2", pat: &Pattern{ - MaxIntegerDigits: 2, + RoundingContext: RoundingContext{ + MaxIntegerDigits: 2, + }, }, test: pairs{ "2017": "17", @@ -201,8 +203,10 @@ func TestAppendDecimal(t *testing.T) { }, { pattern: "0,max_int=2", pat: &Pattern{ - MaxIntegerDigits: 2, - MinIntegerDigits: 1, + RoundingContext: RoundingContext{ + MaxIntegerDigits: 2, + MinIntegerDigits: 1, + }, }, test: pairs{ "2000": "0", @@ -212,8 +216,10 @@ func TestAppendDecimal(t *testing.T) { }, { pattern: "00,max_int=2", pat: &Pattern{ - MaxIntegerDigits: 2, - MinIntegerDigits: 2, + RoundingContext: RoundingContext{ + MaxIntegerDigits: 2, + MinIntegerDigits: 2, + }, }, test: pairs{ "2000": "00", @@ -223,8 +229,10 @@ func TestAppendDecimal(t *testing.T) { }, { pattern: "@@@@,max_int=2", pat: &Pattern{ - MaxIntegerDigits: 2, - MinSignificantDigits: 4, + RoundingContext: RoundingContext{ + MaxIntegerDigits: 2, + MinSignificantDigits: 4, + }, }, test: pairs{ "2017": "17.00", @@ -237,7 +245,7 @@ func TestAppendDecimal(t *testing.T) { pattern: "@@##", test: pairs{ "1": "1.0", - "0.1": "0.10", + "0.1": "0.10", // leading zero does not count as significant digit "123": "123", "1234": "1234", "12345": "12340", @@ -281,22 +289,25 @@ func TestAppendDecimal(t *testing.T) { pattern: "##0E00", test: pairs{ "100": "100\u202f×\u202f10⁰⁰", - "12345": "10\u202f×\u202f10⁰³", - "123.456": "100\u202f×\u202f10⁰⁰", + "12345": "12\u202f×\u202f10⁰³", + "123.456": "123\u202f×\u202f10⁰⁰", }, }, { pattern: "##0.###E00", test: pairs{ - "100": "100\u202f×\u202f10⁰⁰", - "12345": "12.34\u202f×\u202f10⁰³", - "123.456": "123.4\u202f×\u202f10⁰⁰", + "100": "100\u202f×\u202f10⁰⁰", + "12345": "12.345\u202f×\u202f10⁰³", + "123456": "123.456\u202f×\u202f10⁰³", + "123.456": "123.456\u202f×\u202f10⁰⁰", + "123.4567": "123.457\u202f×\u202f10⁰⁰", }, }, { pattern: "##0.000E00", test: pairs{ - "100": "100.0\u202f×\u202f10⁰⁰", - "12345": "12.34\u202f×\u202f10⁰³", - "123.456": "123.4\u202f×\u202f10⁰⁰", + "100": "100.000\u202f×\u202f10⁰⁰", + "12345": "12.345\u202f×\u202f10⁰³", + "123.456": "123.456\u202f×\u202f10⁰⁰", + "12.3456": "12.346\u202f×\u202f10⁰⁰", }, }, { pattern: "@@E0", @@ -441,11 +452,12 @@ func TestAppendDecimal(t *testing.T) { } var f Formatter f.InitPattern(language.English, pat) - for dec, want := range tc.test { + for num, want := range tc.test { buf := make([]byte, 100) - t.Run(tc.pattern+"/"+dec, func(t *testing.T) { - dec := mkdec(dec) - buf = f.Format(buf[:0], &dec) + t.Run(tc.pattern+"/"+num, func(t *testing.T) { + var d Decimal + d.Convert(f.RoundingContext, dec(num)) + buf = f.Format(buf[:0], &d) if got := string(buf); got != want { t.Errorf("\n got %[1]q (%[1]s)\nwant %[2]q (%[2]s)", got, want) } @@ -470,7 +482,8 @@ func TestLocales(t *testing.T) { t.Run(fmt.Sprint(tc.tag, "/", tc.num), func(t *testing.T) { var f Formatter f.InitDecimal(tc.tag) - d := mkdec(tc.num) + var d Decimal + d.Convert(f.RoundingContext, dec(tc.num)) b := f.Format(nil, &d) if got := string(b); got != tc.want { t.Errorf("got %[1]q (%[1]s); want %[2]q (%[2]s)", got, tc.want) @@ -488,7 +501,8 @@ func TestFormatters(t *testing.T) { }{ {f.InitDecimal, "123456.78", "123,456.78"}, {f.InitScientific, "123456.78", "1.23\u202f×\u202f10⁵"}, - {f.InitEngineering, "123456.78", "123\u202f×\u202f10³"}, + {f.InitEngineering, "123456.78", "123.46\u202f×\u202f10³"}, + {f.InitEngineering, "1234", "1.23\u202f×\u202f10³"}, {f.InitPercent, "0.1234", "12.34%"}, {f.InitPerMille, "0.1234", "123.40‰"}, @@ -496,9 +510,9 @@ func TestFormatters(t *testing.T) { for i, tc := range testCases { t.Run(fmt.Sprint(i, "/", tc.num), func(t *testing.T) { tc.init(language.English) - f.Pattern.MinFractionDigits = 2 - f.Pattern.MaxFractionDigits = 2 - d := mkdec(tc.num) + f.SetScale(2) + var d Decimal + d.Convert(f.RoundingContext, dec(tc.num)) b := f.Format(nil, &d) if got := string(b); got != tc.want { t.Errorf("got %[1]q (%[1]s); want %[2]q (%[2]s)", got, tc.want) diff --git a/vendor/golang.org/x/text/internal/number/pattern.go b/vendor/golang.org/x/text/internal/number/pattern.go index ef7f087fe..b95ca40e8 100644 --- a/vendor/golang.org/x/text/internal/number/pattern.go +++ b/vendor/golang.org/x/text/internal/number/pattern.go @@ -39,31 +39,84 @@ import ( // // This type is only intended for internal use. type Pattern struct { - // TODO: this struct can be packed a lot better than it is now. Should be - // possible to make it 32 bytes. - - Affix string // includes prefix and suffix. First byte is prefix length. - Offset uint16 // Offset into Affix for prefix and suffix - NegOffset uint16 // Offset into Affix for negative prefix and suffix or 0. + RoundingContext + Affix string // includes prefix and suffix. First byte is prefix length. + Offset uint16 // Offset into Affix for prefix and suffix + NegOffset uint16 // Offset into Affix for negative prefix and suffix or 0. + PadRune rune FormatWidth uint16 - RoundIncrement uint32 // Use Min*Digits to determine scale - PadRune rune - DigitShift uint8 // Number of decimals to shift. Used for % and ‰. - GroupingSize [2]uint8 Flags PatternFlag +} + +// A RoundingContext indicates how a number should be converted to digits. +// It contains all information needed to determine the "visible digits" as +// required by the pluralization rules. +type RoundingContext struct { + // TODO: unify these two fields so that there is a more unambiguous meaning + // of how precision is handled. + MaxSignificantDigits int16 // -1 is unlimited + MaxFractionDigits int16 // -1 is unlimited + + Increment uint32 + IncrementScale uint8 // May differ from printed scale. + + Mode RoundingMode + + DigitShift uint8 // Number of decimals to shift. Used for % and ‰. // Number of digits. - // TODO: consider using uint32 - MinIntegerDigits uint8 + MinIntegerDigits uint8 + MaxIntegerDigits uint8 MinFractionDigits uint8 - MaxFractionDigits uint8 MinSignificantDigits uint8 - MaxSignificantDigits uint8 - MinExponentDigits uint8 + + MinExponentDigits uint8 +} + +// RoundSignificantDigits returns the number of significant digits an +// implementation of Convert may round to or n < 0 if there is no maximum or +// a maximum is not recommended. +func (r *RoundingContext) RoundSignificantDigits() (n int) { + if r.MaxFractionDigits == 0 && r.MaxSignificantDigits > 0 { + return int(r.MaxSignificantDigits) + } else if r.isScientific() && r.MaxIntegerDigits == 1 { + if r.MaxSignificantDigits == 0 || + int(r.MaxFractionDigits+1) == int(r.MaxSignificantDigits) { + // Note: don't add DigitShift: it is only used for decimals. + return int(r.MaxFractionDigits) + 1 + } + } + return -1 +} + +// RoundFractionDigits returns the number of fraction digits an implementation +// of Convert may round to or n < 0 if there is no maximum or a maximum is not +// recommended. +func (r *RoundingContext) RoundFractionDigits() (n int) { + if r.MinExponentDigits == 0 && + r.MaxSignificantDigits == 0 && + r.MaxFractionDigits >= 0 { + return int(r.MaxFractionDigits) + int(r.DigitShift) + } + return -1 +} + +// SetScale fixes the RoundingContext to a fixed number of fraction digits. +func (r *RoundingContext) SetScale(scale int) { + r.MinFractionDigits = uint8(scale) + r.MaxFractionDigits = int16(scale) +} + +func (r *RoundingContext) SetPrecision(prec int) { + r.MaxSignificantDigits = int16(prec) +} + +func (r *RoundingContext) isScientific() bool { + return r.MinExponentDigits > 0 } func (f *Pattern) needsSep(pos int) bool { @@ -177,6 +230,9 @@ func ParsePattern(s string) (f *Pattern, err error) { } else { p.Affix = affix } + if p.Increment == 0 { + p.IncrementScale = 0 + } return p.Pattern, nil } @@ -302,6 +358,7 @@ func (p *parser) number(r rune) state { case '@': p.groupingCount++ p.leadingSharps = 0 + p.MaxFractionDigits = -1 return p.sigDigits(r) case ',': if p.leadingSharps == 0 { // no leading commas @@ -339,7 +396,7 @@ func (p *parser) integer(r rune) state { p.updateGrouping() return next } - p.RoundIncrement = p.RoundIncrement*10 + uint32(r-'0') + p.Increment = p.Increment*10 + uint32(r-'0') p.groupingCount++ p.MinIntegerDigits++ return p.integer @@ -389,7 +446,8 @@ func (p *parser) normalizeSigDigitsWithExponent() state { func (p *parser) fraction(r rune) state { switch r { case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9': - p.RoundIncrement = p.RoundIncrement*10 + uint32(r-'0') + p.Increment = p.Increment*10 + uint32(r-'0') + p.IncrementScale++ p.MinFractionDigits++ p.MaxFractionDigits++ case '#': diff --git a/vendor/golang.org/x/text/internal/number/pattern_test.go b/vendor/golang.org/x/text/internal/number/pattern_test.go index 97ff64d55..a7517d004 100644 --- a/vendor/golang.org/x/text/internal/number/pattern_test.go +++ b/vendor/golang.org/x/text/internal/number/pattern_test.go @@ -22,96 +22,122 @@ var testCases = []struct { }, { "0", &Pattern{ - FormatWidth: 1, - MinIntegerDigits: 1, + FormatWidth: 1, + RoundingContext: RoundingContext{ + MinIntegerDigits: 1, + }, }, }, { "+0", &Pattern{ - Affix: "\x01+\x00", - FormatWidth: 2, - MinIntegerDigits: 1, + Affix: "\x01+\x00", + FormatWidth: 2, + RoundingContext: RoundingContext{ + MinIntegerDigits: 1, + }, }, }, { "0+", &Pattern{ - Affix: "\x00\x01+", - FormatWidth: 2, - MinIntegerDigits: 1, + Affix: "\x00\x01+", + FormatWidth: 2, + RoundingContext: RoundingContext{ + MinIntegerDigits: 1, + }, }, }, { "0000", &Pattern{ - FormatWidth: 4, - MinIntegerDigits: 4, + FormatWidth: 4, + RoundingContext: RoundingContext{ + MinIntegerDigits: 4, + }, }, }, { ".#", &Pattern{ - FormatWidth: 2, - MaxFractionDigits: 1, + FormatWidth: 2, + RoundingContext: RoundingContext{ + MaxFractionDigits: 1, + }, }, }, { "#0.###", &Pattern{ - FormatWidth: 6, - MinIntegerDigits: 1, - MaxFractionDigits: 3, + FormatWidth: 6, + RoundingContext: RoundingContext{ + MinIntegerDigits: 1, + MaxFractionDigits: 3, + }, }, }, { "#0.######", &Pattern{ - FormatWidth: 9, - MinIntegerDigits: 1, - MaxFractionDigits: 6, + FormatWidth: 9, + RoundingContext: RoundingContext{ + MinIntegerDigits: 1, + MaxFractionDigits: 6, + }, }, }, { "#,0", &Pattern{ - FormatWidth: 3, - GroupingSize: [2]uint8{1, 0}, - MinIntegerDigits: 1, + FormatWidth: 3, + GroupingSize: [2]uint8{1, 0}, + RoundingContext: RoundingContext{ + MinIntegerDigits: 1, + }, }, }, { "#,0.00", &Pattern{ - FormatWidth: 6, - GroupingSize: [2]uint8{1, 0}, - MinIntegerDigits: 1, - MinFractionDigits: 2, - MaxFractionDigits: 2, + FormatWidth: 6, + GroupingSize: [2]uint8{1, 0}, + RoundingContext: RoundingContext{ + MinIntegerDigits: 1, + MinFractionDigits: 2, + MaxFractionDigits: 2, + }, }, }, { "#,##0.###", &Pattern{ - FormatWidth: 9, - GroupingSize: [2]uint8{3, 0}, - MinIntegerDigits: 1, - MaxFractionDigits: 3, + FormatWidth: 9, + GroupingSize: [2]uint8{3, 0}, + RoundingContext: RoundingContext{ + MinIntegerDigits: 1, + MaxFractionDigits: 3, + }, }, }, { "#,##,##0.###", &Pattern{ - FormatWidth: 12, - GroupingSize: [2]uint8{3, 2}, - MinIntegerDigits: 1, - MaxFractionDigits: 3, + FormatWidth: 12, + GroupingSize: [2]uint8{3, 2}, + RoundingContext: RoundingContext{ + MinIntegerDigits: 1, + MaxFractionDigits: 3, + }, }, }, { // Ignore additional separators. "#,####,##,##0.###", &Pattern{ - FormatWidth: 17, - GroupingSize: [2]uint8{3, 2}, - MinIntegerDigits: 1, - MaxFractionDigits: 3, + FormatWidth: 17, + GroupingSize: [2]uint8{3, 2}, + RoundingContext: RoundingContext{ + MinIntegerDigits: 1, + MaxFractionDigits: 3, + }, }, }, { "#E0", &Pattern{ - FormatWidth: 3, - MaxIntegerDigits: 1, - MinExponentDigits: 1, + FormatWidth: 3, + RoundingContext: RoundingContext{ + MaxIntegerDigits: 1, + MinExponentDigits: 1, + }, }, }, { // At least one exponent digit is required. As long as this is true, one can @@ -121,30 +147,47 @@ var testCases = []struct { }, { "0E0", &Pattern{ - FormatWidth: 3, - MinIntegerDigits: 1, - MinExponentDigits: 1, + FormatWidth: 3, + RoundingContext: RoundingContext{ + MinIntegerDigits: 1, + MinExponentDigits: 1, + }, + }, +}, { + "##0.###E00", + &Pattern{ + FormatWidth: 10, + RoundingContext: RoundingContext{ + MinIntegerDigits: 1, + MaxIntegerDigits: 3, + MaxFractionDigits: 3, + MinExponentDigits: 2, + }, }, }, { "##00.0#E0", &Pattern{ - FormatWidth: 9, - MinIntegerDigits: 2, - MaxIntegerDigits: 4, - MinFractionDigits: 1, - MaxFractionDigits: 2, - MinExponentDigits: 1, + FormatWidth: 9, + RoundingContext: RoundingContext{ + MinIntegerDigits: 2, + MaxIntegerDigits: 4, + MinFractionDigits: 1, + MaxFractionDigits: 2, + MinExponentDigits: 1, + }, }, }, { "#00.0E+0", &Pattern{ - FormatWidth: 8, - Flags: AlwaysExpSign, - MinIntegerDigits: 2, - MaxIntegerDigits: 3, - MinFractionDigits: 1, - MaxFractionDigits: 1, - MinExponentDigits: 1, + FormatWidth: 8, + Flags: AlwaysExpSign, + RoundingContext: RoundingContext{ + MinIntegerDigits: 2, + MaxIntegerDigits: 3, + MinFractionDigits: 1, + MaxFractionDigits: 1, + MinExponentDigits: 1, + }, }, }, { "0.0E++0", @@ -156,45 +199,58 @@ var testCases = []struct { // significant digits "@", &Pattern{ - FormatWidth: 1, - MinSignificantDigits: 1, - MaxSignificantDigits: 1, + FormatWidth: 1, + RoundingContext: RoundingContext{ + MinSignificantDigits: 1, + MaxSignificantDigits: 1, + MaxFractionDigits: -1, + }, }, }, { // significant digits "@@@@", &Pattern{ - FormatWidth: 4, - MinSignificantDigits: 4, - MaxSignificantDigits: 4, + FormatWidth: 4, + RoundingContext: RoundingContext{ + MinSignificantDigits: 4, + MaxSignificantDigits: 4, + MaxFractionDigits: -1, + }, }, }, { "@###", &Pattern{ - FormatWidth: 4, - MinSignificantDigits: 1, - MaxSignificantDigits: 4, + FormatWidth: 4, + RoundingContext: RoundingContext{ + MinSignificantDigits: 1, + MaxSignificantDigits: 4, + MaxFractionDigits: -1, + }, }, }, { // Exponents in significant digits mode gets normalized. "@@E0", &Pattern{ - FormatWidth: 4, - MinIntegerDigits: 1, - MaxIntegerDigits: 1, - MinFractionDigits: 1, - MaxFractionDigits: 1, - MinExponentDigits: 1, + FormatWidth: 4, + RoundingContext: RoundingContext{ + MinIntegerDigits: 1, + MaxIntegerDigits: 1, + MinFractionDigits: 1, + MaxFractionDigits: 1, + MinExponentDigits: 1, + }, }, }, { "@###E00", &Pattern{ - FormatWidth: 7, - MinIntegerDigits: 1, - MaxIntegerDigits: 1, - MinFractionDigits: 0, - MaxFractionDigits: 3, - MinExponentDigits: 2, + FormatWidth: 7, + RoundingContext: RoundingContext{ + MinIntegerDigits: 1, + MaxIntegerDigits: 1, + MinFractionDigits: 0, + MaxFractionDigits: 3, + MinExponentDigits: 2, + }, }, }, { // The significant digits mode does not allow fractions. @@ -204,73 +260,89 @@ var testCases = []struct { //alternative negative pattern "#0.###;(#0.###)", &Pattern{ - Affix: "\x00\x00\x01(\x01)", - NegOffset: 2, - FormatWidth: 6, - MinIntegerDigits: 1, - MaxFractionDigits: 3, + Affix: "\x00\x00\x01(\x01)", + NegOffset: 2, + FormatWidth: 6, + RoundingContext: RoundingContext{ + MinIntegerDigits: 1, + MaxFractionDigits: 3, + }, }, }, { // Rounding increment "1.05", &Pattern{ - RoundIncrement: 105, - FormatWidth: 4, - MinIntegerDigits: 1, - MinFractionDigits: 2, - MaxFractionDigits: 2, + FormatWidth: 4, + RoundingContext: RoundingContext{ + Increment: 105, + IncrementScale: 2, + MinIntegerDigits: 1, + MinFractionDigits: 2, + MaxFractionDigits: 2, + }, }, }, { // Rounding increment with grouping "1,05", &Pattern{ - RoundIncrement: 105, - FormatWidth: 4, - GroupingSize: [2]uint8{2, 0}, - MinIntegerDigits: 3, - MinFractionDigits: 0, - MaxFractionDigits: 0, + FormatWidth: 4, + GroupingSize: [2]uint8{2, 0}, + RoundingContext: RoundingContext{ + Increment: 105, + IncrementScale: 0, + MinIntegerDigits: 3, + MinFractionDigits: 0, + MaxFractionDigits: 0, + }, }, }, { "0.0%", &Pattern{ - Affix: "\x00\x01%", - DigitShift: 2, - FormatWidth: 4, - MinIntegerDigits: 1, - MinFractionDigits: 1, - MaxFractionDigits: 1, + Affix: "\x00\x01%", + FormatWidth: 4, + RoundingContext: RoundingContext{ + DigitShift: 2, + MinIntegerDigits: 1, + MinFractionDigits: 1, + MaxFractionDigits: 1, + }, }, }, { "0.0‰", &Pattern{ - Affix: "\x00\x03‰", - DigitShift: 3, - FormatWidth: 4, - MinIntegerDigits: 1, - MinFractionDigits: 1, - MaxFractionDigits: 1, + Affix: "\x00\x03‰", + FormatWidth: 4, + RoundingContext: RoundingContext{ + DigitShift: 3, + MinIntegerDigits: 1, + MinFractionDigits: 1, + MaxFractionDigits: 1, + }, }, }, { "#,##0.00¤", &Pattern{ - Affix: "\x00\x02¤", - FormatWidth: 9, - GroupingSize: [2]uint8{3, 0}, - MinIntegerDigits: 1, - MinFractionDigits: 2, - MaxFractionDigits: 2, + Affix: "\x00\x02¤", + FormatWidth: 9, + GroupingSize: [2]uint8{3, 0}, + RoundingContext: RoundingContext{ + MinIntegerDigits: 1, + MinFractionDigits: 2, + MaxFractionDigits: 2, + }, }, }, { "#,##0.00 ¤;(#,##0.00 ¤)", &Pattern{Affix: "\x00\x04\u00a0¤\x01(\x05\u00a0¤)", - NegOffset: 6, - DigitShift: 0, - FormatWidth: 10, - GroupingSize: [2]uint8{3, 0}, - MinIntegerDigits: 1, - MinFractionDigits: 2, - MaxFractionDigits: 2, + NegOffset: 6, + FormatWidth: 10, + GroupingSize: [2]uint8{3, 0}, + RoundingContext: RoundingContext{ + DigitShift: 0, + MinIntegerDigits: 1, + MinFractionDigits: 2, + MaxFractionDigits: 2, + }, }, }, { // padding @@ -321,16 +393,21 @@ var testCases = []struct { }, { `* #0 o''clock`, &Pattern{Affix: "\x00\x09 o\\'clock", - FormatWidth: 10, - PadRune: 32, - MinIntegerDigits: 0x1}, + FormatWidth: 10, + PadRune: 32, + RoundingContext: RoundingContext{ + MinIntegerDigits: 0x1, + }, + }, }, { `'123'* #0'456'`, &Pattern{Affix: "\x05'123'\x05'456'", - FormatWidth: 8, - PadRune: 32, - MinIntegerDigits: 0x1, - Flags: PadAfterPrefix}, + FormatWidth: 8, + PadRune: 32, + RoundingContext: RoundingContext{ + MinIntegerDigits: 0x1, + }, + Flags: PadAfterPrefix}, }, { // no duplicate padding "*xpre#suf*x", nil, @@ -354,8 +431,8 @@ func TestParsePattern(t *testing.T) { } func TestPatternSize(t *testing.T) { - if sz := unsafe.Sizeof(Pattern{}); sz > 48 { - t.Errorf("got %d; want <= 48", sz) + if sz := unsafe.Sizeof(Pattern{}); sz > 56 { + t.Errorf("got %d; want <= 56", sz) } } diff --git a/vendor/golang.org/x/text/internal/number/tables.go b/vendor/golang.org/x/text/internal/number/tables.go index b08acc48c..286712b17 100644 --- a/vendor/golang.org/x/text/internal/number/tables.go +++ b/vendor/golang.org/x/text/internal/number/tables.go @@ -846,277 +846,309 @@ var tagToPercent = []uint8{ // 754 elements 0x04, 0x04, } // Size: 778 bytes -var formats = []Pattern{Pattern{Affix: "", - Offset: 0x0, - NegOffset: 0x0, - FormatWidth: 0x0, - RoundIncrement: 0x0, - PadRune: 0, - DigitShift: 0x0, - GroupingSize: [2]uint8{0x0, - 0x0}, - Flags: 0x0, +var formats = []Pattern{Pattern{RoundingContext: RoundingContext{MaxSignificantDigits: 0, + MaxFractionDigits: 0, + Increment: 0x0, + IncrementScale: 0x0, + Mode: 0x0, + DigitShift: 0x0, MinIntegerDigits: 0x0, MaxIntegerDigits: 0x0, MinFractionDigits: 0x0, - MaxFractionDigits: 0x0, MinSignificantDigits: 0x0, - MaxSignificantDigits: 0x0, MinExponentDigits: 0x0}, - Pattern{Affix: "", - Offset: 0x0, - NegOffset: 0x0, - FormatWidth: 0x9, - RoundIncrement: 0x0, - PadRune: 0, - DigitShift: 0x0, - GroupingSize: [2]uint8{0x3, - 0x0}, - Flags: 0x0, + Affix: "", + Offset: 0x0, + NegOffset: 0x0, + PadRune: 0, + FormatWidth: 0x0, + GroupingSize: [2]uint8{0x0, + 0x0}, + Flags: 0x0}, + Pattern{RoundingContext: RoundingContext{MaxSignificantDigits: 0, + MaxFractionDigits: 3, + Increment: 0x0, + IncrementScale: 0x0, + Mode: 0x0, + DigitShift: 0x0, MinIntegerDigits: 0x1, MaxIntegerDigits: 0x0, MinFractionDigits: 0x0, - MaxFractionDigits: 0x3, MinSignificantDigits: 0x0, - MaxSignificantDigits: 0x0, MinExponentDigits: 0x0}, - Pattern{Affix: "", - Offset: 0x0, - NegOffset: 0x0, - FormatWidth: 0x3, - RoundIncrement: 0x0, - PadRune: 0, - DigitShift: 0x0, - GroupingSize: [2]uint8{0x0, + Affix: "", + Offset: 0x0, + NegOffset: 0x0, + PadRune: 0, + FormatWidth: 0x9, + GroupingSize: [2]uint8{0x3, 0x0}, - Flags: 0x0, + Flags: 0x0}, + Pattern{RoundingContext: RoundingContext{MaxSignificantDigits: 0, + MaxFractionDigits: 0, + Increment: 0x0, + IncrementScale: 0x0, + Mode: 0x0, + DigitShift: 0x0, MinIntegerDigits: 0x0, MaxIntegerDigits: 0x1, MinFractionDigits: 0x0, - MaxFractionDigits: 0x0, MinSignificantDigits: 0x0, - MaxSignificantDigits: 0x0, MinExponentDigits: 0x1}, - Pattern{Affix: "\x00\x03\u00a0%", - Offset: 0x0, - NegOffset: 0x0, - FormatWidth: 0x7, - RoundIncrement: 0x0, - PadRune: 0, - DigitShift: 0x2, - GroupingSize: [2]uint8{0x3, + Affix: "", + Offset: 0x0, + NegOffset: 0x0, + PadRune: 0, + FormatWidth: 0x3, + GroupingSize: [2]uint8{0x0, 0x0}, - Flags: 0x0, + Flags: 0x0}, + Pattern{RoundingContext: RoundingContext{MaxSignificantDigits: 0, + MaxFractionDigits: 0, + Increment: 0x0, + IncrementScale: 0x0, + Mode: 0x0, + DigitShift: 0x2, MinIntegerDigits: 0x1, MaxIntegerDigits: 0x0, MinFractionDigits: 0x0, - MaxFractionDigits: 0x0, MinSignificantDigits: 0x0, - MaxSignificantDigits: 0x0, MinExponentDigits: 0x0}, - Pattern{Affix: "\x00\x01%", - Offset: 0x0, - NegOffset: 0x0, - FormatWidth: 0x6, - RoundIncrement: 0x0, - PadRune: 0, - DigitShift: 0x2, + Affix: "\x00\x03\u00a0%", + Offset: 0x0, + NegOffset: 0x0, + PadRune: 0, + FormatWidth: 0x7, GroupingSize: [2]uint8{0x3, 0x0}, - Flags: 0x0, + Flags: 0x0}, + Pattern{RoundingContext: RoundingContext{MaxSignificantDigits: 0, + MaxFractionDigits: 0, + Increment: 0x0, + IncrementScale: 0x0, + Mode: 0x0, + DigitShift: 0x2, MinIntegerDigits: 0x1, MaxIntegerDigits: 0x0, MinFractionDigits: 0x0, - MaxFractionDigits: 0x0, MinSignificantDigits: 0x0, - MaxSignificantDigits: 0x0, MinExponentDigits: 0x0}, - Pattern{Affix: "", - Offset: 0x0, - NegOffset: 0x0, - FormatWidth: 0xc, - RoundIncrement: 0x0, - PadRune: 0, - DigitShift: 0x0, + Affix: "\x00\x01%", + Offset: 0x0, + NegOffset: 0x0, + PadRune: 0, + FormatWidth: 0x6, GroupingSize: [2]uint8{0x3, - 0x2}, - Flags: 0x0, + 0x0}, + Flags: 0x0}, + Pattern{RoundingContext: RoundingContext{MaxSignificantDigits: 0, + MaxFractionDigits: 3, + Increment: 0x0, + IncrementScale: 0x0, + Mode: 0x0, + DigitShift: 0x0, MinIntegerDigits: 0x1, MaxIntegerDigits: 0x0, MinFractionDigits: 0x0, - MaxFractionDigits: 0x3, MinSignificantDigits: 0x0, - MaxSignificantDigits: 0x0, MinExponentDigits: 0x0}, - Pattern{Affix: "\x00\x01%", - Offset: 0x0, - NegOffset: 0x0, - FormatWidth: 0x9, - RoundIncrement: 0x0, - PadRune: 0, - DigitShift: 0x2, + Affix: "", + Offset: 0x0, + NegOffset: 0x0, + PadRune: 0, + FormatWidth: 0xc, GroupingSize: [2]uint8{0x3, 0x2}, - Flags: 0x0, + Flags: 0x0}, + Pattern{RoundingContext: RoundingContext{MaxSignificantDigits: 0, + MaxFractionDigits: 0, + Increment: 0x0, + IncrementScale: 0x0, + Mode: 0x0, + DigitShift: 0x2, MinIntegerDigits: 0x1, MaxIntegerDigits: 0x0, MinFractionDigits: 0x0, - MaxFractionDigits: 0x0, MinSignificantDigits: 0x0, - MaxSignificantDigits: 0x0, MinExponentDigits: 0x0}, - Pattern{Affix: "\x00\x03\u00a0%", - Offset: 0x0, - NegOffset: 0x0, - FormatWidth: 0xa, - RoundIncrement: 0x0, - PadRune: 0, - DigitShift: 0x2, + Affix: "\x00\x01%", + Offset: 0x0, + NegOffset: 0x0, + PadRune: 0, + FormatWidth: 0x9, GroupingSize: [2]uint8{0x3, 0x2}, - Flags: 0x0, + Flags: 0x0}, + Pattern{RoundingContext: RoundingContext{MaxSignificantDigits: 0, + MaxFractionDigits: 0, + Increment: 0x0, + IncrementScale: 0x0, + Mode: 0x0, + DigitShift: 0x2, MinIntegerDigits: 0x1, MaxIntegerDigits: 0x0, MinFractionDigits: 0x0, - MaxFractionDigits: 0x0, MinSignificantDigits: 0x0, - MaxSignificantDigits: 0x0, MinExponentDigits: 0x0}, - Pattern{Affix: "", - Offset: 0x0, - NegOffset: 0x0, - FormatWidth: 0x9, - RoundIncrement: 0x0, - PadRune: 0, - DigitShift: 0x0, - GroupingSize: [2]uint8{0x0, - 0x0}, - Flags: 0x0, + Affix: "\x00\x03\u00a0%", + Offset: 0x0, + NegOffset: 0x0, + PadRune: 0, + FormatWidth: 0xa, + GroupingSize: [2]uint8{0x3, + 0x2}, + Flags: 0x0}, + Pattern{RoundingContext: RoundingContext{MaxSignificantDigits: 0, + MaxFractionDigits: 6, + Increment: 0x0, + IncrementScale: 0x0, + Mode: 0x0, + DigitShift: 0x0, MinIntegerDigits: 0x1, MaxIntegerDigits: 0x0, MinFractionDigits: 0x0, - MaxFractionDigits: 0x6, MinSignificantDigits: 0x0, - MaxSignificantDigits: 0x0, MinExponentDigits: 0x0}, - Pattern{Affix: "", - Offset: 0x0, - NegOffset: 0x0, - FormatWidth: 0xd, - RoundIncrement: 0x0, - PadRune: 0, - DigitShift: 0x0, + Affix: "", + Offset: 0x0, + NegOffset: 0x0, + PadRune: 0, + FormatWidth: 0x9, GroupingSize: [2]uint8{0x0, 0x0}, - Flags: 0x4, + Flags: 0x0}, + Pattern{RoundingContext: RoundingContext{MaxSignificantDigits: 0, + MaxFractionDigits: 6, + Increment: 0x0, + IncrementScale: 0x0, + Mode: 0x0, + DigitShift: 0x0, MinIntegerDigits: 0x1, MaxIntegerDigits: 0x0, MinFractionDigits: 0x6, - MaxFractionDigits: 0x6, MinSignificantDigits: 0x0, - MaxSignificantDigits: 0x0, MinExponentDigits: 0x3}, - Pattern{Affix: "\x00\x01%", - Offset: 0x0, - NegOffset: 0x0, - FormatWidth: 0x3, - RoundIncrement: 0x0, - PadRune: 0, - DigitShift: 0x2, + Affix: "", + Offset: 0x0, + NegOffset: 0x0, + PadRune: 0, + FormatWidth: 0xd, GroupingSize: [2]uint8{0x0, 0x0}, - Flags: 0x0, + Flags: 0x4}, + Pattern{RoundingContext: RoundingContext{MaxSignificantDigits: 0, + MaxFractionDigits: 0, + Increment: 0x0, + IncrementScale: 0x0, + Mode: 0x0, + DigitShift: 0x2, MinIntegerDigits: 0x1, MaxIntegerDigits: 0x0, MinFractionDigits: 0x0, - MaxFractionDigits: 0x0, MinSignificantDigits: 0x0, - MaxSignificantDigits: 0x0, MinExponentDigits: 0x0}, - Pattern{Affix: "\x03%\u00a0\x00", - Offset: 0x0, - NegOffset: 0x0, - FormatWidth: 0x7, - RoundIncrement: 0x0, - PadRune: 0, - DigitShift: 0x2, - GroupingSize: [2]uint8{0x3, + Affix: "\x00\x01%", + Offset: 0x0, + NegOffset: 0x0, + PadRune: 0, + FormatWidth: 0x3, + GroupingSize: [2]uint8{0x0, 0x0}, - Flags: 0x0, + Flags: 0x0}, + Pattern{RoundingContext: RoundingContext{MaxSignificantDigits: 0, + MaxFractionDigits: 0, + Increment: 0x0, + IncrementScale: 0x0, + Mode: 0x0, + DigitShift: 0x2, MinIntegerDigits: 0x1, MaxIntegerDigits: 0x0, MinFractionDigits: 0x0, - MaxFractionDigits: 0x0, MinSignificantDigits: 0x0, - MaxSignificantDigits: 0x0, MinExponentDigits: 0x0}, - Pattern{Affix: "\x03%\u00a0\x00\x04%\u00a0-\x00", - Offset: 0x0, - NegOffset: 0x5, - FormatWidth: 0x7, - RoundIncrement: 0x0, - PadRune: 0, - DigitShift: 0x2, + Affix: "\x03%\u00a0\x00", + Offset: 0x0, + NegOffset: 0x0, + PadRune: 0, + FormatWidth: 0x7, GroupingSize: [2]uint8{0x3, 0x0}, - Flags: 0x0, + Flags: 0x0}, + Pattern{RoundingContext: RoundingContext{MaxSignificantDigits: 0, + MaxFractionDigits: 0, + Increment: 0x0, + IncrementScale: 0x0, + Mode: 0x0, + DigitShift: 0x2, MinIntegerDigits: 0x1, MaxIntegerDigits: 0x0, MinFractionDigits: 0x0, - MaxFractionDigits: 0x0, MinSignificantDigits: 0x0, - MaxSignificantDigits: 0x0, MinExponentDigits: 0x0}, - Pattern{Affix: "\x01[\x01]", - Offset: 0x0, - NegOffset: 0x0, - FormatWidth: 0x5, - RoundIncrement: 0x0, - PadRune: 0, - DigitShift: 0x0, - GroupingSize: [2]uint8{0x0, + Affix: "\x03%\u00a0\x00\x04%\u00a0-\x00", + Offset: 0x0, + NegOffset: 0x5, + PadRune: 0, + FormatWidth: 0x7, + GroupingSize: [2]uint8{0x3, 0x0}, - Flags: 0x0, + Flags: 0x0}, + Pattern{RoundingContext: RoundingContext{MaxSignificantDigits: 0, + MaxFractionDigits: 0, + Increment: 0x0, + IncrementScale: 0x0, + Mode: 0x0, + DigitShift: 0x0, MinIntegerDigits: 0x0, MaxIntegerDigits: 0x1, MinFractionDigits: 0x0, - MaxFractionDigits: 0x0, MinSignificantDigits: 0x0, - MaxSignificantDigits: 0x0, MinExponentDigits: 0x1}, - Pattern{Affix: "", - Offset: 0x0, - NegOffset: 0x0, - FormatWidth: 0x1, - RoundIncrement: 0x0, - PadRune: 0, - DigitShift: 0x0, + Affix: "\x01[\x01]", + Offset: 0x0, + NegOffset: 0x0, + PadRune: 0, + FormatWidth: 0x5, GroupingSize: [2]uint8{0x0, 0x0}, - Flags: 0x0, + Flags: 0x0}, + Pattern{RoundingContext: RoundingContext{MaxSignificantDigits: 0, + MaxFractionDigits: 0, + Increment: 0x0, + IncrementScale: 0x0, + Mode: 0x0, + DigitShift: 0x0, MinIntegerDigits: 0x0, MaxIntegerDigits: 0x0, MinFractionDigits: 0x0, - MaxFractionDigits: 0x0, MinSignificantDigits: 0x0, - MaxSignificantDigits: 0x0, MinExponentDigits: 0x0}, - Pattern{Affix: "\x01%\x00", - Offset: 0x0, - NegOffset: 0x0, - FormatWidth: 0x6, - RoundIncrement: 0x0, - PadRune: 0, - DigitShift: 0x2, - GroupingSize: [2]uint8{0x3, + Affix: "", + Offset: 0x0, + NegOffset: 0x0, + PadRune: 0, + FormatWidth: 0x1, + GroupingSize: [2]uint8{0x0, 0x0}, - Flags: 0x0, + Flags: 0x0}, + Pattern{RoundingContext: RoundingContext{MaxSignificantDigits: 0, + MaxFractionDigits: 0, + Increment: 0x0, + IncrementScale: 0x0, + Mode: 0x0, + DigitShift: 0x2, MinIntegerDigits: 0x1, MaxIntegerDigits: 0x0, MinFractionDigits: 0x0, - MaxFractionDigits: 0x0, MinSignificantDigits: 0x0, - MaxSignificantDigits: 0x0, - MinExponentDigits: 0x0}} + MinExponentDigits: 0x0}, + Affix: "\x01%\x00", + Offset: 0x0, + NegOffset: 0x0, + PadRune: 0, + FormatWidth: 0x6, + GroupingSize: [2]uint8{0x3, + 0x0}, + Flags: 0x0}} // Total table size 7101 bytes (6KiB); checksum: 5190D0B3 |