@@ -9,12 +9,27 @@ import (
99)
1010
1111type structCacheTypeMap struct {
12- keys [][]byte
12+ keys [][]byte
13+
14+ // fast path detection
15+ hasEmbedded bool
16+
17+ // fast path (hasEmbedded == false): direct field access
18+ simpleIndexes []int
19+
20+ // embedded path (hasEmbedded == true): path-based access
1321 indexes [][]int // field path (support for embedded structs)
1422}
1523
1624type structCacheTypeArray struct {
17- m [][]int // field path (support for embedded structs)
25+ // fast path detection
26+ hasEmbedded bool
27+
28+ // fast path (hasEmbedded == false): direct field access
29+ simpleIndexes []int
30+
31+ // embedded path (hasEmbedded == true): path-based access
32+ indexes [][]int // field path (support for embedded structs)
1833}
1934
2035// struct cache map
@@ -87,25 +102,57 @@ func (d *decoder) setStructFromArray(rv reflect.Value, offset int, k reflect.Kin
87102 if ! findCache {
88103 scta = & structCacheTypeArray {}
89104 fields := d .CollectFields (rv .Type (), nil )
105+
106+ // detect embedded fields
107+ hasEmbedded := false
108+ for _ , f := range fields {
109+ if len (f .Path ) > 1 || len (f .OmitPaths ) > 0 {
110+ hasEmbedded = true
111+ break
112+ }
113+ }
114+ scta .hasEmbedded = hasEmbedded
115+
90116 for _ , field := range fields {
91- scta .m = append (scta .m , field .Path )
117+ if hasEmbedded {
118+ scta .indexes = append (scta .indexes , field .Path )
119+ } else {
120+ scta .simpleIndexes = append (scta .simpleIndexes , field .Path [0 ])
121+ }
92122 }
93123 mapSCTA .Store (rv .Type (), scta )
94124 } else {
95125 scta = cache .(* structCacheTypeArray )
96126 }
127+
97128 // set value
98- for i := 0 ; i < l ; i ++ {
99- if i < len (scta .m ) {
100- fieldValue := getFieldByPath (rv , scta .m [i ])
101- o , err = d .decode (fieldValue , o )
102- if err != nil {
103- return 0 , err
129+ if scta .hasEmbedded {
130+ for i := 0 ; i < l ; i ++ {
131+ if i < len (scta .indexes ) {
132+ fieldValue := getFieldByPath (rv , scta .indexes [i ])
133+ o , err = d .decode (fieldValue , o )
134+ if err != nil {
135+ return 0 , err
136+ }
137+ } else {
138+ o , err = d .jumpOffset (o )
139+ if err != nil {
140+ return 0 , err
141+ }
104142 }
105- } else {
106- o , err = d .jumpOffset (o )
107- if err != nil {
108- return 0 , err
143+ }
144+ } else {
145+ for i := 0 ; i < l ; i ++ {
146+ if i < len (scta .simpleIndexes ) {
147+ o , err = d .decode (rv .Field (scta .simpleIndexes [i ]), o )
148+ if err != nil {
149+ return 0 , err
150+ }
151+ } else {
152+ o , err = d .jumpOffset (o )
153+ if err != nil {
154+ return 0 , err
155+ }
109156 }
110157 }
111158 }
@@ -128,53 +175,109 @@ func (d *decoder) setStructFromMap(rv reflect.Value, offset int, k reflect.Kind)
128175 if ! cacheFind {
129176 sctm = & structCacheTypeMap {}
130177 fields := d .CollectFields (rv .Type (), nil )
178+
179+ // detect embedded fields
180+ hasEmbedded := false
181+ for _ , f := range fields {
182+ if len (f .Path ) > 1 || len (f .OmitPaths ) > 0 {
183+ hasEmbedded = true
184+ break
185+ }
186+ }
187+ sctm .hasEmbedded = hasEmbedded
188+
131189 for _ , field := range fields {
132190 sctm .keys = append (sctm .keys , []byte (field .Name ))
133- sctm .indexes = append (sctm .indexes , field .Path )
191+ if hasEmbedded {
192+ sctm .indexes = append (sctm .indexes , field .Path )
193+ } else {
194+ sctm .simpleIndexes = append (sctm .simpleIndexes , field .Path [0 ])
195+ }
134196 }
135197 mapSCTM .Store (rv .Type (), sctm )
136198 } else {
137199 sctm = cache .(* structCacheTypeMap )
138200 }
139201
140- for i := 0 ; i < l ; i ++ {
141- dataKey , o2 , err := d .asStringByte (o , k )
142- if err != nil {
143- return 0 , err
144- }
145-
146- fieldPath := []int (nil )
147- for keyIndex , keyBytes := range sctm .keys {
148- if len (keyBytes ) != len (dataKey ) {
149- continue
202+ if sctm .hasEmbedded {
203+ for i := 0 ; i < l ; i ++ {
204+ dataKey , o2 , err := d .asStringByte (o , k )
205+ if err != nil {
206+ return 0 , err
150207 }
151208
152- found := true
153- for dataIndex := range dataKey {
154- if dataKey [dataIndex ] != keyBytes [dataIndex ] {
155- found = false
209+ fieldPath := []int (nil )
210+ for keyIndex , keyBytes := range sctm .keys {
211+ if len (keyBytes ) != len (dataKey ) {
212+ continue
213+ }
214+
215+ found := true
216+ for dataIndex := range dataKey {
217+ if dataKey [dataIndex ] != keyBytes [dataIndex ] {
218+ found = false
219+ break
220+ }
221+ }
222+ if found {
223+ fieldPath = sctm .indexes [keyIndex ]
156224 break
157225 }
158226 }
159- if found {
160- fieldPath = sctm .indexes [keyIndex ]
161- break
227+
228+ if fieldPath != nil {
229+ fieldValue := getFieldByPath (rv , fieldPath )
230+ o2 , err = d .decode (fieldValue , o2 )
231+ if err != nil {
232+ return 0 , err
233+ }
234+ } else {
235+ o2 , err = d .jumpOffset (o2 )
236+ if err != nil {
237+ return 0 , err
238+ }
162239 }
240+ o = o2
163241 }
164-
165- if fieldPath != nil {
166- fieldValue := getFieldByPath (rv , fieldPath )
167- o2 , err = d .decode (fieldValue , o2 )
242+ } else {
243+ for i := 0 ; i < l ; i ++ {
244+ dataKey , o2 , err := d .asStringByte (o , k )
168245 if err != nil {
169246 return 0 , err
170247 }
171- } else {
172- o2 , err = d .jumpOffset (o2 )
173- if err != nil {
174- return 0 , err
248+
249+ fieldIndex := - 1
250+ for keyIndex , keyBytes := range sctm .keys {
251+ if len (keyBytes ) != len (dataKey ) {
252+ continue
253+ }
254+
255+ found := true
256+ for dataIndex := range dataKey {
257+ if dataKey [dataIndex ] != keyBytes [dataIndex ] {
258+ found = false
259+ break
260+ }
261+ }
262+ if found {
263+ fieldIndex = sctm .simpleIndexes [keyIndex ]
264+ break
265+ }
266+ }
267+
268+ if fieldIndex >= 0 {
269+ o2 , err = d .decode (rv .Field (fieldIndex ), o2 )
270+ if err != nil {
271+ return 0 , err
272+ }
273+ } else {
274+ o2 , err = d .jumpOffset (o2 )
275+ if err != nil {
276+ return 0 , err
277+ }
175278 }
279+ o = o2
176280 }
177- o = o2
178281 }
179282 return o , nil
180283}
0 commit comments