]> Cypherpunks.ru repositories - gostls13.git/commitdiff
errors: optimize Is and As by reusing reflection of target
authorj178 <sherlockjoe8@gmail.com>
Fri, 18 Aug 2023 04:04:35 +0000 (12:04 +0800)
committerGopher Robot <gobot@golang.org>
Fri, 18 Aug 2023 23:40:44 +0000 (23:40 +0000)
goos: darwin
goarch: amd64
pkg: errors
cpu: Intel(R) Core(TM) i7-9750H CPU @ 2.60GHz
        │     old     │                 new                 │
        │   sec/op    │   sec/op     vs base                │
Is-12     133.4n ± 0%   126.8n ± 3%   -4.91% (p=0.001 n=10)
As-12     464.1n ± 1%   307.2n ± 0%  -33.80% (p=0.000 n=10)
geomean   248.8n        197.4n       -20.66%

        │    old     │                 new                 │
        │    B/op    │    B/op     vs base                 │
Is-12     24.00 ± 0%   24.00 ± 0%       ~ (p=1.000 n=10) ¹
As-12     40.00 ± 0%   40.00 ± 0%       ~ (p=1.000 n=10) ¹
geomean   30.98        30.98       +0.00%
¹ all samples are equal

        │    old     │                 new                 │
        │ allocs/op  │ allocs/op   vs base                 │
Is-12     1.000 ± 0%   1.000 ± 0%       ~ (p=1.000 n=10) ¹
As-12     2.000 ± 0%   2.000 ± 0%       ~ (p=1.000 n=10) ¹
geomean   1.414        1.414       +0.00%
¹ all samples are equal

Change-Id: I0844f3ab77e63b5f773594157dcffaffffd5e70d
Reviewed-on: https://go-review.googlesource.com/c/go/+/520756
Run-TryBot: Ian Lance Taylor <iant@google.com>
Run-TryBot: Ian Lance Taylor <iant@golang.org>
TryBot-Result: Gopher Robot <gobot@golang.org>
Reviewed-by: Ian Lance Taylor <iant@google.com>
Auto-Submit: Ian Lance Taylor <iant@google.com>
Reviewed-by: Dmitri Shuralyov <dmitshur@google.com>
src/errors/wrap.go
src/errors/wrap_test.go

index 2c934eed5af408ccb248f5d59f1d518a4f937f96..756de6cc1c565a0467c3e915e3a45b6f1bedd3f0 100644 (file)
@@ -47,8 +47,12 @@ func Is(err, target error) bool {
        }
 
        isComparable := reflectlite.TypeOf(target).Comparable()
+       return is(err, target, isComparable)
+}
+
+func is(err, target error, targetComparable bool) bool {
        for {
-               if isComparable && err == target {
+               if targetComparable && err == target {
                        return true
                }
                if x, ok := err.(interface{ Is(error) bool }); ok && x.Is(target) {
@@ -62,7 +66,7 @@ func Is(err, target error) bool {
                        }
                case interface{ Unwrap() []error }:
                        for _, err := range x.Unwrap() {
-                               if Is(err, target) {
+                               if is(err, target, targetComparable) {
                                        return true
                                }
                        }
@@ -106,9 +110,13 @@ func As(err error, target any) bool {
        if targetType.Kind() != reflectlite.Interface && !targetType.Implements(errorType) {
                panic("errors: *target must be interface or implement error")
        }
+       return as(err, target, val, targetType)
+}
+
+func as(err error, target any, targetVal reflectlite.Value, targetType reflectlite.Type) bool {
        for {
                if reflectlite.TypeOf(err).AssignableTo(targetType) {
-                       val.Elem().Set(reflectlite.ValueOf(err))
+                       targetVal.Elem().Set(reflectlite.ValueOf(err))
                        return true
                }
                if x, ok := err.(interface{ As(any) bool }); ok && x.As(target) {
@@ -122,7 +130,10 @@ func As(err error, target any) bool {
                        }
                case interface{ Unwrap() []error }:
                        for _, err := range x.Unwrap() {
-                               if As(err, target) {
+                               if err == nil {
+                                       continue
+                               }
+                               if as(err, target, targetVal, targetType) {
                                        return true
                                }
                        }
index ca9dc0f111c9cc8c0f414f12d88ad36a1bb1247d..0a7bc5d16a1344c87cb7c802cd5c9fb6726dd1c8 100644 (file)
@@ -238,6 +238,27 @@ func TestAsValidation(t *testing.T) {
        }
 }
 
+func BenchmarkIs(b *testing.B) {
+       err1 := errors.New("1")
+       err2 := multiErr{multiErr{multiErr{err1, errorT{"a"}}, errorT{"b"}}}
+
+       for i := 0; i < b.N; i++ {
+               if !errors.Is(err2, err1) {
+                       b.Fatal("Is failed")
+               }
+       }
+}
+
+func BenchmarkAs(b *testing.B) {
+       err := multiErr{multiErr{multiErr{errors.New("a"), errorT{"a"}}, errorT{"b"}}}
+       for i := 0; i < b.N; i++ {
+               var target errorT
+               if !errors.As(err, &target) {
+                       b.Fatal("As failed")
+               }
+       }
+}
+
 func TestUnwrap(t *testing.T) {
        err1 := errors.New("1")
        erra := wrapped{"wrap 2", err1}