Explorar el Código

codec: add decReader.readn1eof and optimize jsonParseInteger

jsonParseInteger now has an ok bool to quickly check if all good
Ugorji Nwoke hace 6 años
padre
commit
3b8306a2a0
Se han modificado 4 ficheros con 84 adiciones y 26 borrados
  1. 4 4
      codec/decode.go
  2. 4 2
      codec/float.go
  3. 19 13
      codec/json.go
  4. 57 7
      codec/reader.go

+ 4 - 4
codec/decode.go

@@ -1723,13 +1723,13 @@ func (d *Decoder) nextValueBytes() (bs []byte) {
 	return
 }
 
-func (d *Decoder) rawBytes() []byte {
+func (d *Decoder) rawBytes() (v []byte) {
 	// ensure that this is not a view into the bytes
 	// i.e. make new copy always.
 	bs := d.nextValueBytes()
-	bs2 := make([]byte, len(bs))
-	copy(bs2, bs)
-	return bs2
+	v = make([]byte, len(bs))
+	copy(v, bs)
+	return
 }
 
 func (d *Decoder) wrapErr(v interface{}, err *error) {

+ 4 - 2
codec/float.go

@@ -24,12 +24,14 @@ func parseFloat64(b []byte) (f float64, err error) {
 }
 
 func parseFloat32_strconv(b []byte) (f float32, err error) {
+	// defer func() { xdebugf("strconv float32: %s, %v, err: %v", b, f, err) }()
 	f64, err := strconv.ParseFloat(stringView(b), 32)
 	f = float32(f64)
 	return
 }
 
 func parseFloat64_strconv(b []byte) (f float64, err error) {
+	// defer func() { xdebugf("strconv float64: %s, %v, err: %v", b, f, err) }()
 	return strconv.ParseFloat(stringView(b), 64)
 }
 
@@ -63,8 +65,8 @@ func parseFloat64_strconv(b []byte) (f float64, err error) {
 // 2^52 =      4503 5996 2737 0496 (between 10^15 and 10^16) (significand bits of uint64)
 // 2^64 = 1844 6744 0737 0955 1616 (between 10^19 and 10^20) (full uint64)
 //
-// Since we only allow for up to what can comfortably fit into the significand
-// ignoring the exponent, and we only try to parse iff significand fits into the
+// Note: we only allow for up to what can comfortably fit into the significand
+// ignoring the exponent, and we only try to parse iff significand fits.
 
 // Exact powers of 10.
 var float64pow10 = [...]float64{

+ 19 - 13
codec/json.go

@@ -709,14 +709,16 @@ func (d *jsonDecDriver) DecodeUint64() (u uint64) {
 	if len(bs) == 0 {
 		return
 	}
-	n, neg, badsyntax, overflow := jsonParseInteger(bs)
-	if overflow {
-		d.d.errorf("overflow parsing unsigned integer: %s", bs)
-	} else if neg {
-		d.d.errorf("minus found parsing unsigned integer: %s", bs)
+	n, neg, badsyntax, overflow, ok := jsonParseInteger(bs)
+	if ok {
+		if neg {
+			d.d.errorf("minus found parsing unsigned integer: %s", bs)
+		}
 	} else if badsyntax {
 		// fallback: try to decode as float, and cast
 		n = d.decUint64ViaFloat(bs)
+	} else if overflow {
+		d.d.errorf("overflow parsing unsigned integer: %s", bs)
 	}
 	return n
 }
@@ -727,9 +729,8 @@ func (d *jsonDecDriver) DecodeInt64() (i int64) {
 	if len(bs) == 0 {
 		return
 	}
-	n, neg, badsyntax, overflow := jsonParseInteger(bs)
-	if overflow {
-		d.d.errorf("overflow parsing integer: %s", bs)
+	n, neg, badsyntax, overflow, ok := jsonParseInteger(bs)
+	if ok {
 	} else if badsyntax {
 		// d.d.errorf("invalid syntax for integer: %s", bs)
 		// fallback: try to decode as float, and cast
@@ -738,6 +739,8 @@ func (d *jsonDecDriver) DecodeInt64() (i int64) {
 		} else {
 			n = d.decUint64ViaFloat(bs)
 		}
+	} else if overflow {
+		d.d.errorf("overflow parsing integer: %s", bs)
 	}
 	if neg {
 		if n > cutoff {
@@ -1058,7 +1061,7 @@ func (d *jsonDecDriver) nakedNum(z *decNaked, bs []byte) (err error) {
 	const cutoff = uint64(1 << uint(64-1))
 
 	var n uint64
-	var neg, badsyntax, overflow bool
+	var neg, badsyntax, overflow, ok bool
 
 	if len(bs) == 0 {
 		if d.h.PreferFloat {
@@ -1076,8 +1079,9 @@ func (d *jsonDecDriver) nakedNum(z *decNaked, bs []byte) (err error) {
 	if d.h.PreferFloat {
 		goto F
 	}
-	n, neg, badsyntax, overflow = jsonParseInteger(bs)
-	if badsyntax || overflow {
+	n, neg, badsyntax, overflow, ok = jsonParseInteger(bs)
+	if ok {
+	} else if badsyntax || overflow {
 		goto F
 	}
 	if neg {
@@ -1353,16 +1357,17 @@ func jsonFloatStrconvFmtPrec32(f float32) (fmt byte, prec int8) {
 
 // custom-fitted version of strconv.Parse(Ui|I)nt.
 // Also ensures we don't have to search for .eE to determine if a float or not.
-// Note: s CANNOT be a zero-length slice.
-func jsonParseInteger(s []byte) (n uint64, neg, badSyntax, overflow bool) {
+func jsonParseInteger(s []byte) (n uint64, neg, badSyntax, overflow, ok bool) {
 	const maxUint64 = (1<<64 - 1)
 	const cutoff = maxUint64/10 + 1
 
 	if len(s) == 0 { // bounds-check-elimination
 		// treat empty string as zero value
 		// badSyntax = true
+		ok = true
 		return
 	}
+
 	switch s[0] {
 	case '+':
 		s = s[1:]
@@ -1389,6 +1394,7 @@ func jsonParseInteger(s []byte) (n uint64, neg, badSyntax, overflow bool) {
 		}
 		n = n1
 	}
+	ok = true
 	return
 }
 

+ 57 - 7
codec/reader.go

@@ -16,6 +16,7 @@ type decReader interface {
 	readx(n uint) []byte
 	readb([]byte)
 	readn1() uint8
+	readn1eof() (v uint8, eof bool)
 
 	// read up to 7 bytes at a time
 	readn(num uint8) (v [rwNLen]byte)
@@ -349,19 +350,24 @@ func (z *bufioDecReader) readb(p []byte) {
 			z.tr = append(z.tr, p...)
 		}
 	} else {
-		z.readbFill(p, n)
+		z.readbFillMust(p, n)
 	}
 }
 
-func (z *bufioDecReader) readbFill(p0 []byte, n uint) {
+func (z *bufioDecReader) readbFillMust(p0 []byte, n uint) {
+	if err := z.readbFill(p0, n); err != nil {
+		panic(err)
+	}
+}
+
+func (z *bufioDecReader) readbFill(p0 []byte, n uint) (err error) {
 	// at this point, there's nothing in z.buf to read (z.buf is fully consumed)
 	p := p0[n:]
 	var n2 uint
-	var err error
 	if len(p) > cap(z.buf) {
 		n2, err = decReadFull(z.r, p)
 		if err != nil {
-			panic(err)
+			return
 		}
 		n += n2
 		z.n += n2
@@ -383,7 +389,7 @@ LOOP:
 		n1, err = z.r.Read(z.buf)
 		n2 = uint(n1)
 		if n2 == 0 && err != nil {
-			panic(err)
+			return
 		}
 		z.buf = z.buf[:n2]
 		n2 = uint(copy(p, z.buf))
@@ -401,13 +407,34 @@ LOOP:
 	if z.trb {
 		z.tr = append(z.tr, p0[:n]...)
 	}
+	return
 }
 
 func (z *bufioDecReader) last() byte {
 	return z.buf[z.c-1]
 }
 
+func (z *bufioDecReader) readn1eof() (b byte, eof bool) {
+	b, err := z.readn1err()
+	if err != nil {
+		if err == io.EOF {
+			eof = true
+		} else {
+			panic(err)
+		}
+	}
+	return
+}
+
 func (z *bufioDecReader) readn1() (b byte) {
+	b, err := z.readn1err()
+	if err != nil {
+		panic(err)
+	}
+	return
+}
+
+func (z *bufioDecReader) readn1err() (b byte, err error) {
 	// fast-path, so we elide calling into Read() most of the time
 	if z.c < uint(len(z.buf)) {
 		b = z.buf[z.c]
@@ -417,7 +444,10 @@ func (z *bufioDecReader) readn1() (b byte) {
 			z.tr = append(z.tr, b)
 		}
 	} else { // meaning z.c == len(z.buf) or greater ... so need to fill
-		z.readbFill(z.b[:1], 0)
+		err = z.readbFill(z.b[:1], 0)
+		if err != nil {
+			return
+		}
 		b = z.b[0]
 	}
 	return
@@ -456,7 +486,7 @@ func (z *bufioDecReader) readx(n uint) (bs []byte) {
 		n = uint(copy(bs, z.buf[z.c:]))
 		z.n += n
 		z.c += n
-		z.readbFill(bs, n)
+		z.readbFillMust(bs, n)
 	}
 	return
 }
@@ -732,6 +762,16 @@ func (z *bytesDecReader) readn1() (v uint8) {
 	return
 }
 
+func (z *bytesDecReader) readn1eof() (v uint8, eof bool) {
+	if z.c >= uint(len(z.b)) {
+		eof = true
+	} else {
+		v = z.b[z.c]
+		z.c++
+	}
+	return
+}
+
 func (z *bytesDecReader) readn(num uint8) (bs [rwNLen]byte) {
 	// if z.c >= uint(len(z.b)) || z.c+uint(num) >= uint(len(z.b)) {
 	// 	panic(io.EOF)
@@ -941,6 +981,16 @@ func (z *decRd) readn1() uint8 {
 	}
 }
 
+func (z *decRd) readn1eof() (uint8, bool) {
+	if z.bytes {
+		return z.rb.readn1eof()
+	} else if z.bufio {
+		return z.bi.readn1eof()
+	} else {
+		return z.ri.readn1eof()
+	}
+}
+
 func (z *decRd) skipWhitespace() (token byte) {
 	if z.bytes {
 		return z.rb.skipWhitespace()