Skip to content

Commit b453ea7

Browse files
committed
imp
1 parent ff677b1 commit b453ea7

4 files changed

Lines changed: 528 additions & 157 deletions

File tree

internal/decoding/struct.go

Lines changed: 143 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,27 @@ import (
99
)
1010

1111
type 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

1624
type 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

Comments
 (0)