@@ -16,9 +16,9 @@ import (
1616const msgBadDesc = "unrecognized descriptor byte"
1717
1818const (
19- decDefMaxDepth = 1024 // maximum depth
20- decDefChanCap = 64 // should be large, as cap cannot be expanded
21- decScratchByteArrayLen = (8 + 2 + 2 ) * 8 // around cacheLineSize ie ~64, depending on Decoder size
19+ decDefMaxDepth = 1024 // maximum depth
20+ decDefChanCap = 64 // should be large, as cap cannot be expanded
21+ decScratchByteArrayLen = (8 + 2 + 2 + 1 ) * 8 // around cacheLineSize ie ~64, depending on Decoder size
2222
2323 // MARKER: massage decScratchByteArrayLen to ensure xxxDecDriver structs fit within cacheLine*N
2424
@@ -150,13 +150,11 @@ type decDriver interface {
150150 // If the format doesn't prefix the length, it returns containerLenUnknown.
151151 // If the expected array was a nil in the stream, it returns containerLenNil.
152152 ReadArrayStart () int
153- ReadArrayEnd ()
154153
155154 // ReadMapStart will return the length of the array.
156155 // If the format doesn't prefix the length, it returns containerLenUnknown.
157156 // If the expected array was a nil in the stream, it returns containerLenNil.
158157 ReadMapStart () int
159- ReadMapEnd ()
160158
161159 reset ()
162160
@@ -186,6 +184,8 @@ type decDriverContainerTracker interface {
186184 ReadArrayElem ()
187185 ReadMapElemKey ()
188186 ReadMapElemValue ()
187+ ReadArrayEnd ()
188+ ReadMapEnd ()
189189}
190190
191191type decNegintPosintFloatNumber interface {
@@ -202,11 +202,11 @@ func (x decDriverNoopNumberHelper) decFloat() (f float64, ok bool) { panic("decF
202202
203203type decDriverNoopContainerReader struct {}
204204
205- func (x decDriverNoopContainerReader ) ReadArrayStart () (v int ) { panic ("ReadArrayStart unsupported" ) }
206- func (x decDriverNoopContainerReader ) ReadArrayEnd () { }
207- func (x decDriverNoopContainerReader ) ReadMapStart () ( v int ) { panic ( "ReadMapStart unsupported" ) }
208- func (x decDriverNoopContainerReader ) ReadMapEnd () {}
209- func (x decDriverNoopContainerReader ) CheckBreak () (v bool ) { return }
205+ // func (x decDriverNoopContainerReader) ReadArrayStart() (v int) { panic("ReadArrayStart unsupported") }
206+ // func (x decDriverNoopContainerReader) ReadMapStart () (v int) { panic("ReadMapStart unsupported") }
207+ func (x decDriverNoopContainerReader ) ReadArrayEnd () { }
208+ func (x decDriverNoopContainerReader ) ReadMapEnd () {}
209+ func (x decDriverNoopContainerReader ) CheckBreak () (v bool ) { return }
210210
211211// DecodeOptions captures configuration options during decode.
212212type DecodeOptions struct {
@@ -729,38 +729,21 @@ func (d *Decoder) kStruct(f *codecFnInfo, rv reflect.Value) {
729729 }
730730 // Not much gain from doing it two ways for array.
731731 // Arrays are not used as much for structs.
732- hasLen := containerLen >= 0
733- var checkbreak bool
734732 tisfi := ti .sfi .source ()
735- for j , si := range tisfi {
736- if hasLen {
737- if j == containerLen {
738- break
739- }
740- } else if d .checkBreak () {
741- checkbreak = true
742- break
743- }
733+ hasLen := containerLen >= 0
734+
735+ // iterate all the items in the stream
736+ // if mapped elem-wise to a field, handle it
737+ // if more stream items than cap be mapped, error it
738+ for j := 0 ; d .containerNext (j , containerLen , hasLen ); j ++ {
744739 d .arrayElem ()
745- d .kStructField (si , rv )
746- }
747- var proceed bool
748- if hasLen {
749- proceed = containerLen > len (tisfi )
750- } else {
751- proceed = ! checkbreak
752- }
753- // if (hasLen && containerLen > len(tisfi)) || (!hasLen && !checkbreak) {
754- if proceed {
755- // read remaining values and throw away
756- for j := len (tisfi ); ; j ++ {
757- if ! d .containerNext (j , containerLen , hasLen ) {
758- break
759- }
760- d .arrayElem ()
740+ if j < len (tisfi ) {
741+ d .kStructField (tisfi [j ], rv )
742+ } else {
761743 d .structFieldNotFound (j , "" )
762744 }
763745 }
746+
764747 d .arrayEnd ()
765748 } else {
766749 d .onerror (errNeedMapOrArrayDecodeToStruct )
@@ -1422,6 +1405,7 @@ func (d *Decoder) r() *decRd {
14221405
14231406func (d * Decoder ) init (h Handle ) {
14241407 initHandle (h )
1408+ d .cbreak = d .js || d .cbor
14251409 d .bytes = true
14261410 d .err = errDecoderNotInitialized
14271411 d .h = h .getBasicHandle ()
@@ -1948,7 +1932,34 @@ func (d *Decoder) decodeFloat32() float32 {
19481932
19491933// MARKER: do not call mapEnd if mapStart returns containerLenNil.
19501934
1935+ // MARKER: optimize decoding since all formats do not truly support all decDriver'ish operations.
1936+ // - Read(Map|Array)Start is only supported by all formats.
1937+ // - CheckBreak is only supported by json and cbor.
1938+ // - Read(Map|Array)End is only supported by json.
1939+ // - Read(Map|Array)Elem(Kay|Value) is only supported by json.
1940+ // Honor these in the code, to reduce the number of interface calls (even if empty).
1941+
1942+ func (d * Decoder ) checkBreak () (v bool ) {
1943+ // MARKER: jsonDecDriver.CheckBreak() cannot be inlined (over budget inlining cost).
1944+ // Consequently, there's no benefit in incurring the cost of this wrapping function.
1945+ // It is faster to just call the interface method directly.
1946+
1947+ // if d.js {
1948+ // return d.jsondriver().CheckBreak()
1949+ // }
1950+ // if d.cbor {
1951+ // return d.cbordriver().CheckBreak()
1952+ // }
1953+
1954+ if d .cbreak {
1955+ v = d .d .CheckBreak ()
1956+ }
1957+ return
1958+ }
1959+
19511960func (d * Decoder ) containerNext (j , containerLen int , hasLen bool ) bool {
1961+ // MARKER: keep in sync with gen-helper.go.tmpl
1962+
19521963 // return (hasLen && j < containerLen) || !(hasLen || slh.d.checkBreak())
19531964 if hasLen {
19541965 return j < containerLen
@@ -1979,7 +1990,10 @@ func (d *Decoder) mapElemValue() {
19791990}
19801991
19811992func (d * Decoder ) mapEnd () {
1982- d .d .ReadMapEnd ()
1993+ if d .js {
1994+ d .jsondriver ().ReadMapEnd ()
1995+ }
1996+ // d.d.ReadMapEnd()
19831997 d .depthDecr ()
19841998 d .c = 0
19851999}
@@ -2000,7 +2014,10 @@ func (d *Decoder) arrayElem() {
20002014}
20012015
20022016func (d * Decoder ) arrayEnd () {
2003- d .d .ReadArrayEnd ()
2017+ if d .js {
2018+ d .jsondriver ().ReadArrayEnd ()
2019+ }
2020+ // d.d.ReadArrayEnd()
20042021 d .depthDecr ()
20052022 d .c = 0
20062023}
0 commit comments