blob: 8a3d8b6fb43c25b814f25d221ce4e78381925289 [file] [log] [blame]
Zack Williamse940c7a2019-08-21 14:25:39 -07001package jsoniter
2
3import (
4 "encoding/json"
5 "io"
6 "math/big"
7 "strconv"
8 "strings"
9 "unsafe"
10)
11
12var floatDigits []int8
13
14const invalidCharForNumber = int8(-1)
15const endOfNumber = int8(-2)
16const dotInNumber = int8(-3)
17
18func init() {
19 floatDigits = make([]int8, 256)
20 for i := 0; i < len(floatDigits); i++ {
21 floatDigits[i] = invalidCharForNumber
22 }
23 for i := int8('0'); i <= int8('9'); i++ {
24 floatDigits[i] = i - int8('0')
25 }
26 floatDigits[','] = endOfNumber
27 floatDigits[']'] = endOfNumber
28 floatDigits['}'] = endOfNumber
29 floatDigits[' '] = endOfNumber
30 floatDigits['\t'] = endOfNumber
31 floatDigits['\n'] = endOfNumber
32 floatDigits['.'] = dotInNumber
33}
34
35// ReadBigFloat read big.Float
36func (iter *Iterator) ReadBigFloat() (ret *big.Float) {
37 str := iter.readNumberAsString()
38 if iter.Error != nil && iter.Error != io.EOF {
39 return nil
40 }
41 prec := 64
42 if len(str) > prec {
43 prec = len(str)
44 }
45 val, _, err := big.ParseFloat(str, 10, uint(prec), big.ToZero)
46 if err != nil {
47 iter.Error = err
48 return nil
49 }
50 return val
51}
52
53// ReadBigInt read big.Int
54func (iter *Iterator) ReadBigInt() (ret *big.Int) {
55 str := iter.readNumberAsString()
56 if iter.Error != nil && iter.Error != io.EOF {
57 return nil
58 }
59 ret = big.NewInt(0)
60 var success bool
61 ret, success = ret.SetString(str, 10)
62 if !success {
63 iter.ReportError("ReadBigInt", "invalid big int")
64 return nil
65 }
66 return ret
67}
68
69//ReadFloat32 read float32
70func (iter *Iterator) ReadFloat32() (ret float32) {
71 c := iter.nextToken()
72 if c == '-' {
73 return -iter.readPositiveFloat32()
74 }
75 iter.unreadByte()
76 return iter.readPositiveFloat32()
77}
78
79func (iter *Iterator) readPositiveFloat32() (ret float32) {
80 i := iter.head
81 // first char
82 if i == iter.tail {
83 return iter.readFloat32SlowPath()
84 }
85 c := iter.buf[i]
86 i++
87 ind := floatDigits[c]
88 switch ind {
89 case invalidCharForNumber:
90 return iter.readFloat32SlowPath()
91 case endOfNumber:
92 iter.ReportError("readFloat32", "empty number")
93 return
94 case dotInNumber:
95 iter.ReportError("readFloat32", "leading dot is invalid")
96 return
97 case 0:
98 if i == iter.tail {
99 return iter.readFloat32SlowPath()
100 }
101 c = iter.buf[i]
102 switch c {
103 case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
104 iter.ReportError("readFloat32", "leading zero is invalid")
105 return
106 }
107 }
108 value := uint64(ind)
109 // chars before dot
110non_decimal_loop:
111 for ; i < iter.tail; i++ {
112 c = iter.buf[i]
113 ind := floatDigits[c]
114 switch ind {
115 case invalidCharForNumber:
116 return iter.readFloat32SlowPath()
117 case endOfNumber:
118 iter.head = i
119 return float32(value)
120 case dotInNumber:
121 break non_decimal_loop
122 }
123 if value > uint64SafeToMultiple10 {
124 return iter.readFloat32SlowPath()
125 }
126 value = (value << 3) + (value << 1) + uint64(ind) // value = value * 10 + ind;
127 }
128 // chars after dot
129 if c == '.' {
130 i++
131 decimalPlaces := 0
132 if i == iter.tail {
133 return iter.readFloat32SlowPath()
134 }
135 for ; i < iter.tail; i++ {
136 c = iter.buf[i]
137 ind := floatDigits[c]
138 switch ind {
139 case endOfNumber:
140 if decimalPlaces > 0 && decimalPlaces < len(pow10) {
141 iter.head = i
142 return float32(float64(value) / float64(pow10[decimalPlaces]))
143 }
144 // too many decimal places
145 return iter.readFloat32SlowPath()
146 case invalidCharForNumber, dotInNumber:
147 return iter.readFloat32SlowPath()
148 }
149 decimalPlaces++
150 if value > uint64SafeToMultiple10 {
151 return iter.readFloat32SlowPath()
152 }
153 value = (value << 3) + (value << 1) + uint64(ind)
154 }
155 }
156 return iter.readFloat32SlowPath()
157}
158
159func (iter *Iterator) readNumberAsString() (ret string) {
160 strBuf := [16]byte{}
161 str := strBuf[0:0]
162load_loop:
163 for {
164 for i := iter.head; i < iter.tail; i++ {
165 c := iter.buf[i]
166 switch c {
167 case '+', '-', '.', 'e', 'E', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
168 str = append(str, c)
169 continue
170 default:
171 iter.head = i
172 break load_loop
173 }
174 }
175 if !iter.loadMore() {
176 break
177 }
178 }
179 if iter.Error != nil && iter.Error != io.EOF {
180 return
181 }
182 if len(str) == 0 {
183 iter.ReportError("readNumberAsString", "invalid number")
184 }
185 return *(*string)(unsafe.Pointer(&str))
186}
187
188func (iter *Iterator) readFloat32SlowPath() (ret float32) {
189 str := iter.readNumberAsString()
190 if iter.Error != nil && iter.Error != io.EOF {
191 return
192 }
193 errMsg := validateFloat(str)
194 if errMsg != "" {
195 iter.ReportError("readFloat32SlowPath", errMsg)
196 return
197 }
198 val, err := strconv.ParseFloat(str, 32)
199 if err != nil {
200 iter.Error = err
201 return
202 }
203 return float32(val)
204}
205
206// ReadFloat64 read float64
207func (iter *Iterator) ReadFloat64() (ret float64) {
208 c := iter.nextToken()
209 if c == '-' {
210 return -iter.readPositiveFloat64()
211 }
212 iter.unreadByte()
213 return iter.readPositiveFloat64()
214}
215
216func (iter *Iterator) readPositiveFloat64() (ret float64) {
217 i := iter.head
218 // first char
219 if i == iter.tail {
220 return iter.readFloat64SlowPath()
221 }
222 c := iter.buf[i]
223 i++
224 ind := floatDigits[c]
225 switch ind {
226 case invalidCharForNumber:
227 return iter.readFloat64SlowPath()
228 case endOfNumber:
229 iter.ReportError("readFloat64", "empty number")
230 return
231 case dotInNumber:
232 iter.ReportError("readFloat64", "leading dot is invalid")
233 return
234 case 0:
235 if i == iter.tail {
236 return iter.readFloat64SlowPath()
237 }
238 c = iter.buf[i]
239 switch c {
240 case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
241 iter.ReportError("readFloat64", "leading zero is invalid")
242 return
243 }
244 }
245 value := uint64(ind)
246 // chars before dot
247non_decimal_loop:
248 for ; i < iter.tail; i++ {
249 c = iter.buf[i]
250 ind := floatDigits[c]
251 switch ind {
252 case invalidCharForNumber:
253 return iter.readFloat64SlowPath()
254 case endOfNumber:
255 iter.head = i
256 return float64(value)
257 case dotInNumber:
258 break non_decimal_loop
259 }
260 if value > uint64SafeToMultiple10 {
261 return iter.readFloat64SlowPath()
262 }
263 value = (value << 3) + (value << 1) + uint64(ind) // value = value * 10 + ind;
264 }
265 // chars after dot
266 if c == '.' {
267 i++
268 decimalPlaces := 0
269 if i == iter.tail {
270 return iter.readFloat64SlowPath()
271 }
272 for ; i < iter.tail; i++ {
273 c = iter.buf[i]
274 ind := floatDigits[c]
275 switch ind {
276 case endOfNumber:
277 if decimalPlaces > 0 && decimalPlaces < len(pow10) {
278 iter.head = i
279 return float64(value) / float64(pow10[decimalPlaces])
280 }
281 // too many decimal places
282 return iter.readFloat64SlowPath()
283 case invalidCharForNumber, dotInNumber:
284 return iter.readFloat64SlowPath()
285 }
286 decimalPlaces++
287 if value > uint64SafeToMultiple10 {
288 return iter.readFloat64SlowPath()
289 }
290 value = (value << 3) + (value << 1) + uint64(ind)
David K. Bainbridgebd6b2882021-08-26 13:31:02 +0000291 if value > maxFloat64 {
292 return iter.readFloat64SlowPath()
293 }
Zack Williamse940c7a2019-08-21 14:25:39 -0700294 }
295 }
296 return iter.readFloat64SlowPath()
297}
298
299func (iter *Iterator) readFloat64SlowPath() (ret float64) {
300 str := iter.readNumberAsString()
301 if iter.Error != nil && iter.Error != io.EOF {
302 return
303 }
304 errMsg := validateFloat(str)
305 if errMsg != "" {
306 iter.ReportError("readFloat64SlowPath", errMsg)
307 return
308 }
309 val, err := strconv.ParseFloat(str, 64)
310 if err != nil {
311 iter.Error = err
312 return
313 }
314 return val
315}
316
317func validateFloat(str string) string {
318 // strconv.ParseFloat is not validating `1.` or `1.e1`
319 if len(str) == 0 {
320 return "empty number"
321 }
322 if str[0] == '-' {
323 return "-- is not valid"
324 }
325 dotPos := strings.IndexByte(str, '.')
326 if dotPos != -1 {
327 if dotPos == len(str)-1 {
328 return "dot can not be last character"
329 }
330 switch str[dotPos+1] {
331 case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
332 default:
333 return "missing digit after dot"
334 }
335 }
336 return ""
337}
338
339// ReadNumber read json.Number
340func (iter *Iterator) ReadNumber() (ret json.Number) {
341 return json.Number(iter.readNumberAsString())
342}