Skip to content

Commit 1ecc713

Browse files
author
Ignacio Van Droogenbroeck
committed
perf(encode,decode): skip reflect.Convert for exact map/slice types
Adds v.Type() == targetType fast path before v.Convert() in map and slice encode/decode functions. Convert is only needed for named types (e.g. type M map[string]string); for exact type matches it's pure overhead. Applies to map[string]string, map[string]bool, map[string]interface{}, and []string paths. Benchmark improvements: StringSlice: 85 ns -> 79 ns (-7%) MapStringString: 192 ns -> 176 ns (-8%) MapStringStringPtr: 217 ns -> 205 ns (-6%)
1 parent 82f46cf commit 1ecc713

4 files changed

Lines changed: 46 additions & 8 deletions

File tree

decode_map.go

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,12 @@ func (d *Decoder) mapLen(c byte) (int, error) {
114114
}
115115

116116
func decodeMapStringStringValue(d *Decoder, v reflect.Value) error {
117-
mptr := v.Addr().Convert(mapStringStringPtrType).Interface().(*map[string]string)
117+
var mptr *map[string]string
118+
if v.Type() == mapStringStringType {
119+
mptr = v.Addr().Interface().(*map[string]string)
120+
} else {
121+
mptr = v.Addr().Convert(mapStringStringPtrType).Interface().(*map[string]string)
122+
}
118123
return d.decodeMapStringStringPtr(mptr)
119124
}
120125

@@ -154,7 +159,12 @@ func (d *Decoder) decodeMapStringStringPtr(ptr *map[string]string) error {
154159
}
155160

156161
func decodeMapStringInterfaceValue(d *Decoder, v reflect.Value) error {
157-
ptr := v.Addr().Convert(mapStringInterfacePtrType).Interface().(*map[string]interface{})
162+
var ptr *map[string]interface{}
163+
if v.Type() == mapStringInterfaceType {
164+
ptr = v.Addr().Interface().(*map[string]interface{})
165+
} else {
166+
ptr = v.Addr().Convert(mapStringInterfacePtrType).Interface().(*map[string]interface{})
167+
}
158168
return d.decodeMapStringInterfacePtr(ptr)
159169
}
160170

decode_slice.go

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,10 @@ import (
77
"github.com/vmihailenco/msgpack/v5/msgpcode"
88
)
99

10-
var sliceStringPtrType = reflect.TypeOf((*[]string)(nil))
10+
var (
11+
sliceStringPtrType = reflect.TypeOf((*[]string)(nil))
12+
sliceStringType = sliceStringPtrType.Elem()
13+
)
1114

1215
// DecodeArrayLen decodes array length. Length is -1 when array is nil.
1316
func (d *Decoder) DecodeArrayLen() (int, error) {
@@ -36,7 +39,12 @@ func (d *Decoder) arrayLen(c byte) (int, error) {
3639
}
3740

3841
func decodeStringSliceValue(d *Decoder, v reflect.Value) error {
39-
ptr := v.Addr().Convert(sliceStringPtrType).Interface().(*[]string)
42+
var ptr *[]string
43+
if v.Type() == sliceStringType {
44+
ptr = v.Addr().Interface().(*[]string)
45+
} else {
46+
ptr = v.Addr().Convert(sliceStringPtrType).Interface().(*[]string)
47+
}
4048
return d.decodeStringSlicePtr(ptr)
4149
}
4250

encode_map.go

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,12 @@ func encodeMapStringBoolValue(e *Encoder, v reflect.Value) error {
3939
return err
4040
}
4141

42-
m := v.Convert(mapStringBoolType).Interface().(map[string]bool)
42+
var m map[string]bool
43+
if v.Type() == mapStringBoolType {
44+
m = v.Interface().(map[string]bool)
45+
} else {
46+
m = v.Convert(mapStringBoolType).Interface().(map[string]bool)
47+
}
4348
if e.flags&sortMapKeysFlag != 0 {
4449
return e.encodeSortedMapStringBool(m)
4550
}
@@ -65,7 +70,12 @@ func encodeMapStringStringValue(e *Encoder, v reflect.Value) error {
6570
return err
6671
}
6772

68-
m := v.Convert(mapStringStringType).Interface().(map[string]string)
73+
var m map[string]string
74+
if v.Type() == mapStringStringType {
75+
m = v.Interface().(map[string]string)
76+
} else {
77+
m = v.Convert(mapStringStringType).Interface().(map[string]string)
78+
}
6979
if e.flags&sortMapKeysFlag != 0 {
7080
return e.encodeSortedMapStringString(m)
7181
}
@@ -86,7 +96,12 @@ func encodeMapStringInterfaceValue(e *Encoder, v reflect.Value) error {
8696
if v.IsNil() {
8797
return e.EncodeNil()
8898
}
89-
m := v.Convert(mapStringInterfaceType).Interface().(map[string]interface{})
99+
var m map[string]interface{}
100+
if v.Type() == mapStringInterfaceType {
101+
m = v.Interface().(map[string]interface{})
102+
} else {
103+
m = v.Convert(mapStringInterfaceType).Interface().(map[string]interface{})
104+
}
90105
if e.flags&sortMapKeysFlag != 0 {
91106
return e.EncodeMapSorted(m)
92107
}

encode_slice.go

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,12 @@ func (e *Encoder) EncodeArrayLen(l int) error {
9999
}
100100

101101
func encodeStringSliceValue(e *Encoder, v reflect.Value) error {
102-
ss := v.Convert(stringSliceType).Interface().([]string)
102+
var ss []string
103+
if v.Type() == stringSliceType {
104+
ss = v.Interface().([]string)
105+
} else {
106+
ss = v.Convert(stringSliceType).Interface().([]string)
107+
}
103108
return e.encodeStringSlice(ss)
104109
}
105110

0 commit comments

Comments
 (0)