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