1
2
3
4
5 package number
6
7 import (
8 "strconv"
9 "unicode/utf8"
10
11 "golang.org/x/text/language"
12 )
13
14
15
16
17
18
19
20
21 type VisibleDigits interface {
22 Digits(buf []byte, t language.Tag, scale int) Digits
23
24 }
25
26
27
28
29
30
31
32
33
34
35 type Formatter struct {
36 Pattern
37 Info
38 }
39
40 func (f *Formatter) init(t language.Tag, index []uint8) {
41 f.Info = InfoFromTag(t)
42 f.Pattern = formats[index[tagToID(t)]]
43 }
44
45
46 func (f *Formatter) InitPattern(t language.Tag, pat *Pattern) {
47 f.Info = InfoFromTag(t)
48 f.Pattern = *pat
49 }
50
51
52
53 func (f *Formatter) InitDecimal(t language.Tag) {
54 f.init(t, tagToDecimal)
55 }
56
57
58
59 func (f *Formatter) InitScientific(t language.Tag) {
60 f.init(t, tagToScientific)
61 f.Pattern.MinFractionDigits = 0
62 f.Pattern.MaxFractionDigits = -1
63 }
64
65
66
67 func (f *Formatter) InitEngineering(t language.Tag) {
68 f.init(t, tagToScientific)
69 f.Pattern.MinFractionDigits = 0
70 f.Pattern.MaxFractionDigits = -1
71 f.Pattern.MaxIntegerDigits = 3
72 f.Pattern.MinIntegerDigits = 1
73 }
74
75
76
77 func (f *Formatter) InitPercent(t language.Tag) {
78 f.init(t, tagToPercent)
79 }
80
81
82
83 func (f *Formatter) InitPerMille(t language.Tag) {
84 f.init(t, tagToPercent)
85 f.Pattern.DigitShift = 3
86 }
87
88 func (f *Formatter) Append(dst []byte, x interface{}) []byte {
89 var d Decimal
90 r := f.RoundingContext
91 d.Convert(r, x)
92 return f.Render(dst, FormatDigits(&d, r))
93 }
94
95 func FormatDigits(d *Decimal, r RoundingContext) Digits {
96 if r.isScientific() {
97 return scientificVisibleDigits(r, d)
98 }
99 return decimalVisibleDigits(r, d)
100 }
101
102 func (f *Formatter) Format(dst []byte, d *Decimal) []byte {
103 return f.Render(dst, FormatDigits(d, f.RoundingContext))
104 }
105
106 func (f *Formatter) Render(dst []byte, d Digits) []byte {
107 var result []byte
108 var postPrefix, preSuffix int
109 if d.IsScientific {
110 result, postPrefix, preSuffix = appendScientific(dst, f, &d)
111 } else {
112 result, postPrefix, preSuffix = appendDecimal(dst, f, &d)
113 }
114 if f.PadRune == 0 {
115 return result
116 }
117 width := int(f.FormatWidth)
118 if count := utf8.RuneCount(result); count < width {
119 insertPos := 0
120 switch f.Flags & PadMask {
121 case PadAfterPrefix:
122 insertPos = postPrefix
123 case PadBeforeSuffix:
124 insertPos = preSuffix
125 case PadAfterSuffix:
126 insertPos = len(result)
127 }
128 num := width - count
129 pad := [utf8.UTFMax]byte{' '}
130 sz := 1
131 if r := f.PadRune; r != 0 {
132 sz = utf8.EncodeRune(pad[:], r)
133 }
134 extra := sz * num
135 if n := len(result) + extra; n < cap(result) {
136 result = result[:n]
137 copy(result[insertPos+extra:], result[insertPos:])
138 } else {
139 buf := make([]byte, n)
140 copy(buf, result[:insertPos])
141 copy(buf[insertPos+extra:], result[insertPos:])
142 result = buf
143 }
144 for ; num > 0; num-- {
145 insertPos += copy(result[insertPos:], pad[:sz])
146 }
147 }
148 return result
149 }
150
151
152
153 func decimalVisibleDigits(r RoundingContext, d *Decimal) Digits {
154 if d.NaN || d.Inf {
155 return Digits{digits: digits{Neg: d.Neg, NaN: d.NaN, Inf: d.Inf}}
156 }
157 n := Digits{digits: d.normalize().digits}
158
159 exp := n.Exp
160 exp += int32(r.DigitShift)
161
162
163 if r.MaxIntegerDigits > 0 {
164 if p := int(exp) - int(r.MaxIntegerDigits); p > 0 {
165 if p > len(n.Digits) {
166 p = len(n.Digits)
167 }
168 if n.Digits = n.Digits[p:]; len(n.Digits) == 0 {
169 exp = 0
170 } else {
171 exp -= int32(p)
172 }
173
174 for len(n.Digits) > 0 && n.Digits[0] == 0 {
175 n.Digits = n.Digits[1:]
176 exp--
177 }
178 }
179 }
180
181
182 p := len(n.Digits)
183 if maxSig := int(r.MaxSignificantDigits); maxSig > 0 {
184 p = maxSig
185 }
186 if maxFrac := int(r.MaxFractionDigits); maxFrac >= 0 {
187 if cap := int(exp) + maxFrac; cap < p {
188 p = int(exp) + maxFrac
189 }
190 if p < 0 {
191 p = 0
192 }
193 }
194 n.round(r.Mode, p)
195
196
197 n.End = int32(len(n.Digits))
198 if n.End == 0 {
199 exp = 0
200 if r.MinFractionDigits > 0 {
201 n.End = int32(r.MinFractionDigits)
202 }
203 if p := int32(r.MinSignificantDigits) - 1; p > n.End {
204 n.End = p
205 }
206 } else {
207 if end := exp + int32(r.MinFractionDigits); end > n.End {
208 n.End = end
209 }
210 if n.End < int32(r.MinSignificantDigits) {
211 n.End = int32(r.MinSignificantDigits)
212 }
213 }
214 n.Exp = exp
215 return n
216 }
217
218
219
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
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) {
234 intDigits = digits
235 } else {
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
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
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
298
299 if len(n.Digits) == 0 {
300 n.Digits = append(n.Digits, 0)
301 n.Exp = 1
302 }
303
304
305
306 maxInt, numInt := int(r.MaxIntegerDigits), int(r.MinIntegerDigits)
307 if numInt == 0 {
308 numInt = 1
309 }
310
311
312
313 if maxInt > numInt {
314
315 numInt = 1
316
317
318
319 d := int(n.Exp-1) % maxInt
320 if d < 0 {
321 d += maxInt
322 }
323 numInt += d
324 }
325
326 p := len(n.Digits)
327 if maxSig := int(r.MaxSignificantDigits); maxSig > 0 {
328 p = maxSig
329 }
330 if maxFrac := int(r.MaxFractionDigits); maxFrac >= 0 && numInt+maxFrac < p {
331 p = numInt + maxFrac
332 }
333 n.round(r.Mode, p)
334
335 n.Comma = uint8(numInt)
336 n.End = int32(len(n.Digits))
337 if minSig := int32(r.MinFractionDigits) + int32(numInt); n.End < minSig {
338 n.End = minSig
339 }
340 return n
341 }
342
343
344
345 func appendScientific(dst []byte, f *Formatter, n *Digits) (b []byte, postPre, preSuf int) {
346 if dst, ok := f.renderSpecial(dst, n); ok {
347 return dst, 0, 0
348 }
349 digits := n.Digits
350 numInt := int(n.Comma)
351 numFrac := int(n.End) - int(n.Comma)
352
353 var intDigits, fracDigits []byte
354 if numInt <= len(digits) {
355 intDigits = digits[:numInt]
356 fracDigits = digits[numInt:]
357 } else {
358 intDigits = digits
359 }
360 neg := n.Neg
361 affix, suffix := f.getAffixes(neg)
362 dst = appendAffix(dst, f, affix, neg)
363 savedLen := len(dst)
364
365 i := 0
366 for ; i < len(intDigits); i++ {
367 dst = f.AppendDigit(dst, intDigits[i])
368 if f.needsSep(numInt - i) {
369 dst = append(dst, f.Symbol(SymGroup)...)
370 }
371 }
372 for ; i < numInt; i++ {
373 dst = f.AppendDigit(dst, 0)
374 if f.needsSep(numInt - i) {
375 dst = append(dst, f.Symbol(SymGroup)...)
376 }
377 }
378
379 if numFrac > 0 || f.Flags&AlwaysDecimalSeparator != 0 {
380 dst = append(dst, f.Symbol(SymDecimal)...)
381 }
382 i = 0
383 for ; i < len(fracDigits); i++ {
384 dst = f.AppendDigit(dst, fracDigits[i])
385 }
386 for ; i < numFrac; i++ {
387 dst = f.AppendDigit(dst, 0)
388 }
389
390
391 buf := [12]byte{}
392
393
394 exp := n.Exp - int32(n.Comma)
395 exponential := f.Symbol(SymExponential)
396 if exponential == "E" {
397 dst = append(dst, "\u202f"...)
398 dst = append(dst, f.Symbol(SymSuperscriptingExponent)...)
399 dst = append(dst, "\u202f"...)
400 dst = f.AppendDigit(dst, 1)
401 dst = f.AppendDigit(dst, 0)
402 switch {
403 case exp < 0:
404 dst = append(dst, superMinus...)
405 exp = -exp
406 case f.Flags&AlwaysExpSign != 0:
407 dst = append(dst, superPlus...)
408 }
409 b = strconv.AppendUint(buf[:0], uint64(exp), 10)
410 for i := len(b); i < int(f.MinExponentDigits); i++ {
411 dst = append(dst, superDigits[0]...)
412 }
413 for _, c := range b {
414 dst = append(dst, superDigits[c-'0']...)
415 }
416 } else {
417 dst = append(dst, exponential...)
418 switch {
419 case exp < 0:
420 dst = append(dst, f.Symbol(SymMinusSign)...)
421 exp = -exp
422 case f.Flags&AlwaysExpSign != 0:
423 dst = append(dst, f.Symbol(SymPlusSign)...)
424 }
425 b = strconv.AppendUint(buf[:0], uint64(exp), 10)
426 for i := len(b); i < int(f.MinExponentDigits); i++ {
427 dst = f.AppendDigit(dst, 0)
428 }
429 for _, c := range b {
430 dst = f.AppendDigit(dst, c-'0')
431 }
432 }
433 return appendAffix(dst, f, suffix, neg), savedLen, len(dst)
434 }
435
436 const (
437 superMinus = "\u207B"
438 superPlus = "\u207A"
439 )
440
441 var (
442
443 superDigits = []string{
444 "\u2070",
445 "\u00B9",
446 "\u00B2",
447 "\u00B3",
448 "\u2074",
449 "\u2075",
450 "\u2076",
451 "\u2077",
452 "\u2078",
453 "\u2079",
454 }
455 )
456
457 func (f *Formatter) getAffixes(neg bool) (affix, suffix string) {
458 str := f.Affix
459 if str != "" {
460 if f.NegOffset > 0 {
461 if neg {
462 str = str[f.NegOffset:]
463 } else {
464 str = str[:f.NegOffset]
465 }
466 }
467 sufStart := 1 + str[0]
468 affix = str[1:sufStart]
469 suffix = str[sufStart+1:]
470 }
471
472
473 if f.NegOffset == 0 && (neg || f.Flags&AlwaysSign != 0) {
474 affix = "-" + affix
475 }
476 return affix, suffix
477 }
478
479 func (f *Formatter) renderSpecial(dst []byte, d *Digits) (b []byte, ok bool) {
480 if d.NaN {
481 return fmtNaN(dst, f), true
482 }
483 if d.Inf {
484 return fmtInfinite(dst, f, d), true
485 }
486 return dst, false
487 }
488
489 func fmtNaN(dst []byte, f *Formatter) []byte {
490 return append(dst, f.Symbol(SymNan)...)
491 }
492
493 func fmtInfinite(dst []byte, f *Formatter, d *Digits) []byte {
494 affix, suffix := f.getAffixes(d.Neg)
495 dst = appendAffix(dst, f, affix, d.Neg)
496 dst = append(dst, f.Symbol(SymInfinity)...)
497 dst = appendAffix(dst, f, suffix, d.Neg)
498 return dst
499 }
500
501 func appendAffix(dst []byte, f *Formatter, affix string, neg bool) []byte {
502 quoting := false
503 escaping := false
504 for _, r := range affix {
505 switch {
506 case escaping:
507
508 dst = append(dst, string(r)...)
509 escaping = false
510 case r == '\\':
511 escaping = true
512 case r == '\'':
513 quoting = !quoting
514 case quoting:
515 dst = append(dst, string(r)...)
516 case r == '%':
517 if f.DigitShift == 3 {
518 dst = append(dst, f.Symbol(SymPerMille)...)
519 } else {
520 dst = append(dst, f.Symbol(SymPercentSign)...)
521 }
522 case r == '-' || r == '+':
523 if neg {
524 dst = append(dst, f.Symbol(SymMinusSign)...)
525 } else if f.Flags&ElideSign == 0 {
526 dst = append(dst, f.Symbol(SymPlusSign)...)
527 } else {
528 dst = append(dst, ' ')
529 }
530 default:
531 dst = append(dst, string(r)...)
532 }
533 }
534 return dst
535 }
536
View as plain text