perf(decode): cache struct schemas per type
Assisted-by: GLM 5.3
This commit is contained in:
@@ -8,6 +8,7 @@ import (
|
||||
"math"
|
||||
"reflect"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
@@ -105,7 +106,7 @@ func (d *decoder) assignTable(tbl map[string]any, dst reflect.Value) error {
|
||||
}
|
||||
|
||||
func (d *decoder) assignStruct(tbl map[string]any, dst reflect.Value) error {
|
||||
schema := newStructSchema(dst.Type())
|
||||
schema := cachedStructSchema(dst.Type())
|
||||
for key, val := range tbl {
|
||||
field, ok := schema.byName[strings.ToLower(key)]
|
||||
if !ok {
|
||||
@@ -253,6 +254,21 @@ type structSchema struct {
|
||||
embedMaps [][]int
|
||||
}
|
||||
|
||||
// structSchemaCache holds one schema per struct type. A schema is immutable
|
||||
// once published, so concurrent callers only race to build an identical value,
|
||||
// the same trade-off encoding/json's field cache makes. The cache grows with
|
||||
// the number of distinct types decoded or encoded, never per document.
|
||||
var structSchemaCache sync.Map // reflect.Type -> structSchema
|
||||
|
||||
func cachedStructSchema(t reflect.Type) structSchema {
|
||||
if s, ok := structSchemaCache.Load(t); ok {
|
||||
return s.(structSchema)
|
||||
}
|
||||
s := newStructSchema(t)
|
||||
actual, _ := structSchemaCache.LoadOrStore(t, s)
|
||||
return actual.(structSchema)
|
||||
}
|
||||
|
||||
func newStructSchema(t reflect.Type) structSchema {
|
||||
s := structSchema{byName: make(map[string]structFieldLoc, t.NumField())}
|
||||
// A struct may embed a pointer to itself, which is legal Go, so the walk
|
||||
|
||||
Reference in New Issue
Block a user