]> Cypherpunks.ru repositories - gostls13.git/commitdiff
reflect: add Value.{Comparable,Equal}
authorcuiweixie <cuiweixie@gmail.com>
Sun, 14 Aug 2022 08:45:33 +0000 (16:45 +0800)
committerGopher Robot <gobot@golang.org>
Fri, 26 Aug 2022 20:56:48 +0000 (20:56 +0000)
For #46746

Change-Id: I879124974cdb55932cd9d07d3b384d49d5059857
Reviewed-on: https://go-review.googlesource.com/c/go/+/423794
Reviewed-by: Cherry Mui <cherryyz@google.com>
Run-TryBot: Dmitri Shuralyov <dmitshur@golang.org>
TryBot-Result: Gopher Robot <gobot@golang.org>
Reviewed-by: Dmitri Shuralyov <dmitshur@google.com>
Auto-Submit: Dmitri Shuralyov <dmitshur@golang.org>
Reviewed-by: Ian Lance Taylor <iant@google.com>
api/next/46746.txt [new file with mode: 0644]
src/reflect/all_test.go
src/reflect/value.go

diff --git a/api/next/46746.txt b/api/next/46746.txt
new file mode 100644 (file)
index 0000000..ae07682
--- /dev/null
@@ -0,0 +1,2 @@
+pkg reflect, method (Value) Comparable() bool #46746
+pkg reflect, method (Value) Equal(Value) bool #46746
\ No newline at end of file
index fe624074121512b4969a631623bf735f79964e52..0398a5099d06edc110d17c47aa53f9fce3a13c65 100644 (file)
@@ -8214,3 +8214,366 @@ func TestValue_Len(t *testing.T) {
                t.Errorf("error is %q, want %q", e, wantStr)
        }
 }
