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  }