diff options
Diffstat (limited to 'vendor/github.com/ugorji/go/codec/decode.go')
-rw-r--r-- | vendor/github.com/ugorji/go/codec/decode.go | 192 |
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. |