+
+func TestValue_Comparable(t *testing.T) {
+       var a int
+       var s []int
+       var i interface{} = a
+       var iSlice interface{} = s
+       var iArrayFalse interface{} = [2]interface{}{1, map[int]int{}}
+       var iArrayTrue interface{} = [2]interface{}{1, struct{ I interface{} }{1}}
+       var testcases = []struct {
+               value      Value
+               comparable bool
+               deref      bool
+       }{
+               {
+                       ValueOf(32),
+                       true,
+                       false,
+               },
+               {
+                       ValueOf(int8(1)),
+                       true,
+                       false,
+               },
+               {
+                       ValueOf(int16(1)),
+                       true,
+                       false,
+               },
+               {
+                       ValueOf(int32(1)),
+                       true,
+                       false,
+               },
+               {
+                       ValueOf(int64(1)),
+                       true,
+                       false,
+               },
+               {
+                       ValueOf(uint8(1)),
+                       true,
+                       false,
+               },
+               {
+                       ValueOf(uint16(1)),
+                       true,
+                       false,
+               },
+               {
+                       ValueOf(uint32(1)),
+                       true,
+                       false,
+               },
+               {
+                       ValueOf(uint64(1)),
+                       true,
+                       false,
+               },
+               {
+                       ValueOf(float32(1)),
+                       true,
+                       false,
+               },
+               {
+                       ValueOf(float64(1)),
+                       true,
+                       false,
+               },
+               {
+                       ValueOf(complex(float32(1), float32(1))),
+                       true,
+                       false,
+               },
+               {
+                       ValueOf(complex(float64(1), float64(1))),
+                       true,
+                       false,
+               },
+               {
+                       ValueOf("abc"),
+                       true,
+                       false,
+               },
+               {
+                       ValueOf(true),
+                       true,
+                       false,
+               },
+               {
+                       ValueOf(map[int]int{}),
+                       false,
+                       false,
+               },
+               {
+                       ValueOf([]int{}),
+                       false,
+                       false,
+               },
+               {
+                       Value{},
+                       false,
+                       false,
+               },
+               {
+                       ValueOf(&a),
+                       true,
+                       false,
+               },
+               {
+                       ValueOf(&s),
+                       true,
+                       false,
+               },
+               {
+                       ValueOf(&i),
+                       true,
+                       true,
+               },
+               {
+                       ValueOf(&iSlice),
+                       false,
+                       true,
+               },
+               {
+                       ValueOf([2]int{}),
+                       true,
+                       false,
+               },
+               {
+                       ValueOf([2]map[int]int{}),
+                       false,
+                       false,
+               },
+               {
+                       ValueOf([0]func(){}),
+                       false,
+                       false,
+               },
+               {
+                       ValueOf([2]struct{ I interface{} }{{1}, {1}}),
+                       true,
+                       false,
+               },
+               {
+                       ValueOf([2]struct{ I interface{} }{{[]int{}}, {1}}),
+                       false,
+                       false,
+               },
+               {
+                       ValueOf([2]interface{}{1, struct{ I int }{1}}),
+                       true,
+                       false,
+               },
+               {
+                       ValueOf([2]interface{}{[1]interface{}{map[int]int{}}, struct{ I int }{1}}),
+                       false,
+                       false,
+               },
+               {
+                       ValueOf(&iArrayFalse),
+                       false,
+                       true,
+               },
+               {
+                       ValueOf(&iArrayTrue),
+                       true,
+                       true,
+               },
+       }
+
+       for _, cas := range testcases {
+               v := cas.value
+               if cas.deref {
+                       v = v.Elem()
+               }
+               got := v.Comparable()
+               if got != cas.comparable {
+                       t.Errorf("%T.Comparable = %t, want %t", v, got, cas.comparable)
+               }
+       }
+}
+
+type ValueEqualTest struct {
+       v, u           any
+       eq             bool
+       vDeref, uDeref bool
+}
+
+var equalI interface{} = 1
+var equalSlice interface{} = []int{1}
+var nilInterface interface{}
+var mapInterface interface{} = map[int]int{}
+
+var valueEqualTests = []ValueEqualTest{
+       {
+               Value{}, Value{},
+               true,
+               false, false,
+       },
+       {
+               true, true,
+               true,
+               false, false,
+       },
+       {
+               1, 1,
+               true,
+               false, false,
+       },
+       {
+               int8(1), int8(1),
+               true,
+               false, false,
+       },
+       {
+               int16(1), int16(1),
+               true,
+               false, false,
+       },
+       {
+               int32(1), int32(1),
+               true,
+               false, false,
+       },
+       {
+               int64(1), int64(1),
+               true,
+               false, false,
+       },
+       {
+               uint(1), uint(1),
+               true,
+               false, false,
+       },
+       {
+               uint8(1), uint8(1),
+               true,
+               false, false,
+       },
+       {
+               uint16(1), uint16(1),
+               true,
+               false, false,
+       },
+       {
+               uint32(1), uint32(1),
+               true,
+               false, false,
+       },
+       {
+               uint64(1), uint64(1),
+               true,
+               false, false,
+       },
+       {
+               float32(1), float32(1),
+               true,
+               false, false,
+       },
+       {
+               float64(1), float64(1),
+               true,
+               false, false,
+       },
+       {
+               complex(1, 1), complex(1, 1),
+               true,
+               false, false,
+       },
+       {
+               complex128(1 + 1i), complex128(1 + 1i),
+               true,
+               false, false,
+       },
+       {
+               func() {}, nil,
+               false,
+               false, false,
+       },
+       {
+               &equalI, 1,
+               true,
+               true, false,
+       },
+       {
+               &equalSlice, []int{1},
+               false,
+               true, false,
+       },
+       {
+               map[int]int{}, map[int]int{},
+               false,
+               false, false,
+       },
+       {
+               (chan int)(nil), nil,
+               false,
+               false, false,
+       },
+       {
+               (chan int)(nil), (chan int)(nil),
+               true,
+               false, false,
+       },
+       {
+               &equalI, &equalI,
+               true,
+               false, false,
+       },
+       {
+               struct{ i int }{1}, struct{ i int }{1},
+               true,
+               false, false,
+       },
+       {
+               struct{ i int }{1}, struct{ i int }{2},
+               false,
+               false, false,
+       },
+       {
+               &nilInterface, &nilInterface,
+               true,
+               true, true,
+       },
+       {
+               1, ValueOf(struct{ i int }{1}).Field(0),
+               true,
+               false, false,
+       },
+       {
+               &mapInterface, &mapInterface,
+               false,
+               true, true,
+       },
+}
+
+func TestValue_Equal(t *testing.T) {
+       for _, test := range valueEqualTests {
+               var v, u Value
+               if vv, ok := test.v.(Value); ok {
+                       v = vv
+               } else {
+                       v = ValueOf(test.v)
+               }
+
+               if uu, ok := test.u.(Value); ok {
+                       u = uu
+               } else {
+                       u = ValueOf(test.u)
+               }
+               if test.vDeref {
+                       v = v.Elem()
+               }
+
+               if test.uDeref {
+                       u = u.Elem()
+               }
+
+               if r := v.Equal(u); r != test.eq {
+                       t.Errorf("%s == %s got %t, want %t", v.Type(), u.Type(), r, test.eq)
+               }
+       }
+}
index 6ab6cc8b232a75d66564b8bce973ef4eeaa68185..9c8b82c41e5816116b863f342675a6625e09e469 100644 (file)
@@ -3246,6 +3246,92 @@ func (v Value) CanConvert(t Type) bool {
        return true
 }
 
