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