]> Cypherpunks repositories - gostls13.git/commitdiff
encoding/gob: make use of reflect.TypeAssert
authorapocelipes <seve3r@outlook.com>
Thu, 11 Sep 2025 09:40:02 +0000 (09:40 +0000)
committerGopher Robot <gobot@golang.org>
Thu, 11 Sep 2025 17:56:37 +0000 (10:56 -0700)
Use "reflect.TypeAssert" to simplify the code.

There are also some performance gains:

goarch: arm64
pkg: encoding/gob
cpu: Apple M4
                         │     old     │                 new                 │
                         │   sec/op    │   sec/op     vs base                │
EncodeComplex128Slice-10   1.048µ ± 3%   1.048µ ± 1%        ~ (p=0.986 n=10)
EncodeFloat64Slice-10      481.5n ± 0%   538.1n ± 0%  +11.75% (p=0.000 n=10)
EncodeInt32Slice-10        560.0n ± 1%   562.2n ± 1%        ~ (p=0.239 n=10)
EncodeStringSlice-10       713.1n ± 2%   690.1n ± 1%   -3.24% (p=0.000 n=10)
EncodeInterfaceSlice-10    16.10µ ± 3%   16.89µ ± 3%   +4.94% (p=0.004 n=10)
DecodeComplex128Slice-10   5.507µ ± 2%   5.488µ ± 2%        ~ (p=0.617 n=10)
DecodeFloat64Slice-10      3.359µ ± 1%   3.365µ ± 1%        ~ (p=0.403 n=10)
DecodeInt32Slice-10        3.296µ ± 1%   3.290µ ± 2%        ~ (p=0.926 n=10)
DecodeStringSlice-10       8.397µ ± 2%   8.459µ ± 1%        ~ (p=0.796 n=10)
DecodeStringsSlice-10      18.47µ ± 1%   11.14µ ± 1%  -39.69% (p=0.000 n=10)
DecodeBytesSlice-10        5.038µ ± 1%   5.039µ ± 1%        ~ (p=0.956 n=10)
DecodeInterfaceSlice-10    40.14µ ± 1%   40.60µ ± 1%   +1.16% (p=0.001 n=10)
DecodeMap-10               43.43µ ± 1%   44.09µ ± 1%   +1.51% (p=0.000 n=10)
geomean                    4.451µ        4.335µ        -2.62%

                         │      old       │                  new                   │
                         │      B/op      │     B/op      vs base                  │
EncodeComplex128Slice-10    1.0000 ±  ?      0.5000 ±  ?        ~ (p=0.350 n=10)
EncodeFloat64Slice-10        0.000 ± 0%       0.000 ± 0%        ~ (p=1.000 n=10) ¹
EncodeInt32Slice-10          0.000 ± 0%       0.000 ± 0%        ~ (p=1.000 n=10) ¹
EncodeStringSlice-10         0.000 ± 0%       0.000 ± 0%        ~ (p=1.000 n=10) ¹
EncodeInterfaceSlice-10      19.00 ± 5%       20.00 ± 5%   +5.26% (p=0.002 n=10)
DecodeComplex128Slice-10   24.55Ki ± 0%     24.53Ki ± 0%   -0.10% (p=0.000 n=10)
DecodeFloat64Slice-10      10.56Ki ± 0%     10.54Ki ± 0%   -0.22% (p=0.000 n=10)
DecodeInt32Slice-10        9.539Ki ± 0%     9.516Ki ± 0%   -0.25% (p=0.000 n=10)
DecodeStringSlice-10       38.18Ki ± 0%     38.16Ki ± 0%   -0.06% (p=0.000 n=10)
DecodeStringsSlice-10      63.96Ki ± 0%     40.51Ki ± 0%  -36.65% (p=0.000 n=10)
DecodeBytesSlice-10        22.58Ki ± 0%     22.58Ki ± 0%        ~ (p=1.000 n=10)
DecodeInterfaceSlice-10    80.47Ki ± 0%     80.47Ki ± 0%        ~ (p=1.000 n=10)
DecodeMap-10               48.81Ki ± 0%     48.81Ki ± 0%        ~ (p=1.000 n=10) ¹
geomean                                 ²                  -8.15%                ²
¹ all samples are equal
² summaries must be >0 to compute geomean

                         │      old      │                  new                  │
                         │   allocs/op   │  allocs/op   vs base                  │
