iter_float.go raw

   1  package jsoniter
   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 invalidCharForNumber = int8(-1)
  15  const endOfNumber = int8(-2)
  16  const dotInNumber = int8(-3)
  17  
  18  func 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
  36  func (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
  54  func (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
  70  func (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  
  79  func (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
 110  non_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  
 159  func (iter *Iterator) readNumberAsString() (ret string) {
 160  	strBuf := [16]byte{}
 161  	str := strBuf[0:0]
 162  load_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  
 188  func (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
 207  func (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  
 216  func (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
 247  non_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)
 291  			if value > maxFloat64 {
 292  				return iter.readFloat64SlowPath()
 293  			}
 294  		}
 295  	}
 296  	return iter.readFloat64SlowPath()
 297  }
 298  
 299  func (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  
 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  	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
 340  func (iter *Iterator) ReadNumber() (ret json.Number) {
 341  	return json.Number(iter.readNumberAsString())
 342  }
 343