summaryrefslogtreecommitdiff
path: root/vendor/github.com/ugorji/go/codec/decode.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/ugorji/go/codec/decode.go')
-rw-r--r--vendor/github.com/ugorji/go/codec/decode.go192
1 files changed, 109 insertions, 83 deletions
diff --git a/vendor/github.com/ugorji/go/codec/decode.go b/vendor/github.com/ugorji/go/codec/decode.go
index d454db09c..db87f2e71 100644
--- a/vendor/github.com/ugorji/go/codec/decode.go
+++ b/vendor/github.com/ugorji/go/codec/decode.go
@@ -16,9 +16,9 @@ import (
const msgBadDesc = "unrecognized descriptor byte"
const (
- decDefMaxDepth = 1024 // maximum depth
- decDefChanCap = 64 // should be large, as cap cannot be expanded
- decScratchByteArrayLen = (8 + 2 + 2) * 8 // around cacheLineSize ie ~64, depending on Decoder size
+ decDefMaxDepth = 1024 // maximum depth
+ decDefChanCap = 64 // should be large, as cap cannot be expanded
+ decScratchByteArrayLen = (8 + 2 + 2 + 1) * 8 // around cacheLineSize ie ~64, depending on Decoder size
// MARKER: massage decScratchByteArrayLen to ensure xxxDecDriver structs fit within cacheLine*N
@@ -150,13 +150,11 @@ type decDriver interface {
// If the format doesn't prefix the length, it returns containerLenUnknown.
// If the expected array was a nil in the stream, it returns containerLenNil.
ReadArrayStart() int
- ReadArrayEnd()
// ReadMapStart will return the length of the array.
// If the format doesn't prefix the length, it returns containerLenUnknown.
// If the expected array was a nil in the stream, it returns containerLenNil.
ReadMapStart() int
- ReadMapEnd()
reset()
@@ -186,6 +184,8 @@ type decDriverContainerTracker interface {
ReadArrayElem()
ReadMapElemKey()
ReadMapElemValue()
+ ReadArrayEnd()
+ ReadMapEnd()
}
type decNegintPosintFloatNumber interface {
@@ -202,11 +202,11 @@ func (x decDriverNoopNumberHelper) decFloat() (f float64, ok bool) { panic("decF
type decDriverNoopContainerReader struct{}
-func (x decDriverNoopContainerReader) ReadArrayStart() (v int) { panic("ReadArrayStart unsupported") }
-func (x decDriverNoopContainerReader) ReadArrayEnd() {}
-func (x decDriverNoopContainerReader) ReadMapStart() (v int) { panic("ReadMapStart unsupported") }
-func (x decDriverNoopContainerReader) ReadMapEnd() {}
-func (x decDriverNoopContainerReader) CheckBreak() (v bool) { return }
+// func (x decDriverNoopContainerReader) ReadArrayStart() (v int) { panic("ReadArrayStart unsupported") }
+// func (x decDriverNoopContainerReader) ReadMapStart() (v int) { panic("ReadMapStart unsupported") }
+func (x decDriverNoopContainerReader) ReadArrayEnd() {}
+func (x decDriverNoopContainerReader) ReadMapEnd() {}
+func (x decDriverNoopContainerReader) CheckBreak() (v bool) { return }
// DecodeOptions captures configuration options during decode.
type DecodeOptions struct {
@@ -335,6 +335,12 @@ type DecodeOptions struct {
//
// This mostly impacts when we decode registered extensions.
PreferPointerForStructOrArray bool
+
+ // ValidateUnicode controls will cause decoding to fail if an expected unicode
+ // string is well-formed but include invalid codepoints.
+ //
+ // This could have a performance impact.
+ ValidateUnicode bool
}
// ----------------------------------------
@@ -638,7 +644,7 @@ func (d *Decoder) kInterface(f *codecFnInfo, rv reflect.Value) {
// decode into it, and reset the interface to that new value.
if !canDecode {
- rvn2 := d.oneShotAddrRV(rvType(rvn), rvn.Kind())
+ rvn2 := d.oneShotAddrRV(rvn.Type(), rvn.Kind())
rvSetDirect(rvn2, rvn)
rvn = rvn2
}
@@ -660,6 +666,16 @@ func decStructFieldKeyNotString(dd decDriver, keyType valueType, b *[decScratchB
return
}
+func (d *Decoder) kStructField(si *structFieldInfo, rv reflect.Value) {
+ if d.d.TryNil() {
+ if rv = si.path.field(rv); rv.IsValid() {
+ decSetNonNilRV2Zero(rv)
+ }
+ return
+ }
+ d.decodeValueNoCheckNil(si.path.fieldAlloc(rv), nil)
+}
+
func (d *Decoder) kStruct(f *codecFnInfo, rv reflect.Value) {
ctyp := d.d.ContainerType()
ti := f.ti
@@ -691,7 +707,7 @@ func (d *Decoder) kStruct(f *codecFnInfo, rv reflect.Value) {
}
d.mapElemValue()
if si := ti.siForEncName(rvkencname); si != nil {
- d.decodeValue(si.path.fieldAlloc(rv), nil)
+ d.kStructField(si, rv)
} else if mf != nil {
// store rvkencname in new []byte, as it previously shares Decoder.b, which is used in decode
name2 = append(name2[:0], rvkencname...)
@@ -713,38 +729,21 @@ func (d *Decoder) kStruct(f *codecFnInfo, rv reflect.Value) {
}
// Not much gain from doing it two ways for array.
// Arrays are not used as much for structs.
- hasLen := containerLen >= 0
- var checkbreak bool
tisfi := ti.sfi.source()
- for j, si := range tisfi {
- if hasLen {
- if j == containerLen {
- break
- }
- } else if d.checkBreak() {
- checkbreak = true
- break
- }
+ hasLen := containerLen >= 0
+
+ // iterate all the items in the stream
+ // if mapped elem-wise to a field, handle it
+ // if more stream items than cap be mapped, error it
+ for j := 0; d.containerNext(j, containerLen, hasLen); j++ {
d.arrayElem()
- d.decodeValue(si.path.fieldAlloc(rv), nil)
- }
- var proceed bool
- if hasLen {
- proceed = containerLen > len(tisfi)
- } else {
- proceed = !checkbreak
- }
- // if (hasLen && containerLen > len(tisfi)) || (!hasLen && !checkbreak) {
- if proceed {
- // read remaining values and throw away
- for j := len(tisfi); ; j++ {
- if !d.containerNext(j, containerLen, hasLen) {
- break
- }
- d.arrayElem()
+ if j < len(tisfi) {
+ d.kStructField(tisfi[j], rv)
+ } else {
d.structFieldNotFound(j, "")
}
}
+
d.arrayEnd()
} else {
d.onerror(errNeedMapOrArrayDecodeToStruct)
@@ -1215,7 +1214,7 @@ func (d *Decoder) kMap(f *codecFnInfo, rv reflect.Value) {
d.decodeValue(rvk, keyFn)
// special case if interface wrapping a byte slice
if ktypeIsIntf {
- if rvk2 := rvk.Elem(); rvk2.IsValid() && rvType(rvk2) == uint8SliceTyp {
+ if rvk2 := rvk.Elem(); rvk2.IsValid() && rvk2.Type() == uint8SliceTyp {
kstr2bs = rvGetBytes(rvk2)
rvSetIntf(rvk, rv4istr(fnRvk2()))
}
@@ -1406,6 +1405,7 @@ func (d *Decoder) r() *decRd {
func (d *Decoder) init(h Handle) {
initHandle(h)
+ d.cbreak = d.js || d.cbor
d.bytes = true
d.err = errDecoderNotInitialized
d.h = h.getBasicHandle()
@@ -1450,21 +1450,11 @@ func (d *Decoder) Reset(r io.Reader) {
r = &eofReader
}
d.bytes = false
- if d.h.ReaderBufferSize > 0 {
- if d.bi == nil {
- d.bi = new(bufioDecReader)
- }
- d.bi.reset(r, d.h.ReaderBufferSize, &d.blist)
- d.bufio = true
- d.decReader = d.bi
- } else {
- if d.ri == nil {
- d.ri = new(ioDecReader)
- }
- d.ri.reset(r, &d.blist)
- d.bufio = false
- d.decReader = d.ri
+ if d.ri == nil {
+ d.ri = new(ioDecReader)
}
+ d.ri.reset(r, d.h.ReaderBufferSize, &d.blist)
+ d.decReader = d.ri
d.resetCommon()
}
@@ -1474,7 +1464,6 @@ func (d *Decoder) ResetBytes(in []byte) {
if in == nil {
in = []byte{}
}
- d.bufio = false
d.bytes = true
d.decReader = &d.rb
d.rb.reset(in)
@@ -1505,14 +1494,15 @@ func (d *Decoder) naked() *fauxUnion {
// We will decode and store a value in that nil interface.
//
// Sample usages:
-// // Decoding into a non-nil typed value
-// var f float32
-// err = codec.NewDecoder(r, handle).Decode(&f)
//
-// // Decoding into nil interface
-// var v interface{}
-// dec := codec.NewDecoder(r, handle)
-// err = dec.Decode(&v)
+// // Decoding into a non-nil typed value
+// var f float32
+// err = codec.NewDecoder(r, handle).Decode(&f)
+//
+// // Decoding into nil interface
+// var v interface{}
+// dec := codec.NewDecoder(r, handle)
+// err = dec.Decode(&v)
//
// When decoding into a nil interface{}, we will decode into an appropriate value based
// on the contents of the stream:
@@ -1520,6 +1510,7 @@ func (d *Decoder) naked() *fauxUnion {
// - Other values are decoded appropriately depending on the type:
// bool, string, []byte, time.Time, etc
// - Extensions are decoded as RawExt (if no ext function registered for the tag)
+//
// Configurations exist on the Handle to override defaults
// (e.g. for MapType, SliceType and how to decode raw bytes).
//
@@ -1814,7 +1805,7 @@ PTR:
if rv.Kind() == reflect.Ptr {
rvpValid = true
if rvIsNil(rv) {
- rvSetDirect(rv, reflect.New(rvType(rv).Elem()))
+ rvSetDirect(rv, reflect.New(rv.Type().Elem()))
}
rvp = rv
rv = rv.Elem()
@@ -1822,7 +1813,7 @@ PTR:
}
if fn == nil {
- fn = d.h.fn(rvType(rv))
+ fn = d.h.fn(rv.Type())
}
if fn.i.addrD {
if rvpValid {
@@ -1908,9 +1899,9 @@ func (d *Decoder) rawBytes() (v []byte) {
// i.e. if necessary, make new copy always.
v = d.d.nextValueBytes([]byte{})
if d.bytes && !d.h.ZeroCopy {
- v0 := v
- v = make([]byte, len(v))
- copy(v, v0)
+ vv := make([]byte, len(v))
+ copy(vv, v) // using copy here triggers make+copy optimization eliding memclr
+ v = vv
}
return
}
@@ -1941,7 +1932,34 @@ func (d *Decoder) decodeFloat32() float32 {
// MARKER: do not call mapEnd if mapStart returns containerLenNil.
+// MARKER: optimize decoding since all formats do not truly support all decDriver'ish operations.
+// - Read(Map|Array)Start is only supported by all formats.
+// - CheckBreak is only supported by json and cbor.
+// - Read(Map|Array)End is only supported by json.
+// - Read(Map|Array)Elem(Kay|Value) is only supported by json.
+// Honor these in the code, to reduce the number of interface calls (even if empty).
+
+func (d *Decoder) checkBreak() (v bool) {
+ // MARKER: jsonDecDriver.CheckBreak() cannot be inlined (over budget inlining cost).
+ // Consequently, there's no benefit in incurring the cost of this wrapping function.
+ // It is faster to just call the interface method directly.
+
+ // if d.js {
+ // return d.jsondriver().CheckBreak()
+ // }
+ // if d.cbor {
+ // return d.cbordriver().CheckBreak()
+ // }
+
+ if d.cbreak {
+ v = d.d.CheckBreak()
+ }
+ return
+}
+
func (d *Decoder) containerNext(j, containerLen int, hasLen bool) bool {
+ // MARKER: keep in sync with gen-helper.go.tmpl
+
// return (hasLen && j < containerLen) || !(hasLen || slh.d.checkBreak())
if hasLen {
return j < containerLen
@@ -1972,7 +1990,10 @@ func (d *Decoder) mapElemValue() {
}
func (d *Decoder) mapEnd() {
- d.d.ReadMapEnd()
+ if d.js {
+ d.jsondriver().ReadMapEnd()
+ }
+ // d.d.ReadMapEnd()
d.depthDecr()
d.c = 0
}
@@ -1993,7 +2014,10 @@ func (d *Decoder) arrayElem() {
}
func (d *Decoder) arrayEnd() {
- d.d.ReadArrayEnd()
+ if d.js {
+ d.jsondriver().ReadArrayEnd()
+ }
+ // d.d.ReadArrayEnd()
d.depthDecr()
d.c = 0
}
@@ -2028,7 +2052,7 @@ func (d *Decoder) interfaceExtConvertAndDecode(v interface{}, ext InterfaceExt)
if !rv.CanAddr() {
rvk = rv.Kind()
- rv2 = d.oneShotAddrRV(rvType(rv), rvk)
+ rv2 = d.oneShotAddrRV(rv.Type(), rvk)
if rvk == reflect.Interface {
rvSetIntf(rv2, rv)
} else {
@@ -2157,9 +2181,9 @@ func (x decSliceHelper) arrayCannotExpand(hasLen bool, lenv, j, containerLenS in
// decNextValueBytesHelper helps with NextValueBytes calls.
//
// Typical usage:
-// - each Handle's decDriver will implement a high level nextValueBytes,
-// which will track the current cursor, delegate to a nextValueBytesR
-// method, and then potentially call bytesRdV at the end.
+// - each Handle's decDriver will implement a high level nextValueBytes,
+// which will track the current cursor, delegate to a nextValueBytesR
+// method, and then potentially call bytesRdV at the end.
//
// See simple.go for typical usage model.
type decNextValueBytesHelper struct {
@@ -2178,6 +2202,12 @@ func (x decNextValueBytesHelper) appendN(v *[]byte, b ...byte) {
}
}
+func (x decNextValueBytesHelper) appendS(v *[]byte, b string) {
+ if *v != nil && !x.d.bytes {
+ *v = append(*v, b...)
+ }
+}
+
func (x decNextValueBytesHelper) bytesRdV(v *[]byte, startpos uint) {
if x.d.bytes {
*v = x.d.rb.b[startpos:x.d.rb.c]
@@ -2281,12 +2311,8 @@ func isDecodeable(rv reflect.Value) (canDecode bool, reason decNotDecodeableReas
}
func decByteSlice(r *decRd, clen, maxInitLen int, bs []byte) (bsOut []byte) {
- if clen == 0 {
- return zeroByteSlice
- }
- if len(bs) == clen {
- bsOut = bs
- r.readb(bsOut)
+ if clen <= 0 {
+ bsOut = zeroByteSlice
} else if cap(bs) >= clen {
bsOut = bs[:clen]
r.readb(bsOut)
@@ -2305,10 +2331,10 @@ func decByteSlice(r *decRd, clen, maxInitLen int, bs []byte) (bsOut []byte) {
}
// decInferLen will infer a sensible length, given the following:
-// - clen: length wanted.
-// - maxlen: max length to be returned.
-// if <= 0, it is unset, and we infer it based on the unit size
-// - unit: number of bytes for each element of the collection
+// - clen: length wanted.
+// - maxlen: max length to be returned.
+// if <= 0, it is unset, and we infer it based on the unit size
+// - unit: number of bytes for each element of the collection
func decInferLen(clen, maxlen, unit int) int {
// anecdotal testing showed increase in allocation with map length of 16.
// We saw same typical alloc from 0-8, then a 20% increase at 16.