github.com/xyproto/u-root@v6.0.1-0.20200302025726-5528e0c77a3c+incompatible/cmds/core/elvish/eval/vals/equal.go (about) 1 package vals 2 3 import ( 4 "reflect" 5 6 "github.com/u-root/u-root/cmds/core/elvish/hashmap" 7 ) 8 9 // Equaler wraps the Equal method. 10 type Equaler interface { 11 // Equal compares the receiver to another value. Two equal values must have 12 // the same hash code. 13 Equal(other interface{}) bool 14 } 15 16 // Equal returns whether two values are equal. It is implemented for the builtin 17 // types bool and string, and types satisfying the listEqualable, mapEqualable 18 // or Equaler interface. For other types, it uses reflect.DeepEqual to compare 19 // the two values. 20 func Equal(x, y interface{}) bool { 21 switch x := x.(type) { 22 case Equaler: 23 return x.Equal(y) 24 case bool: 25 return x == y 26 case string: 27 return x == y 28 case listEqualable: 29 if yy, ok := y.(listEqualable); ok { 30 return equalList(x, yy) 31 } 32 return false 33 case mapEqualable: 34 if yy, ok := y.(mapEqualable); ok { 35 return equalMap(x, yy) 36 } 37 return false 38 } 39 return reflect.DeepEqual(x, y) 40 } 41 42 type listEqualable interface { 43 Lener 44 listIterable 45 } 46 47 func equalList(x, y listEqualable) bool { 48 if x.Len() != y.Len() { 49 return false 50 } 51 ix := x.Iterator() 52 iy := y.Iterator() 53 for ix.HasElem() && iy.HasElem() { 54 if !Equal(ix.Elem(), iy.Elem()) { 55 return false 56 } 57 ix.Next() 58 iy.Next() 59 } 60 return true 61 } 62 63 type mapEqualable interface { 64 Lener 65 Index(interface{}) (interface{}, bool) 66 Iterator() hashmap.Iterator 67 } 68 69 var _ mapEqualable = hashmap.Map(nil) 70 71 func equalMap(x, y mapEqualable) bool { 72 if x.Len() != y.Len() { 73 return false 74 } 75 for it := x.Iterator(); it.HasElem(); it.Next() { 76 k, vx := it.Elem() 77 vy, ok := y.Index(k) 78 if !ok || !Equal(vx, vy) { 79 return false 80 } 81 } 82 return true 83 }