From d509f27cf43bba3daf7e08db0b6e10c0c892392f Mon Sep 17 00:00:00 2001 From: Ignacio Van Droogenbroeck Date: Mon, 2 Mar 2026 19:08:41 -0600 Subject: [PATCH] perf(encode): pool sorted map key slices via sync.Pool Replaces per-call make([]string, 0, len(m)) with a sync.Pool of reusable key slices in EncodeMapSorted, encodeSortedMapStringBool, and encodeSortedMapStringString. Eliminates 1 alloc per sorted map encode for callers using SetSortMapKeys(true). --- encode_map.go | 64 +++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 55 insertions(+), 9 deletions(-) diff --git a/encode_map.go b/encode_map.go index a5aa31b..c9f0b3c 100644 --- a/encode_map.go +++ b/encode_map.go @@ -4,10 +4,35 @@ import ( "math" "reflect" "sort" + "sync" "github.com/vmihailenco/msgpack/v5/msgpcode" ) +var sortedKeysPool = sync.Pool{ + New: func() interface{} { + s := make([]string, 0, 16) + return &s + }, +} + +func getSortedKeys(n int) *[]string { + sp := sortedKeysPool.Get().(*[]string) + if cap(*sp) < n { + *sp = make([]string, 0, n) + } else { + *sp = (*sp)[:0] + } + return sp +} + +func putSortedKeys(sp *[]string) { + if cap(*sp) > 1024 { + return // don't retain oversized slices + } + sortedKeysPool.Put(sp) +} + func encodeMapValue(e *Encoder, v reflect.Value) error { if v.IsNil() { return e.EncodeNil() @@ -119,7 +144,8 @@ func (e *Encoder) EncodeMapSorted(m map[string]interface{}) error { return err } - keys := make([]string, 0, len(m)) + sp := getSortedKeys(len(m)) + keys := *sp for k := range m { keys = append(keys, k) @@ -129,53 +155,73 @@ func (e *Encoder) EncodeMapSorted(m map[string]interface{}) error { for _, k := range keys { if err := e.EncodeString(k); err != nil { + *sp = keys + putSortedKeys(sp) return err } if err := e.Encode(m[k]); err != nil { + *sp = keys + putSortedKeys(sp) return err } } + *sp = keys + putSortedKeys(sp) return nil } func (e *Encoder) encodeSortedMapStringBool(m map[string]bool) error { - keys := make([]string, 0, len(m)) + sp := getSortedKeys(len(m)) + keys := *sp + for k := range m { keys = append(keys, k) } sort.Strings(keys) for _, k := range keys { - err := e.EncodeString(k) - if err != nil { + if err := e.EncodeString(k); err != nil { + *sp = keys + putSortedKeys(sp) return err } - if err = e.EncodeBool(m[k]); err != nil { + if err := e.EncodeBool(m[k]); err != nil { + *sp = keys + putSortedKeys(sp) return err } } + *sp = keys + putSortedKeys(sp) return nil } func (e *Encoder) encodeSortedMapStringString(m map[string]string) error { - keys := make([]string, 0, len(m)) + sp := getSortedKeys(len(m)) + keys := *sp + for k := range m { keys = append(keys, k) } sort.Strings(keys) for _, k := range keys { - err := e.EncodeString(k) - if err != nil { + if err := e.EncodeString(k); err != nil { + *sp = keys + putSortedKeys(sp) return err } - if err = e.EncodeString(m[k]); err != nil { + if err := e.EncodeString(m[k]); err != nil { + *sp = keys + putSortedKeys(sp) return err } } + *sp = keys + putSortedKeys(sp) return nil }