1
1
package fastfloat
2
2
3
3
import (
4
+ "fmt"
4
5
"math"
5
6
"strconv"
6
7
"strings"
@@ -11,6 +12,7 @@ import (
11
12
// It is equivalent to strconv.ParseUint(s, 10, 64), but is faster.
12
13
//
13
14
// 0 is returned if the number cannot be parsed.
15
+ // See also ParseUint64, which returns parse error if the number cannot be parsed.
14
16
func ParseUint64BestEffort (s string ) uint64 {
15
17
if len (s ) == 0 {
16
18
return 0
@@ -45,11 +47,51 @@ func ParseUint64BestEffort(s string) uint64 {
45
47
return d
46
48
}
47
49
50
+ // ParseUint64 parses uint64 from s.
51
+ //
52
+ // It is equivalent to strconv.ParseUint(s, 10, 64), but is faster.
53
+ //
54
+ // See also ParseUint64BestEffort.
55
+ func ParseUint64 (s string ) (uint64 , error ) {
56
+ if len (s ) == 0 {
57
+ return 0 , fmt .Errorf ("cannot parse uint64 from empty string" )
58
+ }
59
+ i := uint (0 )
60
+ d := uint64 (0 )
61
+ j := i
62
+ for i < uint (len (s )) {
63
+ if s [i ] >= '0' && s [i ] <= '9' {
64
+ d = d * 10 + uint64 (s [i ]- '0' )
65
+ i ++
66
+ if i > 18 {
67
+ // The integer part may be out of range for uint64.
68
+ // Fall back to slow parsing.
69
+ dd , err := strconv .ParseUint (s , 10 , 64 )
70
+ if err != nil {
71
+ return 0 , err
72
+ }
73
+ return dd , nil
74
+ }
75
+ continue
76
+ }
77
+ break
78
+ }
79
+ if i <= j {
80
+ return 0 , fmt .Errorf ("cannot parse uint64 from %q" , s )
81
+ }
82
+ if i < uint (len (s )) {
83
+ // Unparsed tail left.
84
+ return 0 , fmt .Errorf ("unparsed tail left after parsing uint64 from %q: %q" , s , s [i :])
85
+ }
86
+ return d , nil
87
+ }
88
+
48
89
// ParseInt64BestEffort parses int64 number s.
49
90
//
50
91
// It is equivalent to strconv.ParseInt(s, 10, 64), but is faster.
51
92
//
52
93
// 0 is returned if the number cannot be parsed.
94
+ // See also ParseInt64, which returns parse error if the number cannot be parsed.
53
95
func ParseInt64BestEffort (s string ) int64 {
54
96
if len (s ) == 0 {
55
97
return 0
@@ -95,6 +137,56 @@ func ParseInt64BestEffort(s string) int64 {
95
137
return d
96
138
}
97
139
140
+ // ParseInt64 parses int64 number s.
141
+ //
142
+ // It is equivalent to strconv.ParseInt(s, 10, 64), but is faster.
143
+ //
144
+ // See also ParseInt64BestEffort.
145
+ func ParseInt64 (s string ) (int64 , error ) {
146
+ if len (s ) == 0 {
147
+ return 0 , fmt .Errorf ("cannot parse int64 from empty string" )
148
+ }
149
+ i := uint (0 )
150
+ minus := s [0 ] == '-'
151
+ if minus {
152
+ i ++
153
+ if i >= uint (len (s )) {
154
+ return 0 , fmt .Errorf ("cannot parse int64 from %q" , s )
155
+ }
156
+ }
157
+
158
+ d := int64 (0 )
159
+ j := i
160
+ for i < uint (len (s )) {
161
+ if s [i ] >= '0' && s [i ] <= '9' {
162
+ d = d * 10 + int64 (s [i ]- '0' )
163
+ i ++
164
+ if i > 18 {
165
+ // The integer part may be out of range for int64.
166
+ // Fall back to slow parsing.
167
+ dd , err := strconv .ParseInt (s , 10 , 64 )
168
+ if err != nil {
169
+ return 0 , err
170
+ }
171
+ return dd , nil
172
+ }
173
+ continue
174
+ }
175
+ break
176
+ }
177
+ if i <= j {
178
+ return 0 , fmt .Errorf ("cannot parse int64 from %q" , s )
179
+ }
180
+ if i < uint (len (s )) {
181
+ // Unparsed tail left.
182
+ return 0 , fmt .Errorf ("unparsed tail left after parsing int64 form %q: %q" , s , s [i :])
183
+ }
184
+ if minus {
185
+ d = - d
186
+ }
187
+ return d , nil
188
+ }
189
+
98
190
// Exact powers of 10.
99
191
//
100
192
// This works faster than math.Pow10, since it avoids additional multiplication.
@@ -107,6 +199,7 @@ var float64pow10 = [...]float64{
107
199
// It is equivalent to strconv.ParseFloat(s, 64), but is faster.
108
200
//
109
201
// 0 is returned if the number cannot be parsed.
202
+ // See also Parse, which returns parse error if the number cannot be parsed.
110
203
func ParseBestEffort (s string ) float64 {
111
204
if len (s ) == 0 {
112
205
return 0
@@ -250,5 +343,153 @@ func ParseBestEffort(s string) float64 {
250
343
return 0
251
344
}
252
345
346
+ // Parse parses floating-point number s.
347
+ //
348
+ // It is equivalent to strconv.ParseFloat(s, 64), but is faster.
349
+ //
350
+ // See also ParseBestEffort.
351
+ func Parse (s string ) (float64 , error ) {
352
+ if len (s ) == 0 {
353
+ return 0 , fmt .Errorf ("cannot parse float64 from empty string" )
354
+ }
355
+ i := uint (0 )
356
+ minus := s [0 ] == '-'
357
+ if minus {
358
+ i ++
359
+ if i >= uint (len (s )) {
360
+ return 0 , fmt .Errorf ("cannot parse float64 from %q" , s )
361
+ }
362
+ }
363
+
364
+ d := uint64 (0 )
365
+ j := i
366
+ for i < uint (len (s )) {
367
+ if s [i ] >= '0' && s [i ] <= '9' {
368
+ d = d * 10 + uint64 (s [i ]- '0' )
369
+ i ++
370
+ if i > 18 {
371
+ // The integer part may be out of range for uint64.
372
+ // Fall back to slow parsing.
373
+ f , err := strconv .ParseFloat (s , 64 )
374
+ if err != nil && ! math .IsInf (f , 0 ) {
375
+ return 0 , err
376
+ }
377
+ return f , nil
378
+ }
379
+ continue
380
+ }
381
+ break
382
+ }
383
+ if i <= j {
384
+ ss := s [i :]
385
+ if strings .HasPrefix (ss , "+" ) {
386
+ ss = ss [1 :]
387
+ }
388
+ if strings .EqualFold (ss , "inf" ) {
389
+ if minus {
390
+ return - inf , nil
391
+ }
392
+ return inf , nil
393
+ }
394
+ if strings .EqualFold (ss , "nan" ) {
395
+ return nan , nil
396
+ }
397
+ return 0 , fmt .Errorf ("unparsed tail left after parsing float64 from %q: %q" , s , ss )
398
+ }
399
+ f := float64 (d )
400
+ if i >= uint (len (s )) {
401
+ // Fast path - just integer.
402
+ if minus {
403
+ f = - f
404
+ }
405
+ return f , nil
406
+ }
407
+
408
+ if s [i ] == '.' {
409
+ // Parse fractional part.
410
+ i ++
411
+ if i >= uint (len (s )) {
412
+ return 0 , fmt .Errorf ("cannot parse fractional part in %q" , s )
413
+ }
414
+ k := i
415
+ for i < uint (len (s )) {
416
+ if s [i ] >= '0' && s [i ] <= '9' {
417
+ d = d * 10 + uint64 (s [i ]- '0' )
418
+ i ++
419
+ if i - j >= uint (len (float64pow10 )) {
420
+ // The mantissa is out of range. Fall back to standard parsing.
421
+ f , err := strconv .ParseFloat (s , 64 )
422
+ if err != nil && ! math .IsInf (f , 0 ) {
423
+ return 0 , fmt .Errorf ("cannot parse mantissa in %q: %s" , s , err )
424
+ }
425
+ return f , nil
426
+ }
427
+ continue
428
+ }
429
+ break
430
+ }
431
+ if i < k {
432
+ return 0 , fmt .Errorf ("cannot find mantissa in %q" , s )
433
+ }
434
+ // Convert the entire mantissa to a float at once to avoid rounding errors.
435
+ f = float64 (d ) / float64pow10 [i - k ]
436
+ if i >= uint (len (s )) {
437
+ // Fast path - parsed fractional number.
438
+ if minus {
439
+ f = - f
440
+ }
441
+ return f , nil
442
+ }
443
+ }
444
+ if s [i ] == 'e' || s [i ] == 'E' {
445
+ // Parse exponent part.
446
+ i ++
447
+ if i >= uint (len (s )) {
448
+ return 0 , fmt .Errorf ("cannot parse exponent in %q" , s )
449
+ }
450
+ expMinus := false
451
+ if s [i ] == '+' || s [i ] == '-' {
452
+ expMinus = s [i ] == '-'
453
+ i ++
454
+ if i >= uint (len (s )) {
455
+ return 0 , fmt .Errorf ("cannot parse exponent in %q" , s )
456
+ }
457
+ }
458
+ exp := int16 (0 )
459
+ j := i
460
+ for i < uint (len (s )) {
461
+ if s [i ] >= '0' && s [i ] <= '9' {
462
+ exp = exp * 10 + int16 (s [i ]- '0' )
463
+ i ++
464
+ if exp > 300 {
465
+ // The exponent may be too big for float64.
466
+ // Fall back to standard parsing.
467
+ f , err := strconv .ParseFloat (s , 64 )
468
+ if err != nil && ! math .IsInf (f , 0 ) {
469
+ return 0 , fmt .Errorf ("cannot parse exponent in %q: %s" , s , err )
470
+ }
471
+ return f , nil
472
+ }
473
+ continue
474
+ }
475
+ break
476
+ }
477
+ if i <= j {
478
+ return 0 , fmt .Errorf ("cannot parse exponent in %q" , s )
479
+ }
480
+ if expMinus {
481
+ exp = - exp
482
+ }
483
+ f *= math .Pow10 (int (exp ))
484
+ if i >= uint (len (s )) {
485
+ if minus {
486
+ f = - f
487
+ }
488
+ return f , nil
489
+ }
490
+ }
491
+ return 0 , fmt .Errorf ("cannot parse float64 from %q" , s )
492
+ }
493
+
253
494
var inf = math .Inf (1 )
254
495
var nan = math .NaN ()
0 commit comments