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  }