src.elv.sh@v0.21.0-dev.0.20240515223629-06979efb9a2a/pkg/eval/vals/equal.go (about) 1 package vals 2 3 import ( 4 "math/big" 5 "reflect" 6 7 "src.elv.sh/pkg/persistent/hashmap" 8 ) 9 10 // Equaler wraps the Equal method. 11 type Equaler interface { 12 // Equal compares the receiver to another value. Two equal values must have 13 // the same hash code. 14 Equal(other any) bool 15 } 16 17 // Equal returns whether two values are equal. It is implemented for the builtin 18 // types bool and string, the File, List, Map types, StructMap types, and types 19 // satisfying the Equaler interface. For other types, it uses reflect.DeepEqual 20 // to compare the two values. 21 func Equal(x, y any) bool { 22 switch x := x.(type) { 23 case nil: 24 return x == y 25 case bool: 26 return x == y 27 case int: 28 return x == y 29 case *big.Int: 30 if y, ok := y.(*big.Int); ok { 31 return x.Cmp(y) == 0 32 } 33 return false 34 case *big.Rat: 35 if y, ok := y.(*big.Rat); ok { 36 return x.Cmp(y) == 0 37 } 38 return false 39 case float64: 40 return x == y 41 case string: 42 return x == y 43 case List: 44 if yy, ok := y.(List); ok { 45 return equalList(x, yy) 46 } 47 return false 48 // Types above are also handled in [Cmp]; keep the branches in the same 49 // order. 50 case Equaler: 51 return x.Equal(y) 52 case File: 53 if yy, ok := y.(File); ok { 54 return x.Fd() == yy.Fd() 55 } 56 return false 57 case Map: 58 switch y := y.(type) { 59 case Map: 60 return equalMap(x, y, Map.Iterator, Map.Index) 61 case StructMap: 62 return equalMap(x, y, Map.Iterator, indexStructMap) 63 } 64 return false 65 case StructMap: 66 switch y := y.(type) { 67 case Map: 68 return equalMap(x, y, iterateStructMap, Map.Index) 69 case StructMap: 70 return equalMap(x, y, iterateStructMap, indexStructMap) 71 } 72 return false 73 default: 74 return reflect.DeepEqual(x, y) 75 } 76 } 77 78 func equalList(x, y List) bool { 79 if x.Len() != y.Len() { 80 return false 81 } 82 ix := x.Iterator() 83 iy := y.Iterator() 84 for ix.HasElem() && iy.HasElem() { 85 if !Equal(ix.Elem(), iy.Elem()) { 86 return false 87 } 88 ix.Next() 89 iy.Next() 90 } 91 return true 92 } 93 94 func equalMap[X, Y any, I hashmap.Iterator](x X, y Y, xit func(X) I, yidx func(Y, any) (any, bool)) bool { 95 if Len(x) != Len(y) { 96 return false 97 } 98 for it := xit(x); it.HasElem(); it.Next() { 99 k, vx := it.Elem() 100 vy, ok := yidx(y, k) 101 if !ok || !Equal(vx, vy) { 102 return false 103 } 104 } 105 return true 106 }