File: equal.go

package info (click to toggle)
elvish 0.21.0-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 6,372 kB
  • sloc: javascript: 236; sh: 130; python: 104; makefile: 88; xml: 9
file content (106 lines) | stat: -rw-r--r-- 2,218 bytes parent folder | download
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
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
package vals

import (
	"math/big"
	"reflect"

	"src.elv.sh/pkg/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 any) bool
}

// Equal returns whether two values are equal. It is implemented for the builtin
// types bool and string, the File, List, Map types, StructMap types, and types
// satisfying the Equaler interface. For other types, it uses reflect.DeepEqual
// to compare the two values.
func Equal(x, y any) bool {
	switch x := x.(type) {
	case nil:
		return x == y
	case bool:
		return x == y
	case int:
		return x == y
	case *big.Int:
		if y, ok := y.(*big.Int); ok {
			return x.Cmp(y) == 0
		}
		return false
	case *big.Rat:
		if y, ok := y.(*big.Rat); ok {
			return x.Cmp(y) == 0
		}
		return false
	case float64:
		return x == y
	case string:
		return x == y
	case List:
		if yy, ok := y.(List); ok {
			return equalList(x, yy)
		}
		return false
	// Types above are also handled in [Cmp]; keep the branches in the same
	// order.
	case Equaler:
		return x.Equal(y)
	case File:
		if yy, ok := y.(File); ok {
			return x.Fd() == yy.Fd()
		}
		return false
	case Map:
		switch y := y.(type) {
		case Map:
			return equalMap(x, y, Map.Iterator, Map.Index)
		case StructMap:
			return equalMap(x, y, Map.Iterator, indexStructMap)
		}
		return false
	case StructMap:
		switch y := y.(type) {
		case Map:
			return equalMap(x, y, iterateStructMap, Map.Index)
		case StructMap:
			return equalMap(x, y, iterateStructMap, indexStructMap)
		}
		return false
	default:
		return reflect.DeepEqual(x, y)
	}
}

func equalList(x, y List) 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
}

func equalMap[X, Y any, I hashmap.Iterator](x X, y Y, xit func(X) I, yidx func(Y, any) (any, bool)) bool {
	if Len(x) != Len(y) {
		return false
	}
	for it := xit(x); it.HasElem(); it.Next() {
		k, vx := it.Elem()
		vy, ok := yidx(y, k)
		if !ok || !Equal(vx, vy) {
			return false
		}
	}
	return true
}