1 package ftoa
2
3 import (
4 "math"
5 "strconv"
6
7 "github.com/dop251/goja/ftoa/internal/fast"
8 )
9
10 type FToStrMode int
11
12 const (
13
14 ModeStandard FToStrMode = iota
15
16 ModeStandardExponential
17
18 ModeFixed
19
20 ModeExponential
21
22 ModePrecision
23 )
24
25 func insert(b []byte, p int, c byte) []byte {
26 b = append(b, 0)
27 copy(b[p+1:], b[p:])
28 b[p] = c
29 return b
30 }
31
32 func expand(b []byte, delta int) []byte {
33 newLen := len(b) + delta
34 if newLen <= cap(b) {
35 return b[:newLen]
36 }
37 b1 := make([]byte, newLen)
38 copy(b1, b)
39 return b1
40 }
41
42 func FToStr(d float64, mode FToStrMode, precision int, buffer []byte) []byte {
43 if math.IsNaN(d) {
44 buffer = append(buffer, "NaN"...)
45 return buffer
46 }
47 if math.IsInf(d, 0) {
48 if math.Signbit(d) {
49 buffer = append(buffer, '-')
50 }
51 buffer = append(buffer, "Infinity"...)
52 return buffer
53 }
54
55 if mode == ModeFixed && (d >= 1e21 || d <= -1e21) {
56 mode = ModeStandard
57 }
58
59 var decPt int
60 var ok bool
61 startPos := len(buffer)
62
63 if d != 0 {
64 if d < 0 {
65 buffer = append(buffer, '-')
66 d = -d
67 startPos++
68 }
69 switch mode {
70 case ModeStandard, ModeStandardExponential:
71 buffer, decPt, ok = fast.Dtoa(d, fast.ModeShortest, 0, buffer)
72 case ModeExponential, ModePrecision:
73 buffer, decPt, ok = fast.Dtoa(d, fast.ModePrecision, precision, buffer)
74 }
75 } else {
76 buffer = append(buffer, '0')
77 decPt, ok = 1, true
78 }
79 if !ok {
80 buffer, decPt = ftoa(d, dtoaModes[mode], mode >= ModeFixed, precision, buffer)
81 }
82 exponentialNotation := false
83 minNDigits := 0
84 nDigits := len(buffer) - startPos
85
86 switch mode {
87 case ModeStandard:
88 if decPt < -5 || decPt > 21 {
89 exponentialNotation = true
90 } else {
91 minNDigits = decPt
92 }
93 case ModeFixed:
94 if precision >= 0 {
95 minNDigits = decPt + precision
96 } else {
97 minNDigits = decPt
98 }
99 case ModeExponential:
100
101 minNDigits = precision
102 fallthrough
103 case ModeStandardExponential:
104 exponentialNotation = true
105 case ModePrecision:
106
107 minNDigits = precision
108 if decPt < -5 || decPt > precision {
109 exponentialNotation = true
110 }
111 }
112
113 for nDigits < minNDigits {
114 buffer = append(buffer, '0')
115 nDigits++
116 }
117
118 if exponentialNotation {
119
120 if nDigits != 1 {
121 buffer = insert(buffer, startPos+1, '.')
122 }
123 buffer = append(buffer, 'e')
124 if decPt-1 >= 0 {
125 buffer = append(buffer, '+')
126 }
127 buffer = strconv.AppendInt(buffer, int64(decPt-1), 10)
128 } else if decPt != nDigits {
129
130
131 if decPt > 0 {
132
133 buffer = insert(buffer, startPos+decPt, '.')
134 } else {
135
136 buffer = expand(buffer, 2-decPt)
137 copy(buffer[startPos+2-decPt:], buffer[startPos:])
138 buffer[startPos] = '0'
139 buffer[startPos+1] = '.'
140 for i := startPos + 2; i < startPos+2-decPt; i++ {
141 buffer[i] = '0'
142 }
143 }
144 }
145
146 return buffer
147 }
148
View as plain text