+// Comparable reports whether the type of v is comparable.
+// If the type of v is an interface, this checks the dynamic type.
+// If this reports true then v.Interface() == x will not panic for any x.
+func (v Value) Comparable() bool {
+       k := v.Kind()
+       switch k {
+       case Invalid:
+               return false
+
+       case Bool,
+               Int, Int8, Int16, Int32, Int64,
+               Uint, Uint8, Uint16, Uint32, Uint64,
+               Uintptr,
+               Float32, Float64, Complex64, Complex128,
+               Chan:
+               return true
+
+       case Array:
+               if v.Type().Len() == 0 {
+                       return v.Type().Comparable()
+               }
+
+               switch v.Type().Elem().Kind() {
+               case Interface, Array, Struct:
+                       for i := 0; i < v.Type().Len(); i++ {
+                               if !v.Index(i).Comparable() {
+                                       return false
+                               }
+                       }
+               default:
+                       return v.Index(0).Comparable()
+               }
+
+               return true
+
+       case Func:
+               return false
+
+       case Interface:
+               return v.Elem().Comparable()
+
+       case Map:
+               return false
+
+       case Pointer:
+               return true
+
+       case Slice:
+               return false
+
+       case String:
+               return true
+
+       case Struct:
+               for i := 0; i < v.NumField(); i++ {
+                       if !v.Field(i).Comparable() {
+                               return false
+                       }
+               }
+               return true
+
+       case UnsafePointer:
+               return true
+
+       default:
+               return false
+       }
+}
+
+// Equal reports true if v is equal to u.
+func (v Value) Equal(u Value) bool {
+       if !v.IsValid() || !u.IsValid() {
+               return v.IsValid() == u.IsValid()
+       }
+
+       if v.Comparable() || u.Comparable() {
+               return valueInterface(v, false) == valueInterface(u, false)
+       }
+
+       if u.Kind() == Interface && v.kind() == Interface { // this case is for nil interface value
+               return v.Elem().Equal(u.Elem())
+       }
+
+       return false
+}
+
 // convertOp returns the function to convert a value of type src
 // to a value of type dst. If the conversion is illegal, convertOp returns nil.
 func convertOp(dst, src *rtype) func(Value, Type) Value {