aboutsummaryrefslogtreecommitdiff
path: root/src/encoding
diff options
context:
space:
mode:
authorDmitrii Okunev <xaionaro@gmail.com>2019-12-31 20:39:14 +0000
committerFilippo Valsorda <filippo@golang.org>2020-11-09 21:36:24 +0000
commitd36169120199e7f2b8c517fa6d82333496bb0a0a (patch)
tree66966e0976e2783d3a404ea494d7f6db762ba8b0 /src/encoding
parentd4957122ee8a45aa73b0e8700d3a41c0ee9f4442 (diff)
downloadgo-d36169120199e7f2b8c517fa6d82333496bb0a0a.tar.gz
go-d36169120199e7f2b8c517fa6d82333496bb0a0a.zip
encoding/asn1: optimize asn1.Unmarshal
Used type-switch instead of switch by reflect.Type and added BenchmarkUnmarshal. name old time/op new time/op delta Marshal-8 28.1µs ± 2% 27.9µs ± 1% ~ (p=0.094 n=9+9) Unmarshal-8 6.45µs ± 1% 5.83µs ± 4% -9.59% (p=0.000 n=10+10) name old alloc/op new alloc/op delta Marshal-8 8.26kB ± 0% 8.26kB ± 0% ~ (all equal) Unmarshal-8 840B ± 0% 488B ± 0% -41.90% (p=0.000 n=10+10) name old allocs/op new allocs/op delta Marshal-8 363 ± 0% 363 ± 0% ~ (all equal) Unmarshal-8 50.0 ± 0% 43.0 ± 0% -14.00% (p=0.000 n=10+10) Change-Id: I6b53833c7a3e2524f025453311841d03c1256a45 GitHub-Pull-Request: golang/go#36341 Reviewed-on: https://go-review.googlesource.com/c/go/+/268557 Trust: Filippo Valsorda <filippo@golang.org> Trust: Roland Shoemaker <roland@golang.org> Run-TryBot: Filippo Valsorda <filippo@golang.org> TryBot-Result: Go Bot <gobot@golang.org> Reviewed-by: Roland Shoemaker <roland@golang.org>
Diffstat (limited to 'src/encoding')
-rw-r--r--src/encoding/asn1/asn1.go50
-rw-r--r--src/encoding/asn1/marshal_test.go28
2 files changed, 45 insertions, 33 deletions
diff --git a/src/encoding/asn1/asn1.go b/src/encoding/asn1/asn1.go
index 068594e2a1..7c260b49d9 100644
--- a/src/encoding/asn1/asn1.go
+++ b/src/encoding/asn1/asn1.go
@@ -851,53 +851,37 @@ func parseField(v reflect.Value, bytes []byte, initOffset int, params fieldParam
offset += t.length
// We deal with the structures defined in this package first.
- switch fieldType {
- case rawValueType:
- result := RawValue{t.class, t.tag, t.isCompound, innerBytes, bytes[initOffset:offset]}
- v.Set(reflect.ValueOf(result))
+ switch v := v.Addr().Interface().(type) {
+ case *RawValue:
+ *v = RawValue{t.class, t.tag, t.isCompound, innerBytes, bytes[initOffset:offset]}
return
- case objectIdentifierType:
- newSlice, err1 := parseObjectIdentifier(innerBytes)
- v.Set(reflect.MakeSlice(v.Type(), len(newSlice), len(newSlice)))
- if err1 == nil {
- reflect.Copy(v, reflect.ValueOf(newSlice))
- }
- err = err1
+ case *ObjectIdentifier:
+ *v, err = parseObjectIdentifier(innerBytes)
return
- case bitStringType:
- bs, err1 := parseBitString(innerBytes)
- if err1 == nil {
- v.Set(reflect.ValueOf(bs))
- }
- err = err1
+ case *BitString:
+ *v, err = parseBitString(innerBytes)
return
- case timeType:
- var time time.Time
- var err1 error
+ case *time.Time:
if universalTag == TagUTCTime {
- time, err1 = parseUTCTime(innerBytes)
- } else {
- time, err1 = parseGeneralizedTime(innerBytes)
- }
- if err1 == nil {
- v.Set(reflect.ValueOf(time))
+ *v, err = parseUTCTime(innerBytes)
+ return
}
- err = err1
+ *v, err = parseGeneralizedTime(innerBytes)
return
- case enumeratedType:
+ case *Enumerated:
parsedInt, err1 := parseInt32(innerBytes)
if err1 == nil {
- v.SetInt(int64(parsedInt))
+ *v = Enumerated(parsedInt)
}
err = err1
return
- case flagType:
- v.SetBool(true)
+ case *Flag:
+ *v = true
return
- case bigIntType:
+ case **big.Int:
parsedInt, err1 := parseBigInt(innerBytes)
if err1 == nil {
- v.Set(reflect.ValueOf(parsedInt))
+ *v = parsedInt
}
err = err1
return
diff --git a/src/encoding/asn1/marshal_test.go b/src/encoding/asn1/marshal_test.go
index 529052285f..e3a7d8ff00 100644
--- a/src/encoding/asn1/marshal_test.go
+++ b/src/encoding/asn1/marshal_test.go
@@ -376,3 +376,31 @@ func TestSetEncoderSETSliceSuffix(t *testing.T) {
t.Errorf("Unexpected SET content. got: %s, want: %s", resultSet, expectedOrder)
}
}
+
+func BenchmarkUnmarshal(b *testing.B) {
+ b.ReportAllocs()
+
+ type testCase struct {
+ in []byte
+ out interface{}
+ }
+ var testData []testCase
+ for _, test := range unmarshalTestData {
+ pv := reflect.New(reflect.TypeOf(test.out).Elem())
+ inCopy := make([]byte, len(test.in))
+ copy(inCopy, test.in)
+ outCopy := pv.Interface()
+
+ testData = append(testData, testCase{
+ in: inCopy,
+ out: outCopy,
+ })
+ }
+
+ b.ResetTimer()
+ for i := 0; i < b.N; i++ {
+ for _, testCase := range testData {
+ _, _ = Unmarshal(testCase.in, testCase.out)
+ }
+ }
+}