@@ -14,22 +14,29 @@ import (
1414)
1515
1616// 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.
1921//
20- // The less function must be:
22+ // A less function must be:
2123// - Deterministic: less(x, y) == less(x, y)
2224// - Irreflexive: !less(x, x)
2325// - Transitive: if !less(x, y) and !less(y, z), then !less(x, z)
2426//
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.
2734//
2835// 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 ))
3340 }
3441 ss := sliceSorter {vf .Type ().In (0 ), vf }
3542 return cmp .FilterValues (ss .filter , cmp .Transformer ("cmpopts.SortSlices" , ss .sort ))
@@ -79,28 +86,40 @@ func (ss sliceSorter) checkSort(v reflect.Value) {
7986}
8087func (ss sliceSorter ) less (v reflect.Value , i , j int ) bool {
8188 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+ }
8395}
8496
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.
89102//
90103// Flattening the map into a slice has the property that [cmp.Equal] is able to
91104// use [cmp.Comparer] options on K or the K.Equal method if it exists.
92105//
93- // The less function must be:
106+ // A less function must be:
94107// - Deterministic: less(x, y) == less(x, y)
95108// - Irreflexive: !less(x, x)
96109// - Transitive: if !less(x, y) and !less(y, z), then !less(x, z)
97110// - Total: if x != y, then either less(x, y) or less(y, x)
98111//
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+ //
99118// 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 ))
104123 }
105124 ms := mapSorter {vf .Type ().In (0 ), vf }
106125 return cmp .FilterValues (ms .filter , cmp .Transformer ("cmpopts.SortMaps" , ms .sort ))
@@ -143,5 +162,10 @@ func (ms mapSorter) checkSort(v reflect.Value) {
143162}
144163func (ms mapSorter ) less (v reflect.Value , i , j int ) bool {
145164 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+ }
147171}
0 commit comments