@@ -14,22 +14,29 @@ import (
14
14
)
15
15
16
16
// SortSlices returns a [cmp.Transformer] option that sorts all []V.
17
- // The less function must be of the form "func(T, T) bool" which is used to
18
- // sort any slice with element type V that is assignable to T.
17
+ // The lessOrCompareFunc function must be either
18
+ // a less function of the form "func(T, T) bool" or
19
+ // a compare function of the format "func(T, T) int"
20
+ // which is used to sort any slice with element type V that is assignable to T.
19
21
//
20
- // The less function must be:
22
+ // A less function must be:
21
23
// - Deterministic: less(x, y) == less(x, y)
22
24
// - Irreflexive: !less(x, x)
23
25
// - Transitive: if !less(x, y) and !less(y, z), then !less(x, z)
24
26
//
25
- // The less function does not have to be "total". That is, if !less(x, y) and
26
- // !less(y, x) for two elements x and y, their relative order is maintained.
27
+ // A compare function must be:
28
+ // - Deterministic: compare(x, y) == compare(x, y)
29
+ // - Irreflexive: compare(x, x) == 0
30
+ // - Transitive: if !less(x, y) and !less(y, z), then !less(x, z)
31
+ //
32
+ // The function does not have to be "total". That is, if x != y, but
33
+ // less or compare report inequality, their relative order is maintained.
27
34
//
28
35
// SortSlices can be used in conjunction with [EquateEmpty].
29
- func SortSlices (lessFunc interface {}) cmp.Option {
30
- vf := reflect .ValueOf (lessFunc )
31
- if ! function .IsType (vf .Type (), function .Less ) || vf .IsNil () {
32
- panic (fmt .Sprintf ("invalid less function: %T" , lessFunc ))
36
+ func SortSlices (lessOrCompareFunc interface {}) cmp.Option {
37
+ vf := reflect .ValueOf (lessOrCompareFunc )
38
+ if ( ! function .IsType (vf .Type (), function .Less ) && ! function . IsType ( vf . Type (), function . Compare ) ) || vf .IsNil () {
39
+ panic (fmt .Sprintf ("invalid less or compare function: %T" , lessOrCompareFunc ))
33
40
}
34
41
ss := sliceSorter {vf .Type ().In (0 ), vf }
35
42
return cmp .FilterValues (ss .filter , cmp .Transformer ("cmpopts.SortSlices" , ss .sort ))
@@ -79,28 +86,40 @@ func (ss sliceSorter) checkSort(v reflect.Value) {
79
86
}
80
87
func (ss sliceSorter ) less (v reflect.Value , i , j int ) bool {
81
88
vx , vy := v .Index (i ), v .Index (j )
82
- return ss .fnc .Call ([]reflect.Value {vx , vy })[0 ].Bool ()
89
+ vo := ss .fnc .Call ([]reflect.Value {vx , vy })[0 ]
90
+ if vo .Kind () == reflect .Bool {
91
+ return vo .Bool ()
92
+ } else {
93
+ return vo .Int () < 0
94
+ }
83
95
}
84
96
85
- // SortMaps returns a [cmp.Transformer] option that flattens map[K]V types to be a
86
- // sorted []struct{K, V}. The less function must be of the form
87
- // "func(T, T) bool" which is used to sort any map with key K that is
88
- // assignable to T.
97
+ // SortMaps returns a [cmp.Transformer] option that flattens map[K]V types to be
98
+ // a sorted []struct{K, V}. The lessOrCompareFunc function must be either
99
+ // a less function of the form "func(T, T) bool" or
100
+ // a compare function of the format "func(T, T) int"
101
+ // which is used to sort any map with key K that is assignable to T.
89
102
//
90
103
// Flattening the map into a slice has the property that [cmp.Equal] is able to
91
104
// use [cmp.Comparer] options on K or the K.Equal method if it exists.
92
105
//
93
- // The less function must be:
106
+ // A less function must be:
94
107
// - Deterministic: less(x, y) == less(x, y)
95
108
// - Irreflexive: !less(x, x)
96
109
// - Transitive: if !less(x, y) and !less(y, z), then !less(x, z)
97
110
// - Total: if x != y, then either less(x, y) or less(y, x)
98
111
//
112
+ // A compare function must be:
113
+ // - Deterministic: compare(x, y) == compare(x, y)
114
+ // - Irreflexive: compare(x, x) == 0
115
+ // - Transitive: if compare(x, y) < 0 and compare(y, z) < 0, then compare(x, z) < 0
116
+ // - Total: if x != y, then compare(x, y) != 0
117
+ //
99
118
// SortMaps can be used in conjunction with [EquateEmpty].
100
- func SortMaps (lessFunc interface {}) cmp.Option {
101
- vf := reflect .ValueOf (lessFunc )
102
- if ! function .IsType (vf .Type (), function .Less ) || vf .IsNil () {
103
- panic (fmt .Sprintf ("invalid less function: %T" , lessFunc ))
119
+ func SortMaps (lessOrCompareFunc interface {}) cmp.Option {
120
+ vf := reflect .ValueOf (lessOrCompareFunc )
121
+ if ( ! function .IsType (vf .Type (), function .Less ) && ! function . IsType ( vf . Type (), function . Compare ) ) || vf .IsNil () {
122
+ panic (fmt .Sprintf ("invalid less or compare function: %T" , lessOrCompareFunc ))
104
123
}
105
124
ms := mapSorter {vf .Type ().In (0 ), vf }
106
125
return cmp .FilterValues (ms .filter , cmp .Transformer ("cmpopts.SortMaps" , ms .sort ))
@@ -143,5 +162,10 @@ func (ms mapSorter) checkSort(v reflect.Value) {
143
162
}
144
163
func (ms mapSorter ) less (v reflect.Value , i , j int ) bool {
145
164
vx , vy := v .Index (i ).Field (0 ), v .Index (j ).Field (0 )
146
- return ms .fnc .Call ([]reflect.Value {vx , vy })[0 ].Bool ()
165
+ vo := ms .fnc .Call ([]reflect.Value {vx , vy })[0 ]
166
+ if vo .Kind () == reflect .Bool {
167
+ return vo .Bool ()
168
+ } else {
169
+ return vo .Int () < 0
170
+ }
147
171
}
0 commit comments