summaryrefslogtreecommitdiffstats
path: root/vendor/golang.org/x/text/internal/number/format.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/golang.org/x/text/internal/number/format.go')
-rwxr-xr-xvendor/golang.org/x/text/internal/number/format.go176
1 files changed, 97 insertions, 79 deletions
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 &nbsp;
+// 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)...)