EncodeComplex128Slice-10    0.000 ± 0%      0.000 ± 0%        ~ (p=1.000 n=10) ¹
EncodeFloat64Slice-10       0.000 ± 0%      0.000 ± 0%        ~ (p=1.000 n=10) ¹
EncodeInt32Slice-10         0.000 ± 0%      0.000 ± 0%        ~ (p=1.000 n=10) ¹
EncodeStringSlice-10        0.000 ± 0%      0.000 ± 0%        ~ (p=1.000 n=10) ¹
EncodeInterfaceSlice-10     0.000 ± 0%      0.000 ± 0%        ~ (p=1.000 n=10) ¹
DecodeComplex128Slice-10    149.0 ± 0%      148.0 ± 0%   -0.67% (p=0.000 n=10)
DecodeFloat64Slice-10       150.0 ± 0%      149.0 ± 0%   -0.67% (p=0.000 n=10)
DecodeInt32Slice-10         149.0 ± 0%      148.0 ± 0%   -0.67% (p=0.000 n=10)
DecodeStringSlice-10       1.150k ± 0%     1.149k ± 0%   -0.09% (p=0.000 n=10)
DecodeStringsSlice-10      2.158k ± 0%     1.158k ± 0%  -46.34% (p=0.000 n=10)
DecodeBytesSlice-10         149.0 ± 0%      149.0 ± 0%        ~ (p=1.000 n=10) ¹
DecodeInterfaceSlice-10    3.158k ± 0%     3.158k ± 0%        ~ (p=1.000 n=10) ¹
DecodeMap-10                160.0 ± 0%      160.0 ± 0%        ~ (p=1.000 n=10) ¹
geomean                                ²                 -4.83%                ²
¹ all samples are equal
² summaries must be >0 to compute geomean

Updates #62121

Change-Id: I1d3534e5001ca185bc8ba5a7ed4ddbc00f85a17e
GitHub-Last-Rev: c0209f8c50e14477069592bfeb161011e7f9e80a
GitHub-Pull-Request: golang/go#75409
Reviewed-on: https://go-review.googlesource.com/c/go/+/702735
Reviewed-by: Mark Freeman <markfreeman@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Auto-Submit: Michael Pratt <mpratt@google.com>
Reviewed-by: Daniel Martí <mvdan@mvdan.cc>
Reviewed-by: Michael Pratt <mpratt@google.com>
src/encoding/gob/dec_helpers.go
src/encoding/gob/decgen.go
src/encoding/gob/decode.go
src/encoding/gob/enc_helpers.go
src/encoding/gob/encgen.go
src/encoding/gob/encode.go

