waveterm/pkg/util/utilfn/compare.go
2024-11-02 10:58:13 -07:00

147 lines
2.7 KiB
Go

// Copyright 2024, Command Line Inc.
// SPDX-License-Identifier: Apache-2.0
package utilfn
import (
"reflect"
)
// this is a shallow equal, but with special handling for numeric types
// it will up convert to float64 and compare
func JsonValEqual(a, b any) bool {
if a == nil && b == nil {
return true
}
if a == nil || b == nil {
return false
}
typeA := reflect.TypeOf(a)
typeB := reflect.TypeOf(b)
if typeA == typeB && typeA.Comparable() {
return a == b
}
if IsNumericType(a) && IsNumericType(b) {
return CompareAsFloat64(a, b)
}
if typeA != typeB {
return false
}
// for slices and maps, compare their pointers
valA := reflect.ValueOf(a)
valB := reflect.ValueOf(b)
switch valA.Kind() {
case reflect.Slice, reflect.Map:
return valA.Pointer() == valB.Pointer()
}
return false
}
// Helper to check if a value is a numeric type
func IsNumericType(val any) bool {
switch val.(type) {
case int, int8, int16, int32, int64,
uint, uint8, uint16, uint32, uint64,
float32, float64:
return true
default:
return false
}
}
// Helper to handle numeric comparisons as float64
func CompareAsFloat64(a, b any) bool {
valA, okA := ToFloat64(a)
valB, okB := ToFloat64(b)
return okA && okB && valA == valB
}
// Convert various numeric types to float64 for comparison
func ToFloat64(val any) (float64, bool) {
if val == nil {
return 0, false
}
switch v := val.(type) {
case int:
return float64(v), true
case int8:
return float64(v), true
case int16:
return float64(v), true
case int32:
return float64(v), true
case int64:
return float64(v), true
case uint:
return float64(v), true
case uint8:
return float64(v), true
case uint16:
return float64(v), true
case uint32:
return float64(v), true
case uint64:
return float64(v), true
case float32:
return float64(v), true
case float64:
return v, true
default:
return 0, false
}
}
func ToInt64(val any) (int64, bool) {
if val == nil {
return 0, false
}
switch v := val.(type) {
case int:
return int64(v), true
case int8:
return int64(v), true
case int16:
return int64(v), true
case int32:
return int64(v), true
case int64:
return v, true
case uint:
return int64(v), true
case uint8:
return int64(v), true
case uint16:
return int64(v), true
case uint32:
return int64(v), true
case uint64:
return int64(v), true
case float32:
return int64(v), true
case float64:
return int64(v), true
default:
return 0, false
}
}
func ToInt(val any) (int, bool) {
i, ok := ToInt64(val)
if !ok {
return 0, false
}
return int(i), true
}
func ToStr(val any) (string, bool) {
if val == nil {
return "", false
}
switch v := val.(type) {
case string:
return v, true
default:
return "", false
}
}