File: compare.go

package info (click to toggle)
golang-github-wader-gojq 0.0~git20231105.2b6d9e2-1
  • links: PTS, VCS
  • area: main
  • in suites: sid, trixie
  • size: 960 kB
  • sloc: yacc: 642; makefile: 84
file content (100 lines) | stat: -rw-r--r-- 1,651 bytes parent folder | download | duplicates (2)
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
package gojq

import (
	"math"
	"math/big"
)

// Compare l and r, and returns jq-flavored comparison value.
// The result will be 0 if l == r, -1 if l < r, and +1 if l > r.
// This comparison is used by built-in operators and functions.
func Compare(l, r any) int {
	return compare(l, r)
}

func compare(l, r any) int {
	return binopTypeSwitch(l, r,
		compareInt,
		func(l, r float64) any {
			switch {
			case l < r || math.IsNaN(l):
				return -1
			case l == r:
				return 0
			default:
				return 1
			}
		},
		func(l, r *big.Int) any {
			return l.Cmp(r)
		},
		func(l, r string) any {
			switch {
			case l < r:
				return -1
			case l == r:
				return 0
			default:
				return 1
			}
		},
		func(l, r []any) any {
			n := len(l)
			if len(r) < n {
				n = len(r)
			}
			for i := 0; i < n; i++ {
				if cmp := compare(l[i], r[i]); cmp != 0 {
					return cmp
				}
			}
			return compareInt(len(l), len(r))
		},
		func(l, r map[string]any) any {
			lk, rk := funcKeys(l), funcKeys(r)
			if cmp := compare(lk, rk); cmp != 0 {
				return cmp
			}
			for _, k := range lk.([]any) {
				if cmp := compare(l[k.(string)], r[k.(string)]); cmp != 0 {
					return cmp
				}
			}
			return 0
		},
		func(l, r any) any {
			return compareInt(typeIndex(l), typeIndex(r))
		},
	).(int)
}

func compareInt(l, r int) any {
	switch {
	case l < r:
		return -1
	case l == r:
		return 0
	default:
		return 1
	}
}

func typeIndex(v any) int {
	switch v := v.(type) {
	default:
		return 0
	case bool:
		if !v {
			return 1
		}
		return 2
	case int, float64, *big.Int:
		return 3
	case string:
		return 4
	case []any:
		return 5
	case map[string]any:
		return 6
	}
}