@@ -9,77 +9,77 @@ import (
9
9
"github.com/sourcegraph/conc/pool"
10
10
)
11
11
12
- // OrderBy compares two values of type V and returns an integer indicating their order.
12
+ // SortFunc compares two values of type V and returns an integer indicating their order.
13
13
// If a < b, the function should return a negative value.
14
14
// If a == b, the function should return 0.
15
15
// If a > b, the function should return a positive value.
16
- type OrderBy [V any ] func (ctx context.Context , a , b V ) int
16
+ type SortFunc [V any ] func (ctx context.Context , a , b V ) int
17
17
18
- // ConcurrentOrderBy should return a integer indicating the order of the given value.
19
- // The results will later be ordered by the returned value.
20
- type ConcurrentOrderBy [V any ] func (ctx context.Context , a V ) int
18
+ // ConcurrentSortFunc should return an integer indicating the order of the given value.
19
+ // The results will later be sorted by the returned value.
20
+ type ConcurrentSortFunc [V any ] func (ctx context.Context , a V ) int
21
21
22
+ // Filter is a function that returns true if the given value should be included in the result.
22
23
type Filter [V any , FilterObj any ] func (ctx context.Context , v V , filter FilterObj ) bool
23
24
24
- type orderByValue [V any ] struct {
25
- concurrentOrderBy ConcurrentOrderBy [V ]
26
- orderBy OrderBy [V ]
25
+ type funcs [V any ] struct {
26
+ concurrentSort ConcurrentSortFunc [V ]
27
+ sort SortFunc [V ]
27
28
}
28
29
29
- type SortFilter [V any , OrderKey comparable , FilterObj comparable ] struct {
30
- orderBys map [OrderKey ] orderByValue [V ]
31
- filters []Filter [V , FilterObj ]
32
- tieBreakSortKey OrderKey
33
- tieBreakOrderDirection model.OrderDirection
30
+ type SortFilter [V any , SortField comparable , FilterObj comparable ] struct {
31
+ sorters map [SortField ] funcs [V ]
32
+ filters []Filter [V , FilterObj ]
33
+ tieBreakSortField SortField
34
+ tieBreakSortDirection model.OrderDirection
34
35
}
35
36
36
- // New creates a new SortFilter with the given tieBreakSortKey and tieBreakOrderDirection .
37
- // The tieBreakSortKey is used when two values are equal in the OrderBy function.
38
- // The tieBreakSortKey must not be registered as a ConcurrentOrderBy .
39
- func New [V any , OrderKey comparable , FilterObj comparable ](tieBreakSortKey OrderKey , tieBreakOrderDirection model.OrderDirection ) * SortFilter [V , OrderKey , FilterObj ] {
40
- return & SortFilter [V , OrderKey , FilterObj ]{
41
- orderBys : make (map [OrderKey ] orderByValue [V ]),
42
- tieBreakSortKey : tieBreakSortKey ,
43
- tieBreakOrderDirection : tieBreakOrderDirection ,
37
+ // New creates a new SortFilter with the given tieBreakSortField and tieBreakSortDirection .
38
+ // The tieBreakSortField is used when two values are equal in the Sort function.
39
+ // The tieBreakSortField must not be registered as a ConcurrentSort .
40
+ func New [V any , SortField comparable , FilterObj comparable ](tieBreakSortField SortField , tieBreakSortDirection model.OrderDirection ) * SortFilter [V , SortField , FilterObj ] {
41
+ return & SortFilter [V , SortField , FilterObj ]{
42
+ sorters : make (map [SortField ] funcs [V ]),
43
+ tieBreakSortField : tieBreakSortField ,
44
+ tieBreakSortDirection : tieBreakSortDirection ,
44
45
}
45
46
}
46
47
47
- func (s * SortFilter [T , OrderKey , FilterObj ]) DefaultSortKey () OrderKey {
48
- return s .tieBreakSortKey
49
- }
50
-
51
- func (s * SortFilter [T , OrderKey , FilterObj ]) DefaultOrderDirection () model.OrderDirection {
52
- return s .tieBreakOrderDirection
53
- }
54
-
55
- func (s * SortFilter [T , OrderKey , FilterObj ]) Supports (key OrderKey ) bool {
56
- _ , exists := s .orderBys [key ]
48
+ // SupportsSort returns true if the given field is registered using RegisterSort or RegisterConcurrentSort.
49
+ func (s * SortFilter [T , SortField , FilterObj ]) SupportsSort (field SortField ) bool {
50
+ _ , exists := s .sorters [field ]
57
51
return exists
58
52
}
59
53
60
- func (s * SortFilter [T , OrderKey , FilterObj ]) RegisterFilter (filter Filter [T , FilterObj ]) {
61
- s .filters = append (s .filters , filter )
62
- }
63
-
64
- func (s * SortFilter [T , OrderKey , FilterObj ]) RegisterOrderBy (key OrderKey , orderBy OrderBy [T ]) {
65
- if _ , ok := s .orderBys [key ]; ok {
66
- panic (fmt .Sprintf ("OrderBy already registered for key: %v" , key ))
54
+ func (s * SortFilter [T , SortField , FilterObj ]) RegisterSort (field SortField , sort SortFunc [T ]) {
55
+ if _ , ok := s .sorters [field ]; ok {
56
+ panic (fmt .Sprintf ("sort field is already registered: %v" , field ))
67
57
}
68
- s .orderBys [key ] = orderByValue [T ]{
69
- orderBy : orderBy ,
58
+
59
+ s .sorters [field ] = funcs [T ]{
60
+ sort : sort ,
70
61
}
71
62
}
72
63
73
- func (s * SortFilter [T , OrderKey , FilterObj ]) RegisterConcurrentOrderBy (key OrderKey , orderBy ConcurrentOrderBy [T ]) {
74
- if _ , ok := s .orderBys [key ]; ok {
75
- panic (fmt .Sprintf ("OrderBy already registered for key: %v" , key ))
64
+ func (s * SortFilter [T , SortField , FilterObj ]) RegisterConcurrentSort (field SortField , sort ConcurrentSortFunc [T ]) {
65
+ if _ , ok := s .sorters [field ]; ok {
66
+ panic (fmt .Sprintf ("sort field is already registered: %v" , field ))
67
+ } else if field == s .tieBreakSortField {
68
+ panic (fmt .Sprintf ("sort field is used for tie break and can not be concurrent: %v" , field ))
76
69
}
77
- s .orderBys [key ] = orderByValue [T ]{
78
- concurrentOrderBy : orderBy ,
70
+
71
+ s .sorters [field ] = funcs [T ]{
72
+ concurrentSort : sort ,
79
73
}
80
74
}
81
75
82
- func (s * SortFilter [T , OrderKey , FilterObj ]) Filter (ctx context.Context , items []T , filter FilterObj ) []T {
76
+ // RegisterFilter registers a filter function that will be applied to the items when calling Filter.
77
+ func (s * SortFilter [T , SortField , FilterObj ]) RegisterFilter (filter Filter [T , FilterObj ]) {
78
+ s .filters = append (s .filters , filter )
79
+ }
80
+
81
+ // Filter filters all items based on the filters registered with RegisterFilter.
82
+ func (s * SortFilter [T , SortField , FilterObj ]) Filter (ctx context.Context , items []T , filter FilterObj ) []T {
83
83
var nillish FilterObj
84
84
if filter == nillish {
85
85
return items
@@ -118,25 +118,27 @@ func (s *SortFilter[T, OrderKey, FilterObj]) Filter(ctx context.Context, items [
118
118
return filtered
119
119
}
120
120
121
- func (s * SortFilter [T , OrderKey , FilterObj ]) Sort (ctx context.Context , items []T , key OrderKey , direction model.OrderDirection ) {
122
- orderBy , ok := s .orderBys [key ]
121
+ // Sort will sort items based on a specific field and direction. The field used must be registered with RegisterSort or
122
+ // RegisterConcurrentSort.
123
+ func (s * SortFilter [T , SortField , FilterObj ]) Sort (ctx context.Context , items []T , field SortField , direction model.OrderDirection ) {
124
+ sorter , ok := s .sorters [field ]
123
125
if ! ok {
124
- panic (fmt .Sprintf ("OrderBy not registered for key : %v" , key ))
126
+ panic (fmt .Sprintf ("no sort registered for field : %v" , field ))
125
127
}
126
128
127
129
if len (items ) == 0 {
128
130
return
129
131
}
130
132
131
- if orderBy . concurrentOrderBy != nil {
132
- s .sortConcurrent (ctx , items , orderBy . concurrentOrderBy , direction )
133
+ if sorter . concurrentSort != nil {
134
+ s .sortConcurrent (ctx , items , sorter . concurrentSort , direction )
133
135
return
134
136
}
135
137
136
- s .sort (ctx , items , orderBy . orderBy , direction )
138
+ s .sort (ctx , items , sorter . sort , direction )
137
139
}
138
140
139
- func (s * SortFilter [T , OrderKey , FilterObj ]) sortConcurrent (ctx context.Context , items []T , orderBy ConcurrentOrderBy [T ], direction model.OrderDirection ) {
141
+ func (s * SortFilter [T , SortField , FilterObj ]) sortConcurrent (ctx context.Context , items []T , sort ConcurrentSortFunc [T ], direction model.OrderDirection ) {
140
142
type sortable struct {
141
143
item T
142
144
key int
@@ -147,53 +149,53 @@ func (s *SortFilter[T, OrderKey, FilterObj]) sortConcurrent(ctx context.Context,
147
149
wg .Go (func (ctx context.Context ) (sortable , error ) {
148
150
return sortable {
149
151
item : item ,
150
- key : orderBy (ctx , item ),
152
+ key : sort (ctx , item ),
151
153
}, nil
152
154
})
153
155
}
154
156
155
157
res , err := wg .Wait ()
156
158
if err != nil {
157
- // This should never happen, as orderBy doesn't return errors.
159
+ // This should never happen, as sort doesn't return errors.
158
160
panic (err )
159
161
}
160
162
161
- slices .SortStableFunc (res , func (i , j sortable ) int {
162
- if j .key == i .key {
163
- return s .defaultSort (ctx , i .item , j .item )
163
+ slices .SortStableFunc (res , func (a , b sortable ) int {
164
+ if b .key == a .key {
165
+ return s .tieBreak (ctx , a .item , b .item )
164
166
}
165
167
166
168
if direction == model .OrderDirectionDesc {
167
- return j .key - i .key
169
+ return b .key - a .key
168
170
}
169
- return i .key - j .key
171
+ return a .key - b .key
170
172
})
171
173
172
174
for i , r := range res {
173
175
items [i ] = r .item
174
176
}
175
177
}
176
178
177
- func (s * SortFilter [T , OrderKey , FilterObj ]) sort (ctx context.Context , items []T , orderBy OrderBy [T ], direction model.OrderDirection ) {
178
- slices .SortStableFunc (items , func (i , j T ) int {
179
+ func (s * SortFilter [T , SortField , FilterObj ]) sort (ctx context.Context , items []T , sort SortFunc [T ], direction model.OrderDirection ) {
180
+ slices .SortStableFunc (items , func (a , b T ) int {
179
181
var ret int
180
182
if direction == model .OrderDirectionDesc {
181
- ret = orderBy (ctx , j , i )
183
+ ret = sort (ctx , b , a )
182
184
} else {
183
- ret = orderBy (ctx , i , j )
185
+ ret = sort (ctx , a , b )
184
186
}
185
187
186
188
if ret == 0 {
187
- return s .defaultSort (ctx , i , j )
189
+ return s .tieBreak (ctx , a , b )
188
190
}
189
191
return ret
190
192
})
191
193
}
192
194
193
- func (s * SortFilter [T , OrderKey , FilterObj ]) defaultSort (ctx context.Context , a , b T ) int {
194
- if s .tieBreakOrderDirection == model .OrderDirectionDesc {
195
- return s .orderBys [s .tieBreakSortKey ]. orderBy (ctx , b , a )
195
+ func (s * SortFilter [T , SortField , FilterObj ]) tieBreak (ctx context.Context , a , b T ) int {
196
+ if s .tieBreakSortDirection == model .OrderDirectionDesc {
197
+ return s .sorters [s .tieBreakSortField ]. sort (ctx , b , a )
196
198
}
197
199
198
- return s .orderBys [s .tieBreakSortKey ]. orderBy (ctx , a , b )
200
+ return s .sorters [s .tieBreakSortField ]. sort (ctx , a , b )
199
201
}
0 commit comments