OSDN Git Service

new repo
[bytom/vapor.git] / vendor / golang.org / x / text / internal / number / format.go
1 // Copyright 2017 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
4
5 package number
6
7 import (
8         "strconv"
9         "unicode/utf8"
10
11         "golang.org/x/text/language"
12 )
13
14 // TODO:
15 // - grouping of fractions
16 // - allow user-defined superscript notation (such as <sup>4</sup>)
17 // - same for non-breaking spaces, like &nbsp;
18
19 // Formatting proceeds along the following lines:
20 // 0) Compose rounding information from format and context.
21 // 1) Convert a number into a Decimal.
22 // 2) Sanitize Decimal by adding trailing zeros, removing leading digits, and
23 //    (non-increment) rounding. The Decimal that results from this is suitable
24 //    for determining the plural form.
25 // 3) Render the Decimal in the localized form.
26
27 // Formatter contains all the information needed to render a number.
28 type Formatter struct {
29         Pattern
30         Info
31 }
32
33 func (f *Formatter) init(t language.Tag, index []uint8) {
34         f.Info = InfoFromTag(t)
35         for ; ; t = t.Parent() {
36                 if ci, ok := language.CompactIndex(t); ok {
37                         f.Pattern = formats[index[ci]]
38                         break
39                 }
40         }
41 }
42
43 // InitPattern initializes a Formatter for the given Pattern.
44 func (f *Formatter) InitPattern(t language.Tag, pat *Pattern) {
45         f.Info = InfoFromTag(t)
46         f.Pattern = *pat
47 }
48
49 // InitDecimal initializes a Formatter using the default Pattern for the given
50 // language.
51 func (f *Formatter) InitDecimal(t language.Tag) {
52         f.init(t, tagToDecimal)
53 }
54
55 // InitScientific initializes a Formatter using the default Pattern for the
56 // given language.
57 func (f *Formatter) InitScientific(t language.Tag) {
58         f.init(t, tagToScientific)
59         f.Pattern.MinFractionDigits = 0
60         f.Pattern.MaxFractionDigits = -1
61 }
62
63 // InitEngineering initializes a Formatter using the default Pattern for the
64 // given language.
65 func (f *Formatter) InitEngineering(t language.Tag) {
66         f.init(t, tagToScientific)
67         f.Pattern.MinFractionDigits = 0
68         f.Pattern.MaxFractionDigits = -1
69         f.Pattern.MaxIntegerDigits = 3
70         f.Pattern.MinIntegerDigits = 1
71 }
72
73 // InitPercent initializes a Formatter using the default Pattern for the given
74 // language.
75 func (f *Formatter) InitPercent(t language.Tag) {
76         f.init(t, tagToPercent)
77 }
78
79 // InitPerMille initializes a Formatter using the default Pattern for the given
80 // language.
81 func (f *Formatter) InitPerMille(t language.Tag) {
82         f.init(t, tagToPercent)
83         f.Pattern.DigitShift = 3
84 }
85
86 func (f *Formatter) Append(dst []byte, x interface{}) []byte {
87         var d Decimal
88         r := f.RoundingContext
89         d.Convert(r, x)
90         return f.Render(dst, FormatDigits(&d, r))
91 }
92
93 func FormatDigits(d *Decimal, r RoundingContext) Digits {
94         if r.isScientific() {
95                 return scientificVisibleDigits(r, d)
96         }
97         return decimalVisibleDigits(r, d)
98 }
99
100 func (f *Formatter) Format(dst []byte, d *Decimal) []byte {
101         return f.Render(dst, FormatDigits(d, f.RoundingContext))
102 }
103
104 func (f *Formatter) Render(dst []byte, d Digits) []byte {
105         var result []byte
106         var postPrefix, preSuffix int
107         if d.IsScientific {
108                 result, postPrefix, preSuffix = appendScientific(dst, f, &d)
109         } else {
110                 result, postPrefix, preSuffix = appendDecimal(dst, f, &d)
111         }
112         if f.PadRune == 0 {
113                 return result
114         }
115         width := int(f.FormatWidth)
116         if count := utf8.RuneCount(result); count < width {
117                 insertPos := 0
118                 switch f.Flags & PadMask {
119                 case PadAfterPrefix:
120                         insertPos = postPrefix
121                 case PadBeforeSuffix:
122                         insertPos = preSuffix
123                 case PadAfterSuffix:
124                         insertPos = len(result)
125                 }
126                 num := width - count
127                 pad := [utf8.UTFMax]byte{' '}
128                 sz := 1
129                 if r := f.PadRune; r != 0 {
130                         sz = utf8.EncodeRune(pad[:], r)
131                 }
132                 extra := sz * num
133                 if n := len(result) + extra; n < cap(result) {
134                         result = result[:n]
135                         copy(result[insertPos+extra:], result[insertPos:])
136                 } else {
137                         buf := make([]byte, n)
138                         copy(buf, result[:insertPos])
139                         copy(buf[insertPos+extra:], result[insertPos:])
140                         result = buf
141                 }
142                 for ; num > 0; num-- {
143                         insertPos += copy(result[insertPos:], pad[:sz])
144                 }
145         }
146         return result
147 }
148
149 // decimalVisibleDigits converts d according to the RoundingContext. Note that
150 // the exponent may change as a result of this operation.
151 func decimalVisibleDigits(r RoundingContext, d *Decimal) Digits {
152         if d.NaN || d.Inf {
153                 return Digits{digits: digits{Neg: d.Neg, NaN: d.NaN, Inf: d.Inf}}
154         }
155         n := Digits{digits: d.normalize().digits}
156
157         if maxSig := int(r.MaxSignificantDigits); maxSig > 0 {
158                 // TODO: really round to zero?
159                 n.round(ToZero, maxSig)
160         }
161         digits := n.Digits
162         exp := n.Exp
163         exp += int32(r.DigitShift)
164
165         // Cap integer digits. Remove *most-significant* digits.
166         if r.MaxIntegerDigits > 0 {
167                 if p := int(exp) - int(r.MaxIntegerDigits); p > 0 {
168                         if p > len(digits) {
169                                 p = len(digits)
170                         }
171                         if digits = digits[p:]; len(digits) == 0 {
172                                 exp = 0
173                         } else {
174                                 exp -= int32(p)
175                         }
176                         // Strip leading zeros.
177                         for len(digits) > 0 && digits[0] == 0 {
178                                 digits = digits[1:]
179                                 exp--
180                         }
181                 }
182         }
183
184         // Rounding usually is done by convert, but we don't rely on it.
185         numFrac := len(digits) - int(exp)
186         if r.MaxSignificantDigits == 0 && int(r.MaxFractionDigits) < numFrac {
187                 p := int(exp) + int(r.MaxFractionDigits)
188                 if p <= 0 {
189                         p = 0
190                 } else if p >= len(digits) {
191                         p = len(digits)
192                 }
193                 digits = digits[:p] // TODO: round
194         }
195
196         // set End (trailing zeros)
197         n.End = int32(len(digits))
198         if len(digits) == 0 {
199                 if r.MinFractionDigits > 0 {
200                         n.End = int32(r.MinFractionDigits)
201                 }
202                 if p := int32(r.MinSignificantDigits) - 1; p > n.End {
203                         n.End = p
204                 }
205         } else {
206                 if end := exp + int32(r.MinFractionDigits); end > n.End {
207                         n.End = end
208                 }
209                 if n.End < int32(r.MinSignificantDigits) {
210                         n.End = int32(r.MinSignificantDigits)
211                 }
212         }
213         n.Digits = digits
214         n.Exp = exp
215         return n
216 }
217
218 // appendDecimal appends a formatted number to dst. It returns two possible
219 // insertion points for padding.
220 func appendDecimal(dst []byte, f *Formatter, n *Digits) (b []byte, postPre, preSuf int) {
221         if dst, ok := f.renderSpecial(dst, n); ok {
222                 return dst, 0, len(dst)
223         }
224         digits := n.Digits
225         exp := n.Exp
226
227         // Split in integer and fraction part.
228         var intDigits, fracDigits []byte
229         numInt := 0
230         numFrac := int(n.End - n.Exp)
231         if exp > 0 {
232                 numInt = int(exp)
233                 if int(exp) >= len(digits) { // ddddd | ddddd00
234                         intDigits = digits
235                 } else { // ddd.dd
236                         intDigits = digits[:exp]
237                         fracDigits = digits[exp:]
238                 }
239         } else {
240                 fracDigits = digits
241         }
242
243         neg := n.Neg
244         affix, suffix := f.getAffixes(neg)
245         dst = appendAffix(dst, f, affix, neg)
246         savedLen := len(dst)
247
248         minInt := int(f.MinIntegerDigits)
249         if minInt == 0 && f.MinSignificantDigits > 0 {
250                 minInt = 1
251         }
252         // add leading zeros
253         for i := minInt; i > numInt; i-- {
254                 dst = f.AppendDigit(dst, 0)
255                 if f.needsSep(i) {
256                         dst = append(dst, f.Symbol(SymGroup)...)
257                 }
258         }
259         i := 0
260         for ; i < len(intDigits); i++ {
261                 dst = f.AppendDigit(dst, intDigits[i])
262                 if f.needsSep(numInt - i) {
263                         dst = append(dst, f.Symbol(SymGroup)...)
264                 }
265         }
266         for ; i < numInt; i++ {
267                 dst = f.AppendDigit(dst, 0)
268                 if f.needsSep(numInt - i) {
269                         dst = append(dst, f.Symbol(SymGroup)...)
270                 }
271         }
272
273         if numFrac > 0 || f.Flags&AlwaysDecimalSeparator != 0 {
274                 dst = append(dst, f.Symbol(SymDecimal)...)
275         }
276         // Add trailing zeros
277         i = 0
278         for n := -int(n.Exp); i < n; i++ {
279                 dst = f.AppendDigit(dst, 0)
280         }
281         for _, d := range fracDigits {
282                 i++
283                 dst = f.AppendDigit(dst, d)
284         }
285         for ; i < numFrac; i++ {
286                 dst = f.AppendDigit(dst, 0)
287         }
288         return appendAffix(dst, f, suffix, neg), savedLen, len(dst)
289 }
290
291 func scientificVisibleDigits(r RoundingContext, d *Decimal) Digits {
292         if d.NaN || d.Inf {
293                 return Digits{digits: digits{Neg: d.Neg, NaN: d.NaN, Inf: d.Inf}}
294         }
295         n := Digits{digits: d.normalize().digits, IsScientific: true}
296
297         // Normalize to have at least one digit. This simplifies engineering
298         // notation.
299         if len(n.Digits) == 0 {
300                 n.Digits = append(n.Digits, 0)
301                 n.Exp = 1
302         }
303
304         // Significant digits are transformed by the parser for scientific notation
305         // and do not need to be handled here.
306         maxInt, numInt := int(r.MaxIntegerDigits), int(r.MinIntegerDigits)
307         if numInt == 0 {
308                 numInt = 1
309         }
310
311         // If a maximum number of integers is specified, the minimum must be 1
312         // and the exponent is grouped by this number (e.g. for engineering)
313         if maxInt > numInt {
314                 // Correct the exponent to reflect a single integer digit.
315                 numInt = 1
316                 // engineering
317                 // 0.01234 ([12345]e-1) -> 1.2345e-2  12.345e-3
318                 // 12345   ([12345]e+5) -> 1.2345e4  12.345e3
319                 d := int(n.Exp-1) % maxInt
320                 if d < 0 {
321                         d += maxInt
322                 }
323                 numInt += d
324         }
325
326         if maxSig := int(r.MaxFractionDigits); maxSig >= 0 {
327                 n.round(r.Mode, maxSig+numInt)
328         }
329
330         n.Comma = uint8(numInt)
331         n.End = int32(len(n.Digits))
332         if minSig := int32(r.MinFractionDigits) + int32(numInt); n.End < minSig {
333                 n.End = minSig
334         }
335         return n
336 }
337
338 // appendScientific appends a formatted number to dst. It returns two possible
339 // insertion points for padding.
340 func appendScientific(dst []byte, f *Formatter, n *Digits) (b []byte, postPre, preSuf int) {
341         if dst, ok := f.renderSpecial(dst, n); ok {
342                 return dst, 0, 0
343         }
344         digits := n.Digits
345         numInt := int(n.Comma)
346         numFrac := int(n.End) - int(n.Comma)
347
348         var intDigits, fracDigits []byte
349         if numInt <= len(digits) {
350                 intDigits = digits[:numInt]
351                 fracDigits = digits[numInt:]
352         } else {
353                 intDigits = digits
354         }
355         neg := n.Neg
356         affix, suffix := f.getAffixes(neg)
357         dst = appendAffix(dst, f, affix, neg)
358         savedLen := len(dst)
359
360         i := 0
361         for ; i < len(intDigits); i++ {
362                 dst = f.AppendDigit(dst, intDigits[i])
363                 if f.needsSep(numInt - i) {
364                         dst = append(dst, f.Symbol(SymGroup)...)
365                 }
366         }
367         for ; i < numInt; i++ {
368                 dst = f.AppendDigit(dst, 0)
369                 if f.needsSep(numInt - i) {
370                         dst = append(dst, f.Symbol(SymGroup)...)
371                 }
372         }
373
374         if numFrac > 0 || f.Flags&AlwaysDecimalSeparator != 0 {
375                 dst = append(dst, f.Symbol(SymDecimal)...)
376         }
377         i = 0
378         for ; i < len(fracDigits); i++ {
379                 dst = f.AppendDigit(dst, fracDigits[i])
380         }
381         for ; i < numFrac; i++ {
382                 dst = f.AppendDigit(dst, 0)
383         }
384
385         // exp
386         buf := [12]byte{}
387         // TODO: use exponential if superscripting is not available (no Latin
388         // numbers or no tags) and use exponential in all other cases.
389         exp := n.Exp - int32(n.Comma)
390         exponential := f.Symbol(SymExponential)
391         if exponential == "E" {
392                 dst = append(dst, "\u202f"...) // NARROW NO-BREAK SPACE
393                 dst = append(dst, f.Symbol(SymSuperscriptingExponent)...)
394                 dst = append(dst, "\u202f"...) // NARROW NO-BREAK SPACE
395                 dst = f.AppendDigit(dst, 1)
396                 dst = f.AppendDigit(dst, 0)
397                 switch {
398                 case exp < 0:
399                         dst = append(dst, superMinus...)
400                         exp = -exp
401                 case f.Flags&AlwaysExpSign != 0:
402                         dst = append(dst, superPlus...)
403                 }
404                 b = strconv.AppendUint(buf[:0], uint64(exp), 10)
405                 for i := len(b); i < int(f.MinExponentDigits); i++ {
406                         dst = append(dst, superDigits[0]...)
407                 }
408                 for _, c := range b {
409                         dst = append(dst, superDigits[c-'0']...)
410                 }
411         } else {
412                 dst = append(dst, exponential...)
413                 switch {
414                 case exp < 0:
415                         dst = append(dst, f.Symbol(SymMinusSign)...)
416                         exp = -exp
417                 case f.Flags&AlwaysExpSign != 0:
418                         dst = append(dst, f.Symbol(SymPlusSign)...)
419                 }
420                 b = strconv.AppendUint(buf[:0], uint64(exp), 10)
421                 for i := len(b); i < int(f.MinExponentDigits); i++ {
422                         dst = f.AppendDigit(dst, 0)
423                 }
424                 for _, c := range b {
425                         dst = f.AppendDigit(dst, c-'0')
426                 }
427         }
428         return appendAffix(dst, f, suffix, neg), savedLen, len(dst)
429 }
430
431 const (
432         superMinus = "\u207B" // SUPERSCRIPT HYPHEN-MINUS
433         superPlus  = "\u207A" // SUPERSCRIPT PLUS SIGN
434 )
435
436 var (
437         // Note: the digits are not sequential!!!
438         superDigits = []string{
439                 "\u2070", // SUPERSCRIPT DIGIT ZERO
440                 "\u00B9", // SUPERSCRIPT DIGIT ONE
441                 "\u00B2", // SUPERSCRIPT DIGIT TWO
442                 "\u00B3", // SUPERSCRIPT DIGIT THREE
443                 "\u2074", // SUPERSCRIPT DIGIT FOUR
444                 "\u2075", // SUPERSCRIPT DIGIT FIVE
445                 "\u2076", // SUPERSCRIPT DIGIT SIX
446                 "\u2077", // SUPERSCRIPT DIGIT SEVEN
447                 "\u2078", // SUPERSCRIPT DIGIT EIGHT
448                 "\u2079", // SUPERSCRIPT DIGIT NINE
449         }
450 )
451
452 func (f *Formatter) getAffixes(neg bool) (affix, suffix string) {
453         str := f.Affix
454         if str != "" {
455                 if f.NegOffset > 0 {
456                         if neg {
457                                 str = str[f.NegOffset:]
458                         } else {
459                                 str = str[:f.NegOffset]
460                         }
461                 }
462                 sufStart := 1 + str[0]
463                 affix = str[1:sufStart]
464                 suffix = str[sufStart+1:]
465         }
466         // TODO: introduce a NeedNeg sign to indicate if the left pattern already
467         // has a sign marked?
468         if f.NegOffset == 0 && (neg || f.Flags&AlwaysSign != 0) {
469                 affix = "-" + affix
470         }
471         return affix, suffix
472 }
473
474 func (f *Formatter) renderSpecial(dst []byte, d *Digits) (b []byte, ok bool) {
475         if d.NaN {
476                 return fmtNaN(dst, f), true
477         }
478         if d.Inf {
479                 return fmtInfinite(dst, f, d), true
480         }
481         return dst, false
482 }
483
484 func fmtNaN(dst []byte, f *Formatter) []byte {
485         return append(dst, f.Symbol(SymNan)...)
486 }
487
488 func fmtInfinite(dst []byte, f *Formatter, d *Digits) []byte {
489         affix, suffix := f.getAffixes(d.Neg)
490         dst = appendAffix(dst, f, affix, d.Neg)
491         dst = append(dst, f.Symbol(SymInfinity)...)
492         dst = appendAffix(dst, f, suffix, d.Neg)
493         return dst
494 }
495
496 func appendAffix(dst []byte, f *Formatter, affix string, neg bool) []byte {
497         quoting := false
498         escaping := false
499         for _, r := range affix {
500                 switch {
501                 case escaping:
502                         // escaping occurs both inside and outside of quotes
503                         dst = append(dst, string(r)...)
504                         escaping = false
505                 case r == '\\':
506                         escaping = true
507                 case r == '\'':
508                         quoting = !quoting
509                 case quoting:
510                         dst = append(dst, string(r)...)
511                 case r == '%':
512                         if f.DigitShift == 3 {
513                                 dst = append(dst, f.Symbol(SymPerMille)...)
514                         } else {
515                                 dst = append(dst, f.Symbol(SymPercentSign)...)
516                         }
517                 case r == '-' || r == '+':
518                         if neg {
519                                 dst = append(dst, f.Symbol(SymMinusSign)...)
520                         } else if f.Flags&ElideSign == 0 {
521                                 dst = append(dst, f.Symbol(SymPlusSign)...)
522                         } else {
523                                 dst = append(dst, ' ')
524                         }
525                 default:
526                         dst = append(dst, string(r)...)
527                 }
528         }
529         return dst
530 }