gitee.com/quant1x/gox@v1.7.6/fastjson/fastfloat.go (about)

     1  package fastjson
     2  
     3  import (
     4  	"math"
     5  	"strconv"
     6  )
     7  
     8  // ParseUint64BestEffort parses uint64 number s.
     9  //
    10  // It is equivalent to strconv.ParseUint(s, 10, 64), but is faster.
    11  //
    12  // 0 is returned if the number cannot be parsed.
    13  func ParseUint64BestEffort(s string) uint64 {
    14  	if len(s) == 0 {
    15  		return 0
    16  	}
    17  	i := uint(0)
    18  	d := uint64(0)
    19  	j := i
    20  	for i < uint(len(s)) {
    21  		if s[i] >= '0' && s[i] <= '9' {
    22  			d = d*10 + uint64(s[i]-'0')
    23  			i++
    24  			if i > 18 {
    25  				// The integer part may be out of range for uint64.
    26  				// Fall back to slow parsing.
    27  				dd, err := strconv.ParseUint(s, 10, 64)
    28  				if err != nil {
    29  					return 0
    30  				}
    31  				return dd
    32  			}
    33  			continue
    34  		}
    35  		break
    36  	}
    37  	if i <= j {
    38  		return 0
    39  	}
    40  	if i < uint(len(s)) {
    41  		// Unparsed tail left.
    42  		return 0
    43  	}
    44  	return d
    45  }
    46  
    47  // ParseInt64BestEffort parses int64 number s.
    48  //
    49  // It is equivalent to strconv.ParseInt(s, 10, 64), but is faster.
    50  //
    51  // 0 is returned if the number cannot be parsed.
    52  func ParseInt64BestEffort(s string) int64 {
    53  	if len(s) == 0 {
    54  		return 0
    55  	}
    56  	i := uint(0)
    57  	minus := s[0] == '-'
    58  	if minus {
    59  		i++
    60  		if i >= uint(len(s)) {
    61  			return 0
    62  		}
    63  	}
    64  
    65  	d := int64(0)
    66  	j := i
    67  	for i < uint(len(s)) {
    68  		if s[i] >= '0' && s[i] <= '9' {
    69  			d = d*10 + int64(s[i]-'0')
    70  			i++
    71  			if i > 18 {
    72  				// The integer part may be out of range for int64.
    73  				// Fall back to slow parsing.
    74  				dd, err := strconv.ParseInt(s, 10, 64)
    75  				if err != nil {
    76  					return 0
    77  				}
    78  				return dd
    79  			}
    80  			continue
    81  		}
    82  		break
    83  	}
    84  	if i <= j {
    85  		return 0
    86  	}
    87  	if i < uint(len(s)) {
    88  		// Unparsed tail left.
    89  		return 0
    90  	}
    91  	if minus {
    92  		d = -d
    93  	}
    94  	return d
    95  }
    96  
    97  // ParseBestEffort parses floating-point number s.
    98  //
    99  // It is equivalent to strconv.ParseFloat(s, 64), but is faster.
   100  //
   101  // 0 is returned if the number cannot be parsed.
   102  func ParseBestEffort(s string) float64 {
   103  	if len(s) == 0 {
   104  		return 0
   105  	}
   106  	i := uint(0)
   107  	minus := s[0] == '-'
   108  	if minus {
   109  		i++
   110  		if i >= uint(len(s)) {
   111  			return 0
   112  		}
   113  	}
   114  
   115  	d := uint64(0)
   116  	j := i
   117  	for i < uint(len(s)) {
   118  		if s[i] >= '0' && s[i] <= '9' {
   119  			d = d*10 + uint64(s[i]-'0')
   120  			i++
   121  			if i > 18 {
   122  				// The integer part may be out of range for uint64.
   123  				// Fall back to slow parsing.
   124  				f, err := strconv.ParseFloat(s, 64)
   125  				if err != nil && !math.IsInf(f, 0) {
   126  					return 0
   127  				}
   128  				return f
   129  			}
   130  			continue
   131  		}
   132  		break
   133  	}
   134  	if i <= j {
   135  		return 0
   136  	}
   137  	f := float64(d)
   138  	if i >= uint(len(s)) {
   139  		// Fast path - just integer.
   140  		if minus {
   141  			f = -f
   142  		}
   143  		return f
   144  	}
   145  
   146  	if s[i] == '.' {
   147  		// Parse fractional part.
   148  		i++
   149  		if i >= uint(len(s)) {
   150  			return 0
   151  		}
   152  		fr := uint64(0)
   153  		j := i
   154  		for i < uint(len(s)) {
   155  			if s[i] >= '0' && s[i] <= '9' {
   156  				fr = fr*10 + uint64(s[i]-'0')
   157  				i++
   158  				if i-j > 18 {
   159  					// The fractional part may be out of range for uint64.
   160  					// Fall back to standard parsing.
   161  					f, err := strconv.ParseFloat(s, 64)
   162  					if err != nil && !math.IsInf(f, 0) {
   163  						return 0
   164  					}
   165  					return f
   166  				}
   167  				continue
   168  			}
   169  			break
   170  		}
   171  		if i <= j {
   172  			return 0
   173  		}
   174  		f += float64(fr) / math.Pow10(int(i-j))
   175  		if i >= uint(len(s)) {
   176  			// Fast path - parsed fractional number.
   177  			if minus {
   178  				f = -f
   179  			}
   180  			return f
   181  		}
   182  	}
   183  	if s[i] == 'e' || s[i] == 'E' {
   184  		// Parse exponent part.
   185  		i++
   186  		if i >= uint(len(s)) {
   187  			return 0
   188  		}
   189  		expMinus := false
   190  		if s[i] == '+' || s[i] == '-' {
   191  			expMinus = s[i] == '-'
   192  			i++
   193  			if i >= uint(len(s)) {
   194  				return 0
   195  			}
   196  		}
   197  		exp := int16(0)
   198  		j := i
   199  		for i < uint(len(s)) {
   200  			if s[i] >= '0' && s[i] <= '9' {
   201  				exp = exp*10 + int16(s[i]-'0')
   202  				i++
   203  				if exp > 300 {
   204  					// The exponent may be too big for float64.
   205  					// Fall back to standard parsing.
   206  					f, err := strconv.ParseFloat(s, 64)
   207  					if err != nil && !math.IsInf(f, 0) {
   208  						return 0
   209  					}
   210  					return f
   211  				}
   212  				continue
   213  			}
   214  			break
   215  		}
   216  		if i <= j {
   217  			return 0
   218  		}
   219  		if expMinus {
   220  			exp = -exp
   221  		}
   222  		f *= math.Pow10(int(exp))
   223  		if i >= uint(len(s)) {
   224  			if minus {
   225  				f = -f
   226  			}
   227  			return f
   228  		}
   229  	}
   230  	return 0
   231  }