index 44a74e24427987ae504bf77531659ae757c906df..e8696830e55486b38b011e6fe8f396ff274062a0 100644 (file)
@@ -58,7 +58,7 @@ func decBoolArray(state *decoderState, v reflect.Value, length int, ovfl error)
 }
 
 func decBoolSlice(state *decoderState, v reflect.Value, length int, ovfl error) bool {
-       slice, ok := v.Interface().([]bool)
+       slice, ok := reflect.TypeAssert[[]bool](v)
        if !ok {
                // It is kind bool but not type bool. TODO: We can handle this unsafely.
                return false
@@ -85,7 +85,7 @@ func decComplex64Array(state *decoderState, v reflect.Value, length int, ovfl er
 }
 
 func decComplex64Slice(state *decoderState, v reflect.Value, length int, ovfl error) bool {
-       slice, ok := v.Interface().([]complex64)
+       slice, ok := reflect.TypeAssert[[]complex64](v)
        if !ok {
                // It is kind complex64 but not type complex64. TODO: We can handle this unsafely.
                return false
@@ -114,7 +114,7 @@ func decComplex128Array(state *decoderState, v reflect.Value, length int, ovfl e
 }
 
 func decComplex128Slice(state *decoderState, v reflect.Value, length int, ovfl error) bool {
-       slice, ok := v.Interface().([]complex128)
+       slice, ok := reflect.TypeAssert[[]complex128](v)
        if !ok {
                // It is kind complex128 but not type complex128. TODO: We can handle this unsafely.
                return false
@@ -143,7 +143,7 @@ func decFloat32Array(state *decoderState, v reflect.Value, length int, ovfl erro
 }
 
 func decFloat32Slice(state *decoderState, v reflect.Value, length int, ovfl error) bool {
-       slice, ok := v.Interface().([]float32)
+       slice, ok := reflect.TypeAssert[[]float32](v)
        if !ok {
                // It is kind float32 but not type float32. TODO: We can handle this unsafely.
                return false
@@ -170,7 +170,7 @@ func decFloat64Array(state *decoderState, v reflect.Value, length int, ovfl erro
 }
 
 func decFloat64Slice(state *decoderState, v reflect.Value, length int, ovfl error) bool {
-       slice, ok := v.Interface().([]float64)
+       slice, ok := reflect.TypeAssert[[]float64](v)
        if !ok {
                // It is kind float64 but not type float64. TODO: We can handle this unsafely.
                return false
@@ -197,7 +197,7 @@ func decIntArray(state *decoderState, v reflect.Value, length int, ovfl error) b
 }
 
 func decIntSlice(state *decoderState, v reflect.Value, length int, ovfl error) bool {
-       slice, ok := v.Interface().([]int)
+       slice, ok := reflect.TypeAssert[[]int](v)
        if !ok {
                // It is kind int but not type int. TODO: We can handle this unsafely.
                return false
@@ -229,7 +229,7 @@ func decInt16Array(state *decoderState, v reflect.Value, length int, ovfl error)
 }
 
 func decInt16Slice(state *decoderState, v reflect.Value, length int, ovfl error) bool {
-       slice, ok := v.Interface().([]int16)
+       slice, ok := reflect.TypeAssert[[]int16](v)
        if !ok {
                // It is kind int16 but not type int16. TODO: We can handle this unsafely.
                return false
@@ -260,7 +260,7 @@ func decInt32Array(state *decoderState, v reflect.Value, length int, ovfl error)
 }
 
 func decInt32Slice(state *decoderState, v reflect.Value, length int, ovfl error) bool {
-       slice, ok := v.Interface().([]int32)
+       slice, ok := reflect.TypeAssert[[]int32](v)
        if !ok {
                // It is kind int32 but not type int32. TODO: We can handle this unsafely.
                return false
@@ -291,7 +291,7 @@ func decInt64Array(state *decoderState, v reflect.Value, length int, ovfl error)
 }
 
 func decInt64Slice(state *decoderState, v reflect.Value, length int, ovfl error) bool {
-       slice, ok := v.Interface().([]int64)
+       slice, ok := reflect.TypeAssert[[]int64](v)
        if !ok {
                // It is kind int64 but not type int64. TODO: We can handle this unsafely.
                return false
@@ -318,7 +318,7 @@ func decInt8Array(state *decoderState, v reflect.Value, length int, ovfl error)
 }
 
 func decInt8Slice(state *decoderState, v reflect.Value, length int, ovfl error) bool {
-       slice, ok := v.Interface().([]int8)
+       slice, ok := reflect.TypeAssert[[]int8](v)
        if !ok {
                // It is kind int8 but not type int8. TODO: We can handle this unsafely.
                return false
@@ -349,7 +349,7 @@ func decStringArray(state *decoderState, v reflect.Value, length int, ovfl error
 }
 
 func decStringSlice(state *decoderState, v reflect.Value, length int, ovfl error) bool {
-       slice, ok := v.Interface().([]string)
+       slice, ok := reflect.TypeAssert[[]string](v)
        if !ok {
                // It is kind string but not type string. TODO: We can handle this unsafely.
                return false
@@ -390,7 +390,7 @@ func decUintArray(state *decoderState, v reflect.Value, length int, ovfl error)
 }
 
 func decUintSlice(state *decoderState, v reflect.Value, length int, ovfl error) bool {
-       slice, ok := v.Interface().([]uint)
+       slice, ok := reflect.TypeAssert[[]uint](v)
        if !ok {
                // It is kind uint but not type uint. TODO: We can handle this unsafely.
                return false
@@ -421,7 +421,7 @@ func decUint16Array(state *decoderState, v reflect.Value, length int, ovfl error
 }
 
 func decUint16Slice(state *decoderState, v reflect.Value, length int, ovfl error) bool {
-       slice, ok := v.Interface().([]uint16)
+       slice, ok := reflect.TypeAssert[[]uint16](v)
        if !ok {
                // It is kind uint16 but not type uint16. TODO: We can handle this unsafely.
                return false
@@ -452,7 +452,7 @@ func decUint32Array(state *decoderState, v reflect.Value, length int, ovfl error
 }
 
 func decUint32Slice(state *decoderState, v reflect.Value, length int, ovfl error) bool {
-       slice, ok := v.Interface().([]uint32)
+       slice, ok := reflect.TypeAssert[[]uint32](v)
        if !ok {
                // It is kind uint32 but not type uint32. TODO: We can handle this unsafely.
                return false
@@ -483,7 +483,7 @@ func decUint64Array(state *decoderState, v reflect.Value, length int, ovfl error
 }
 
 func decUint64Slice(state *decoderState, v reflect.Value, length int, ovfl error) bool {
-       slice, ok := v.Interface().([]uint64)
+       slice, ok := reflect.TypeAssert[[]uint64](v)
        if !ok {
                // It is kind uint64 but not type uint64. TODO: We can handle this unsafely.
                return false
@@ -510,7 +510,7 @@ func decUintptrArray(state *decoderState, v reflect.Value, length int, ovfl erro
 }
 
 func decUintptrSlice(state *decoderState, v reflect.Value, length int, ovfl error) bool {
-       slice, ok := v.Interface().([]uintptr)
+       slice, ok := reflect.TypeAssert[[]uintptr](v)
        if !ok {
                // It is kind uintptr but not type uintptr. TODO: We can handle this unsafely.
                return false
index af4cdbee9dfd11a3e318406f6a25947c27985057..420c86207c200ed58f710650a0181634c7fea008 100644 (file)
@@ -231,7 +231,7 @@ func dec%[2]sArray(state *decoderState, v reflect.Value, length int, ovfl error)
 
 const sliceHelper = `
 func dec%[2]sSlice(state *decoderState, v reflect.Value, length int, ovfl error) bool {
-       slice, ok := v.Interface().([]%[1]s)
+       slice, ok := reflect.TypeAssert[[]%[1]s](v)
        if !ok {
                // It is kind %[1]s but not type %[1]s. TODO: We can handle this unsafely.
                return false
index 26b5f6d62b631e30cda1ee212130455a21e91492..fb7837b11b2bb21042fd372f0c52f9f90439cb3c 100644 (file)
@@ -768,11 +768,14 @@ func (dec *Decoder) decodeGobDecoder(ut *userTypeInfo, state *decoderState, valu
        // We know it's one of these.
        switch ut.externalDec {
        case xGob:
-               err = value.Interface().(GobDecoder).GobDecode(b)
+               gobDecoder, _ := reflect.TypeAssert[GobDecoder](value)
+               err = gobDecoder.GobDecode(b)
        case xBinary:
-               err = value.Interface().(encoding.BinaryUnmarshaler).UnmarshalBinary(b)
+               binaryUnmarshaler, _ := reflect.TypeAssert[encoding.BinaryUnmarshaler](value)
+               err = binaryUnmarshaler.UnmarshalBinary(b)
        case xText:
-               err = value.Interface().(encoding.TextUnmarshaler).UnmarshalText(b)
+               textUnmarshaler, _ := reflect.TypeAssert[encoding.TextUnmarshaler](value)
+               err = textUnmarshaler.UnmarshalText(b)
        }
        if err != nil {
                error_(err)
index c3b4ca8972a68630c1c53d053b10f25e6dcbb3a4..a9c45a46690e5ecbeb6ab188d20136ea87b1ee15 100644 (file)
@@ -57,7 +57,7 @@ func encBoolArray(state *encoderState, v reflect.Value) bool {
 }
 
 func encBoolSlice(state *encoderState, v reflect.Value) bool {
-       slice, ok := v.Interface().([]bool)
+       slice, ok := reflect.TypeAssert[[]bool](v)
        if !ok {
                // It is kind bool but not type bool. TODO: We can handle this unsafely.
                return false
@@ -83,7 +83,7 @@ func encComplex64Array(state *encoderState, v reflect.Value) bool {
 }
 
 func encComplex64Slice(state *encoderState, v reflect.Value) bool {
-       slice, ok := v.Interface().([]complex64)
+       slice, ok := reflect.TypeAssert[[]complex64](v)
        if !ok {
                // It is kind complex64 but not type complex64. TODO: We can handle this unsafely.
                return false
@@ -108,7 +108,7 @@ func encComplex128Array(state *encoderState, v reflect.Value) bool {
 }
 
 func encComplex128Slice(state *encoderState, v reflect.Value) bool {
-       slice, ok := v.Interface().([]complex128)
+       slice, ok := reflect.TypeAssert[[]complex128](v)
        if !ok {
                // It is kind complex128 but not type complex128. TODO: We can handle this unsafely.
                return false
@@ -133,7 +133,7 @@ func encFloat32Array(state *encoderState, v reflect.Value) bool {
 }
 
 func encFloat32Slice(state *encoderState, v reflect.Value) bool {
-       slice, ok := v.Interface().([]float32)
+       slice, ok := reflect.TypeAssert[[]float32](v)
        if !ok {
                // It is kind float32 but not type float32. TODO: We can handle this unsafely.
                return false
@@ -156,7 +156,7 @@ func encFloat64Array(state *encoderState, v reflect.Value) bool {
 }
 
 func encFloat64Slice(state *encoderState, v reflect.Value) bool {
-       slice, ok := v.Interface().([]float64)
+       slice, ok := reflect.TypeAssert[[]float64](v)
        if !ok {
                // It is kind float64 but not type float64. TODO: We can handle this unsafely.
                return false
@@ -179,7 +179,7 @@ func encIntArray(state *encoderState, v reflect.Value) bool {
 }
 
 func encIntSlice(state *encoderState, v reflect.Value) bool {
-       slice, ok := v.Interface().([]int)
+       slice, ok := reflect.TypeAssert[[]int](v)
        if !ok {
                // It is kind int but not type int. TODO: We can handle this unsafely.
                return false
@@ -201,7 +201,7 @@ func encInt16Array(state *encoderState, v reflect.Value) bool {
 }
 
 func encInt16Slice(state *encoderState, v reflect.Value) bool {
-       slice, ok := v.Interface().([]int16)
+       slice, ok := reflect.TypeAssert[[]int16](v)
        if !ok {
                // It is kind int16 but not type int16. TODO: We can handle this unsafely.
                return false
@@ -223,7 +223,7 @@ func encInt32Array(state *encoderState, v reflect.Value) bool {
 }
 
 func encInt32Slice(state *encoderState, v reflect.Value) bool {
-       slice, ok := v.Interface().([]int32)
+       slice, ok := reflect.TypeAssert[[]int32](v)
        if !ok {
                // It is kind int32 but not type int32. TODO: We can handle this unsafely.
                return false
@@ -245,7 +245,7 @@ func encInt64Array(state *encoderState, v reflect.Value) bool {
 }
 
 func encInt64Slice(state *encoderState, v reflect.Value) bool {
-       slice, ok := v.Interface().([]int64)
+       slice, ok := reflect.TypeAssert[[]int64](v)
        if !ok {
                // It is kind int64 but not type int64. TODO: We can handle this unsafely.
                return false
@@ -267,7 +267,7 @@ func encInt8Array(state *encoderState, v reflect.Value) bool {
 }
 
 func encInt8Slice(state *encoderState, v reflect.Value) bool {
-       slice, ok := v.Interface().([]int8)
+       slice, ok := reflect.TypeAssert[[]int8](v)
        if !ok {
                // It is kind int8 but not type int8. TODO: We can handle this unsafely.
                return false
@@ -289,7 +289,7 @@ func encStringArray(state *encoderState, v reflect.Value) bool {
 }
 
 func encStringSlice(state *encoderState, v reflect.Value) bool {
-       slice, ok := v.Interface().([]string)
+       slice, ok := reflect.TypeAssert[[]string](v)
        if !ok {
                // It is kind string but not type string. TODO: We can handle this unsafely.
                return false
@@ -312,7 +312,7 @@ func encUintArray(state *encoderState, v reflect.Value) bool {
 }
 
 func encUintSlice(state *encoderState, v reflect.Value) bool {
-       slice, ok := v.Interface().([]uint)
+       slice, ok := reflect.TypeAssert[[]uint](v)
        if !ok {
                // It is kind uint but not type uint. TODO: We can handle this unsafely.
                return false
@@ -334,7 +334,7 @@ func encUint16Array(state *encoderState, v reflect.Value) bool {
 }
 
 func encUint16Slice(state *encoderState, v reflect.Value) bool {
-       slice, ok := v.Interface().([]uint16)
+       slice, ok := reflect.TypeAssert[[]uint16](v)
        if !ok {
                // It is kind uint16 but not type uint16. TODO: We can handle this unsafely.
                return false
@@ -356,7 +356,7 @@ func encUint32Array(state *encoderState, v reflect.Value) bool {
 }
 
 func encUint32Slice(state *encoderState, v reflect.Value) bool {
-       slice, ok := v.Interface().([]uint32)
+       slice, ok := reflect.TypeAssert[[]uint32](v)
        if !ok {
                // It is kind uint32 but not type uint32. TODO: We can handle this unsafely.
                return false
@@ -378,7 +378,7 @@ func encUint64Array(state *encoderState, v reflect.Value) bool {
 }
 
 func encUint64Slice(state *encoderState, v reflect.Value) bool {
-       slice, ok := v.Interface().([]uint64)
+       slice, ok := reflect.TypeAssert[[]uint64](v)
        if !ok {
                // It is kind uint64 but not type uint64. TODO: We can handle this unsafely.
                return false
@@ -400,7 +400,7 @@ func encUintptrArray(state *encoderState, v reflect.Value) bool {
 }
 
 func encUintptrSlice(state *encoderState, v reflect.Value) bool {
-       slice, ok := v.Interface().([]uintptr)
+       slice, ok := reflect.TypeAssert[[]uintptr](v)
        if !ok {
                // It is kind uintptr but not type uintptr. TODO: We can handle this unsafely.
                return false
index 64f5c69bd44dfef86a671efc4d9db7579d4503f3..b89fa47ef6c6a6a271232daba2f09804b0e1c0a1 100644 (file)
@@ -208,7 +208,7 @@ func enc%[2]sArray(state *encoderState, v reflect.Value) bool {
 
 const sliceHelper = `
 func enc%[2]sSlice(state *encoderState, v reflect.Value) bool {
-       slice, ok := v.Interface().([]%[1]s)
+       slice, ok := reflect.TypeAssert[[]%[1]s](v)
        if !ok {
                // It is kind %[1]s but not type %[1]s. TODO: We can handle this unsafely.
                return false
index ed3494218ce70efc4027167662519bf1a7837358..15932aabe0b990a5780aa3e3eac547687e23e63e 100644 (file)
@@ -440,11 +440,14 @@ func (enc *Encoder) encodeGobEncoder(b *encBuffer, ut *userTypeInfo, v reflect.V
        // We know it's one of these.
        switch ut.externalEnc {
        case xGob:
-               data, err = v.Interface().(GobEncoder).GobEncode()
+               gobEncoder, _ := reflect.TypeAssert[GobEncoder](v)
+               data, err = gobEncoder.GobEncode()
        case xBinary:
-               data, err = v.Interface().(encoding.BinaryMarshaler).MarshalBinary()
+               binaryMarshaler, _ := reflect.TypeAssert[encoding.BinaryMarshaler](v)
+               data, err = binaryMarshaler.MarshalBinary()
        case xText:
-               data, err = v.Interface().(encoding.TextMarshaler).MarshalText()
+               textMarshaler, _ := reflect.TypeAssert[encoding.TextMarshaler](v)
+               data, err = textMarshaler.MarshalText()
        }
        if err != nil {
                error_(err)