1
0
mirror of https://github.com/danog/liquid.git synced 2024-12-02 12:17:48 +01:00
liquid/generics/compare.go

123 lines
2.5 KiB
Go
Raw Normal View History

2017-06-27 16:28:39 +02:00
package generics
import (
"fmt"
"reflect"
)
// Equal returns a bool indicating whether a == b after conversion.
func Equal(a, b interface{}) bool {
return genericCompare(reflect.ValueOf(a), reflect.ValueOf(b)) == 0
}
// Less returns a bool indicating whether a < b.
func Less(a, b interface{}) bool {
return genericCompare(reflect.ValueOf(a), reflect.ValueOf(b)) < 0
}
func genericSameTypeCompare(av, bv interface{}) int {
2017-06-27 23:29:50 +02:00
switch {
case av == nil && bv == nil:
return 0
case av == nil:
return -1
case bv == nil:
return 1
}
2017-06-27 16:28:39 +02:00
a, b := reflect.ValueOf(av), reflect.ValueOf(bv)
if a.Kind() != b.Kind() {
panic(fmt.Errorf("genericSameTypeCompare called on different types: %v and %v", a, b))
}
if a == b {
return 0
}
switch a.Kind() {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
if a.Int() < b.Int() {
return -1
}
case reflect.Float32, reflect.Float64:
if a.Float() < b.Float() {
return -1
}
case reflect.String:
if a.String() < b.String() {
return -1
}
default:
2017-06-27 23:29:50 +02:00
panic(genericErrorf("unimplemented generic same-type comparison for %v<%s> and %v<%s>", a, a.Type(), b.Type()))
2017-06-27 16:28:39 +02:00
}
return 1
}
func genericCompare(a, b reflect.Value) int {
if a.Interface() == b.Interface() {
return 0
}
2017-06-27 23:29:50 +02:00
if a.Type() == b.Type() {
return genericSameTypeCompare(a.Interface(), b.Interface())
}
2017-06-27 16:28:39 +02:00
ak, bk := a.Kind(), b.Kind()
// _ = ak.Convert
switch a.Kind() {
case reflect.Bool:
if b.Kind() == reflect.Bool {
switch {
case a.Bool() && b.Bool():
return 0
case a.Bool():
return 1
case b.Bool():
return -1
default:
return 0
}
}
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
if hasIntKind(b) {
if a.Int() < b.Int() {
return -1
}
if a.Int() > b.Int() {
return 1
}
return 0
}
if hasFloatKind(b) {
return genericCompare(reflect.ValueOf(float64(a.Int())), b)
}
case reflect.Float32, reflect.Float64:
if hasIntKind(b) {
b = reflect.ValueOf(float64(b.Int()))
}
if hasFloatKind(b) {
if a.Float() < b.Float() {
return -1
}
if a.Float() > b.Float() {
return 1
}
return 0
}
}
panic(genericErrorf("unimplemented: comparison of %v<%s> with %v<%s>", a, ak, b, bk))
}
func hasIntKind(n reflect.Value) bool {
switch n.Kind() {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
return true
default:
return false
}
}
func hasFloatKind(n reflect.Value) bool {
switch n.Kind() {
case reflect.Float32, reflect.Float64:
return true
default:
return false
}
}