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