| ... | @@ -5,7 +5,13 @@ const mem = std.mem; | ... | @@ -5,7 +5,13 @@ const mem = std.mem; |
| 5 | const math = std.math; | 5 | const math = std.math; |
| 6 | const builtin = @import("builtin"); | 6 | const builtin = @import("builtin"); |
| 7 | | 7 | |
| 8 | pub fn binarySearch(comptime T: type, key: T, items: []const T, comptime compareFn: fn (lhs: T, rhs: T) math.Order) ?usize { | 8 | pub fn binarySearch( |
| | 9 | comptime T: type, |
| | 10 | key: T, |
| | 11 | items: []const T, |
| | 12 | context: var, |
| | 13 | comptime compareFn: fn (context: @TypeOf(context), lhs: T, rhs: T) math.Order, |
| | 14 | ) ?usize { |
| 9 | var left: usize = 0; | 15 | var left: usize = 0; |
| 10 | var right: usize = items.len; | 16 | var right: usize = items.len; |
| 11 | | 17 | |
| ... | @@ -13,7 +19,7 @@ pub fn binarySearch(comptime T: type, key: T, items: []const T, comptime compare | ... | @@ -13,7 +19,7 @@ pub fn binarySearch(comptime T: type, key: T, items: []const T, comptime compare |
| 13 | // Avoid overflowing in the midpoint calculation | 19 | // Avoid overflowing in the midpoint calculation |
| 14 | const mid = left + (right - left) / 2; | 20 | const mid = left + (right - left) / 2; |
| 15 | // Compare the key with the midpoint element | 21 | // Compare the key with the midpoint element |
| 16 | switch (compareFn(key, items[mid])) { | 22 | switch (compareFn(context, key, items[mid])) { |
| 17 | .eq => return mid, | 23 | .eq => return mid, |
| 18 | .gt => left = mid + 1, | 24 | .gt => left = mid + 1, |
| 19 | .lt => right = mid, | 25 | .lt => right = mid, |
| ... | @@ -23,56 +29,61 @@ pub fn binarySearch(comptime T: type, key: T, items: []const T, comptime compare | ... | @@ -23,56 +29,61 @@ pub fn binarySearch(comptime T: type, key: T, items: []const T, comptime compare |
| 23 | return null; | 29 | return null; |
| 24 | } | 30 | } |
| 25 | | 31 | |
| 26 | test "std.sort.binarySearch" { | 32 | test "binarySearch" { |
| 27 | const S = struct { | 33 | const S = struct { |
| 28 | fn order_u32(lhs: u32, rhs: u32) math.Order { | 34 | fn order_u32(context: void, lhs: u32, rhs: u32) math.Order { |
| 29 | return math.order(lhs, rhs); | 35 | return math.order(lhs, rhs); |
| 30 | } | 36 | } |
| 31 | fn order_i32(lhs: i32, rhs: i32) math.Order { | 37 | fn order_i32(context: void, lhs: i32, rhs: i32) math.Order { |
| 32 | return math.order(lhs, rhs); | 38 | return math.order(lhs, rhs); |
| 33 | } | 39 | } |
| 34 | }; | 40 | }; |
| 35 | testing.expectEqual( | 41 | testing.expectEqual( |
| 36 | @as(?usize, null), | 42 | @as(?usize, null), |
| 37 | binarySearch(u32, 1, &[_]u32{}, S.order_u32), | 43 | binarySearch(u32, 1, &[_]u32{}, {}, S.order_u32), |
| 38 | ); | 44 | ); |
| 39 | testing.expectEqual( | 45 | testing.expectEqual( |
| 40 | @as(?usize, 0), | 46 | @as(?usize, 0), |
| 41 | binarySearch(u32, 1, &[_]u32{1}, S.order_u32), | 47 | binarySearch(u32, 1, &[_]u32{1}, {}, S.order_u32), |
| 42 | ); | 48 | ); |
| 43 | testing.expectEqual( | 49 | testing.expectEqual( |
| 44 | @as(?usize, null), | 50 | @as(?usize, null), |
| 45 | binarySearch(u32, 1, &[_]u32{0}, S.order_u32), | 51 | binarySearch(u32, 1, &[_]u32{0}, {}, S.order_u32), |
| 46 | ); | 52 | ); |
| 47 | testing.expectEqual( | 53 | testing.expectEqual( |
| 48 | @as(?usize, null), | 54 | @as(?usize, null), |
| 49 | binarySearch(u32, 0, &[_]u32{1}, S.order_u32), | 55 | binarySearch(u32, 0, &[_]u32{1}, {}, S.order_u32), |
| 50 | ); | 56 | ); |
| 51 | testing.expectEqual( | 57 | testing.expectEqual( |
| 52 | @as(?usize, 4), | 58 | @as(?usize, 4), |
| 53 | binarySearch(u32, 5, &[_]u32{ 1, 2, 3, 4, 5 }, S.order_u32), | 59 | binarySearch(u32, 5, &[_]u32{ 1, 2, 3, 4, 5 }, {}, S.order_u32), |
| 54 | ); | 60 | ); |
| 55 | testing.expectEqual( | 61 | testing.expectEqual( |
| 56 | @as(?usize, 0), | 62 | @as(?usize, 0), |
| 57 | binarySearch(u32, 2, &[_]u32{ 2, 4, 8, 16, 32, 64 }, S.order_u32), | 63 | binarySearch(u32, 2, &[_]u32{ 2, 4, 8, 16, 32, 64 }, {}, S.order_u32), |
| 58 | ); | 64 | ); |
| 59 | testing.expectEqual( | 65 | testing.expectEqual( |
| 60 | @as(?usize, 1), | 66 | @as(?usize, 1), |
| 61 | binarySearch(i32, -4, &[_]i32{ -7, -4, 0, 9, 10 }, S.order_i32), | 67 | binarySearch(i32, -4, &[_]i32{ -7, -4, 0, 9, 10 }, {}, S.order_i32), |
| 62 | ); | 68 | ); |
| 63 | testing.expectEqual( | 69 | testing.expectEqual( |
| 64 | @as(?usize, 3), | 70 | @as(?usize, 3), |
| 65 | binarySearch(i32, 98, &[_]i32{ -100, -25, 2, 98, 99, 100 }, S.order_i32), | 71 | binarySearch(i32, 98, &[_]i32{ -100, -25, 2, 98, 99, 100 }, {}, S.order_i32), |
| 66 | ); | 72 | ); |
| 67 | } | 73 | } |
| 68 | | 74 | |
| 69 | /// Stable in-place sort. O(n) best case, O(pow(n, 2)) worst case. O(1) memory (no allocator required). | 75 | /// Stable in-place sort. O(n) best case, O(pow(n, 2)) worst case. O(1) memory (no allocator required). |
| 70 | pub fn insertionSort(comptime T: type, items: []T, lessThan: fn (lhs: T, rhs: T) bool) void { | 76 | pub fn insertionSort( |
| | 77 | comptime T: type, |
| | 78 | items: []T, |
| | 79 | context: var, |
| | 80 | comptime lessThan: fn (context: @TypeOf(context), lhs: T, rhs: T) bool, |
| | 81 | ) void { |
| 71 | var i: usize = 1; | 82 | var i: usize = 1; |
| 72 | while (i < items.len) : (i += 1) { | 83 | while (i < items.len) : (i += 1) { |
| 73 | const x = items[i]; | 84 | const x = items[i]; |
| 74 | var j: usize = i; | 85 | var j: usize = i; |
| 75 | while (j > 0 and lessThan(x, items[j - 1])) : (j -= 1) { | 86 | while (j > 0 and lessThan(context, x, items[j - 1])) : (j -= 1) { |
| 76 | items[j] = items[j - 1]; | 87 | items[j] = items[j - 1]; |
| 77 | } | 88 | } |
| 78 | items[j] = x; | 89 | items[j] = x; |
| ... | @@ -168,20 +179,25 @@ const Pull = struct { | ... | @@ -168,20 +179,25 @@ const Pull = struct { |
| 168 | | 179 | |
| 169 | /// Stable in-place sort. O(n) best case, O(n*log(n)) worst case and average case. O(1) memory (no allocator required). | 180 | /// Stable in-place sort. O(n) best case, O(n*log(n)) worst case and average case. O(1) memory (no allocator required). |
| 170 | /// Currently implemented as block sort. | 181 | /// Currently implemented as block sort. |
| 171 | pub fn sort(comptime T: type, items: []T, lessThan: fn (lhs: T, rhs: T) bool) void { | 182 | pub fn sort( |
| | 183 | comptime T: type, |
| | 184 | items: []T, |
| | 185 | context: var, |
| | 186 | comptime lessThan: fn (context: @TypeOf(context), lhs: T, rhs: T) bool, |
| | 187 | ) void { |
| 172 | // Implementation ported from https://github.com/BonzaiThePenguin/WikiSort/blob/master/WikiSort.c | 188 | // Implementation ported from https://github.com/BonzaiThePenguin/WikiSort/blob/master/WikiSort.c |
| 173 | var cache: [512]T = undefined; | 189 | var cache: [512]T = undefined; |
| 174 | | 190 | |
| 175 | if (items.len < 4) { | 191 | if (items.len < 4) { |
| 176 | if (items.len == 3) { | 192 | if (items.len == 3) { |
| 177 | // hard coded insertion sort | 193 | // hard coded insertion sort |
| 178 | if (lessThan(items[1], items[0])) mem.swap(T, &items[0], &items[1]); | 194 | if (lessThan(context, items[1], items[0])) mem.swap(T, &items[0], &items[1]); |
| 179 | if (lessThan(items[2], items[1])) { | 195 | if (lessThan(context, items[2], items[1])) { |
| 180 | mem.swap(T, &items[1], &items[2]); | 196 | mem.swap(T, &items[1], &items[2]); |
| 181 | if (lessThan(items[1], items[0])) mem.swap(T, &items[0], &items[1]); | 197 | if (lessThan(context, items[1], items[0])) mem.swap(T, &items[0], &items[1]); |
| 182 | } | 198 | } |
| 183 | } else if (items.len == 2) { | 199 | } else if (items.len == 2) { |
| 184 | if (lessThan(items[1], items[0])) mem.swap(T, &items[0], &items[1]); | 200 | if (lessThan(context, items[1], items[0])) mem.swap(T, &items[0], &items[1]); |
| 185 | } | 201 | } |
| 186 | return; | 202 | return; |
| 187 | } | 203 | } |
| ... | @@ -197,75 +213,75 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn (lhs: T, rhs: T) bool) vo | ... | @@ -197,75 +213,75 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn (lhs: T, rhs: T) bool) vo |
| 197 | const sliced_items = items[range.start..]; | 213 | const sliced_items = items[range.start..]; |
| 198 | switch (range.length()) { | 214 | switch (range.length()) { |
| 199 | 8 => { | 215 | 8 => { |
| 200 | swap(T, sliced_items, lessThan, &order, 0, 1); | 216 | swap(T, sliced_items, context, lessThan, &order, 0, 1); |
| 201 | swap(T, sliced_items, lessThan, &order, 2, 3); | 217 | swap(T, sliced_items, context, lessThan, &order, 2, 3); |
| 202 | swap(T, sliced_items, lessThan, &order, 4, 5); | 218 | swap(T, sliced_items, context, lessThan, &order, 4, 5); |
| 203 | swap(T, sliced_items, lessThan, &order, 6, 7); | 219 | swap(T, sliced_items, context, lessThan, &order, 6, 7); |
| 204 | swap(T, sliced_items, lessThan, &order, 0, 2); | 220 | swap(T, sliced_items, context, lessThan, &order, 0, 2); |
| 205 | swap(T, sliced_items, lessThan, &order, 1, 3); | 221 | swap(T, sliced_items, context, lessThan, &order, 1, 3); |
| 206 | swap(T, sliced_items, lessThan, &order, 4, 6); | 222 | swap(T, sliced_items, context, lessThan, &order, 4, 6); |
| 207 | swap(T, sliced_items, lessThan, &order, 5, 7); | 223 | swap(T, sliced_items, context, lessThan, &order, 5, 7); |
| 208 | swap(T, sliced_items, lessThan, &order, 1, 2); | 224 | swap(T, sliced_items, context, lessThan, &order, 1, 2); |
| 209 | swap(T, sliced_items, lessThan, &order, 5, 6); | 225 | swap(T, sliced_items, context, lessThan, &order, 5, 6); |
| 210 | swap(T, sliced_items, lessThan, &order, 0, 4); | 226 | swap(T, sliced_items, context, lessThan, &order, 0, 4); |
| 211 | swap(T, sliced_items, lessThan, &order, 3, 7); | 227 | swap(T, sliced_items, context, lessThan, &order, 3, 7); |
| 212 | swap(T, sliced_items, lessThan, &order, 1, 5); | 228 | swap(T, sliced_items, context, lessThan, &order, 1, 5); |
| 213 | swap(T, sliced_items, lessThan, &order, 2, 6); | 229 | swap(T, sliced_items, context, lessThan, &order, 2, 6); |
| 214 | swap(T, sliced_items, lessThan, &order, 1, 4); | 230 | swap(T, sliced_items, context, lessThan, &order, 1, 4); |
| 215 | swap(T, sliced_items, lessThan, &order, 3, 6); | 231 | swap(T, sliced_items, context, lessThan, &order, 3, 6); |
| 216 | swap(T, sliced_items, lessThan, &order, 2, 4); | 232 | swap(T, sliced_items, context, lessThan, &order, 2, 4); |
| 217 | swap(T, sliced_items, lessThan, &order, 3, 5); | 233 | swap(T, sliced_items, context, lessThan, &order, 3, 5); |
| 218 | swap(T, sliced_items, lessThan, &order, 3, 4); | 234 | swap(T, sliced_items, context, lessThan, &order, 3, 4); |
| 219 | }, | 235 | }, |
| 220 | 7 => { | 236 | 7 => { |
| 221 | swap(T, sliced_items, lessThan, &order, 1, 2); | 237 | swap(T, sliced_items, context, lessThan, &order, 1, 2); |
| 222 | swap(T, sliced_items, lessThan, &order, 3, 4); | 238 | swap(T, sliced_items, context, lessThan, &order, 3, 4); |
| 223 | swap(T, sliced_items, lessThan, &order, 5, 6); | 239 | swap(T, sliced_items, context, lessThan, &order, 5, 6); |
| 224 | swap(T, sliced_items, lessThan, &order, 0, 2); | 240 | swap(T, sliced_items, context, lessThan, &order, 0, 2); |
| 225 | swap(T, sliced_items, lessThan, &order, 3, 5); | 241 | swap(T, sliced_items, context, lessThan, &order, 3, 5); |
| 226 | swap(T, sliced_items, lessThan, &order, 4, 6); | 242 | swap(T, sliced_items, context, lessThan, &order, 4, 6); |
| 227 | swap(T, sliced_items, lessThan, &order, 0, 1); | 243 | swap(T, sliced_items, context, lessThan, &order, 0, 1); |
| 228 | swap(T, sliced_items, lessThan, &order, 4, 5); | 244 | swap(T, sliced_items, context, lessThan, &order, 4, 5); |
| 229 | swap(T, sliced_items, lessThan, &order, 2, 6); | 245 | swap(T, sliced_items, context, lessThan, &order, 2, 6); |
| 230 | swap(T, sliced_items, lessThan, &order, 0, 4); | 246 | swap(T, sliced_items, context, lessThan, &order, 0, 4); |
| 231 | swap(T, sliced_items, lessThan, &order, 1, 5); | 247 | swap(T, sliced_items, context, lessThan, &order, 1, 5); |
| 232 | swap(T, sliced_items, lessThan, &order, 0, 3); | 248 | swap(T, sliced_items, context, lessThan, &order, 0, 3); |
| 233 | swap(T, sliced_items, lessThan, &order, 2, 5); | 249 | swap(T, sliced_items, context, lessThan, &order, 2, 5); |
| 234 | swap(T, sliced_items, lessThan, &order, 1, 3); | 250 | swap(T, sliced_items, context, lessThan, &order, 1, 3); |
| 235 | swap(T, sliced_items, lessThan, &order, 2, 4); | 251 | swap(T, sliced_items, context, lessThan, &order, 2, 4); |
| 236 | swap(T, sliced_items, lessThan, &order, 2, 3); | 252 | swap(T, sliced_items, context, lessThan, &order, 2, 3); |
| 237 | }, | 253 | }, |
| 238 | 6 => { | 254 | 6 => { |
| 239 | swap(T, sliced_items, lessThan, &order, 1, 2); | 255 | swap(T, sliced_items, context, lessThan, &order, 1, 2); |
| 240 | swap(T, sliced_items, lessThan, &order, 4, 5); | 256 | swap(T, sliced_items, context, lessThan, &order, 4, 5); |
| 241 | swap(T, sliced_items, lessThan, &order, 0, 2); | 257 | swap(T, sliced_items, context, lessThan, &order, 0, 2); |
| 242 | swap(T, sliced_items, lessThan, &order, 3, 5); | 258 | swap(T, sliced_items, context, lessThan, &order, 3, 5); |
| 243 | swap(T, sliced_items, lessThan, &order, 0, 1); | 259 | swap(T, sliced_items, context, lessThan, &order, 0, 1); |
| 244 | swap(T, sliced_items, lessThan, &order, 3, 4); | 260 | swap(T, sliced_items, context, lessThan, &order, 3, 4); |
| 245 | swap(T, sliced_items, lessThan, &order, 2, 5); | 261 | swap(T, sliced_items, context, lessThan, &order, 2, 5); |
| 246 | swap(T, sliced_items, lessThan, &order, 0, 3); | 262 | swap(T, sliced_items, context, lessThan, &order, 0, 3); |
| 247 | swap(T, sliced_items, lessThan, &order, 1, 4); | 263 | swap(T, sliced_items, context, lessThan, &order, 1, 4); |
| 248 | swap(T, sliced_items, lessThan, &order, 2, 4); | 264 | swap(T, sliced_items, context, lessThan, &order, 2, 4); |
| 249 | swap(T, sliced_items, lessThan, &order, 1, 3); | 265 | swap(T, sliced_items, context, lessThan, &order, 1, 3); |
| 250 | swap(T, sliced_items, lessThan, &order, 2, 3); | 266 | swap(T, sliced_items, context, lessThan, &order, 2, 3); |
| 251 | }, | 267 | }, |
| 252 | 5 => { | 268 | 5 => { |
| 253 | swap(T, sliced_items, lessThan, &order, 0, 1); | 269 | swap(T, sliced_items, context, lessThan, &order, 0, 1); |
| 254 | swap(T, sliced_items, lessThan, &order, 3, 4); | 270 | swap(T, sliced_items, context, lessThan, &order, 3, 4); |
| 255 | swap(T, sliced_items, lessThan, &order, 2, 4); | 271 | swap(T, sliced_items, context, lessThan, &order, 2, 4); |
| 256 | swap(T, sliced_items, lessThan, &order, 2, 3); | 272 | swap(T, sliced_items, context, lessThan, &order, 2, 3); |
| 257 | swap(T, sliced_items, lessThan, &order, 1, 4); | 273 | swap(T, sliced_items, context, lessThan, &order, 1, 4); |
| 258 | swap(T, sliced_items, lessThan, &order, 0, 3); | 274 | swap(T, sliced_items, context, lessThan, &order, 0, 3); |
| 259 | swap(T, sliced_items, lessThan, &order, 0, 2); | 275 | swap(T, sliced_items, context, lessThan, &order, 0, 2); |
| 260 | swap(T, sliced_items, lessThan, &order, 1, 3); | 276 | swap(T, sliced_items, context, lessThan, &order, 1, 3); |
| 261 | swap(T, sliced_items, lessThan, &order, 1, 2); | 277 | swap(T, sliced_items, context, lessThan, &order, 1, 2); |
| 262 | }, | 278 | }, |
| 263 | 4 => { | 279 | 4 => { |
| 264 | swap(T, sliced_items, lessThan, &order, 0, 1); | 280 | swap(T, sliced_items, context, lessThan, &order, 0, 1); |
| 265 | swap(T, sliced_items, lessThan, &order, 2, 3); | 281 | swap(T, sliced_items, context, lessThan, &order, 2, 3); |
| 266 | swap(T, sliced_items, lessThan, &order, 0, 2); | 282 | swap(T, sliced_items, context, lessThan, &order, 0, 2); |
| 267 | swap(T, sliced_items, lessThan, &order, 1, 3); | 283 | swap(T, sliced_items, context, lessThan, &order, 1, 3); |
| 268 | swap(T, sliced_items, lessThan, &order, 1, 2); | 284 | swap(T, sliced_items, context, lessThan, &order, 1, 2); |
| 269 | }, | 285 | }, |
| 270 | else => {}, | 286 | else => {}, |
| 271 | } | 287 | } |
| ... | @@ -288,16 +304,16 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn (lhs: T, rhs: T) bool) vo | ... | @@ -288,16 +304,16 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn (lhs: T, rhs: T) bool) vo |
| 288 | var A2 = iterator.nextRange(); | 304 | var A2 = iterator.nextRange(); |
| 289 | var B2 = iterator.nextRange(); | 305 | var B2 = iterator.nextRange(); |
| 290 | | 306 | |
| 291 | if (lessThan(items[B1.end - 1], items[A1.start])) { | 307 | if (lessThan(context, items[B1.end - 1], items[A1.start])) { |
| 292 | // the two ranges are in reverse order, so copy them in reverse order into the cache | 308 | // the two ranges are in reverse order, so copy them in reverse order into the cache |
| 293 | mem.copy(T, cache[B1.length()..], items[A1.start..A1.end]); | 309 | mem.copy(T, cache[B1.length()..], items[A1.start..A1.end]); |
| 294 | mem.copy(T, cache[0..], items[B1.start..B1.end]); | 310 | mem.copy(T, cache[0..], items[B1.start..B1.end]); |
| 295 | } else if (lessThan(items[B1.start], items[A1.end - 1])) { | 311 | } else if (lessThan(context, items[B1.start], items[A1.end - 1])) { |
| 296 | // these two ranges weren't already in order, so merge them into the cache | 312 | // these two ranges weren't already in order, so merge them into the cache |
| 297 | mergeInto(T, items, A1, B1, lessThan, cache[0..]); | 313 | mergeInto(T, items, A1, B1, context, lessThan, cache[0..]); |
| 298 | } else { | 314 | } else { |
| 299 | // if A1, B1, A2, and B2 are all in order, skip doing anything else | 315 | // if A1, B1, A2, and B2 are all in order, skip doing anything else |
| 300 | if (!lessThan(items[B2.start], items[A2.end - 1]) and !lessThan(items[A2.start], items[B1.end - 1])) continue; | 316 | if (!lessThan(context, items[B2.start], items[A2.end - 1]) and !lessThan(context, items[A2.start], items[B1.end - 1])) continue; |
| 301 | | 317 | |
| 302 | // copy A1 and B1 into the cache in the same order | 318 | // copy A1 and B1 into the cache in the same order |
| 303 | mem.copy(T, cache[0..], items[A1.start..A1.end]); | 319 | mem.copy(T, cache[0..], items[A1.start..A1.end]); |
| ... | @@ -306,13 +322,13 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn (lhs: T, rhs: T) bool) vo | ... | @@ -306,13 +322,13 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn (lhs: T, rhs: T) bool) vo |
| 306 | A1 = Range.init(A1.start, B1.end); | 322 | A1 = Range.init(A1.start, B1.end); |
| 307 | | 323 | |
| 308 | // merge A2 and B2 into the cache | 324 | // merge A2 and B2 into the cache |
| 309 | if (lessThan(items[B2.end - 1], items[A2.start])) { | 325 | if (lessThan(context, items[B2.end - 1], items[A2.start])) { |
| 310 | // the two ranges are in reverse order, so copy them in reverse order into the cache | 326 | // the two ranges are in reverse order, so copy them in reverse order into the cache |
| 311 | mem.copy(T, cache[A1.length() + B2.length() ..], items[A2.start..A2.end]); | 327 | mem.copy(T, cache[A1.length() + B2.length() ..], items[A2.start..A2.end]); |
| 312 | mem.copy(T, cache[A1.length()..], items[B2.start..B2.end]); | 328 | mem.copy(T, cache[A1.length()..], items[B2.start..B2.end]); |
| 313 | } else if (lessThan(items[B2.start], items[A2.end - 1])) { | 329 | } else if (lessThan(context, items[B2.start], items[A2.end - 1])) { |
| 314 | // these two ranges weren't already in order, so merge them into the cache | 330 | // these two ranges weren't already in order, so merge them into the cache |
| 315 | mergeInto(T, items, A2, B2, lessThan, cache[A1.length()..]); | 331 | mergeInto(T, items, A2, B2, context, lessThan, cache[A1.length()..]); |
| 316 | } else { | 332 | } else { |
| 317 | // copy A2 and B2 into the cache in the same order | 333 | // copy A2 and B2 into the cache in the same order |
| 318 | mem.copy(T, cache[A1.length()..], items[A2.start..A2.end]); | 334 | mem.copy(T, cache[A1.length()..], items[A2.start..A2.end]); |
| ... | @@ -324,13 +340,13 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn (lhs: T, rhs: T) bool) vo | ... | @@ -324,13 +340,13 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn (lhs: T, rhs: T) bool) vo |
| 324 | const A3 = Range.init(0, A1.length()); | 340 | const A3 = Range.init(0, A1.length()); |
| 325 | const B3 = Range.init(A1.length(), A1.length() + A2.length()); | 341 | const B3 = Range.init(A1.length(), A1.length() + A2.length()); |
| 326 | | 342 | |
| 327 | if (lessThan(cache[B3.end - 1], cache[A3.start])) { | 343 | if (lessThan(context, cache[B3.end - 1], cache[A3.start])) { |
| 328 | // the two ranges are in reverse order, so copy them in reverse order into the items | 344 | // the two ranges are in reverse order, so copy them in reverse order into the items |
| 329 | mem.copy(T, items[A1.start + A2.length() ..], cache[A3.start..A3.end]); | 345 | mem.copy(T, items[A1.start + A2.length() ..], cache[A3.start..A3.end]); |
| 330 | mem.copy(T, items[A1.start..], cache[B3.start..B3.end]); | 346 | mem.copy(T, items[A1.start..], cache[B3.start..B3.end]); |
| 331 | } else if (lessThan(cache[B3.start], cache[A3.end - 1])) { | 347 | } else if (lessThan(context, cache[B3.start], cache[A3.end - 1])) { |
| 332 | // these two ranges weren't already in order, so merge them back into the items | 348 | // these two ranges weren't already in order, so merge them back into the items |
| 333 | mergeInto(T, cache[0..], A3, B3, lessThan, items[A1.start..]); | 349 | mergeInto(T, cache[0..], A3, B3, context, lessThan, items[A1.start..]); |
| 334 | } else { | 350 | } else { |
| 335 | // copy A3 and B3 into the items in the same order | 351 | // copy A3 and B3 into the items in the same order |
| 336 | mem.copy(T, items[A1.start..], cache[A3.start..A3.end]); | 352 | mem.copy(T, items[A1.start..], cache[A3.start..A3.end]); |
| ... | @@ -347,13 +363,13 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn (lhs: T, rhs: T) bool) vo | ... | @@ -347,13 +363,13 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn (lhs: T, rhs: T) bool) vo |
| 347 | var A = iterator.nextRange(); | 363 | var A = iterator.nextRange(); |
| 348 | var B = iterator.nextRange(); | 364 | var B = iterator.nextRange(); |
| 349 | | 365 | |
| 350 | if (lessThan(items[B.end - 1], items[A.start])) { | 366 | if (lessThan(context, items[B.end - 1], items[A.start])) { |
| 351 | // the two ranges are in reverse order, so a simple rotation should fix it | 367 | // the two ranges are in reverse order, so a simple rotation should fix it |
| 352 | mem.rotate(T, items[A.start..B.end], A.length()); | 368 | mem.rotate(T, items[A.start..B.end], A.length()); |
| 353 | } else if (lessThan(items[B.start], items[A.end - 1])) { | 369 | } else if (lessThan(context, items[B.start], items[A.end - 1])) { |
| 354 | // these two ranges weren't already in order, so we'll need to merge them! | 370 | // these two ranges weren't already in order, so we'll need to merge them! |
| 355 | mem.copy(T, cache[0..], items[A.start..A.end]); | 371 | mem.copy(T, cache[0..], items[A.start..A.end]); |
| 356 | mergeExternal(T, items, A, B, lessThan, cache[0..]); | 372 | mergeExternal(T, items, A, B, context, lessThan, cache[0..]); |
| 357 | } | 373 | } |
| 358 | } | 374 | } |
| 359 | } | 375 | } |
| ... | @@ -435,7 +451,7 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn (lhs: T, rhs: T) bool) vo | ... | @@ -435,7 +451,7 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn (lhs: T, rhs: T) bool) vo |
| 435 | last = index; | 451 | last = index; |
| 436 | count += 1; | 452 | count += 1; |
| 437 | }) { | 453 | }) { |
| 438 | index = findLastForward(T, items, items[last], Range.init(last + 1, A.end), lessThan, find - count); | 454 | index = findLastForward(T, items, items[last], Range.init(last + 1, A.end), context, lessThan, find - count); |
| 439 | if (index == A.end) break; | 455 | if (index == A.end) break; |
| 440 | } | 456 | } |
| 441 | index = last; | 457 | index = last; |
| ... | @@ -493,7 +509,7 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn (lhs: T, rhs: T) bool) vo | ... | @@ -493,7 +509,7 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn (lhs: T, rhs: T) bool) vo |
| 493 | last = index - 1; | 509 | last = index - 1; |
| 494 | count += 1; | 510 | count += 1; |
| 495 | }) { | 511 | }) { |
| 496 | index = findFirstBackward(T, items, items[last], Range.init(B.start, last), lessThan, find - count); | 512 | index = findFirstBackward(T, items, items[last], Range.init(B.start, last), context, lessThan, find - count); |
| 497 | if (index == B.start) break; | 513 | if (index == B.start) break; |
| 498 | } | 514 | } |
| 499 | index = last; | 515 | index = last; |
| ... | @@ -558,7 +574,7 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn (lhs: T, rhs: T) bool) vo | ... | @@ -558,7 +574,7 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn (lhs: T, rhs: T) bool) vo |
| 558 | index = pull[pull_index].from; | 574 | index = pull[pull_index].from; |
| 559 | count = 1; | 575 | count = 1; |
| 560 | while (count < length) : (count += 1) { | 576 | while (count < length) : (count += 1) { |
| 561 | index = findFirstBackward(T, items, items[index - 1], Range.init(pull[pull_index].to, pull[pull_index].from - (count - 1)), lessThan, length - count); | 577 | index = findFirstBackward(T, items, items[index - 1], Range.init(pull[pull_index].to, pull[pull_index].from - (count - 1)), context, lessThan, length - count); |
| 562 | const range = Range.init(index + 1, pull[pull_index].from + 1); | 578 | const range = Range.init(index + 1, pull[pull_index].from + 1); |
| 563 | mem.rotate(T, items[range.start..range.end], range.length() - count); | 579 | mem.rotate(T, items[range.start..range.end], range.length() - count); |
| 564 | pull[pull_index].from = index + count; | 580 | pull[pull_index].from = index + count; |
| ... | @@ -568,7 +584,7 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn (lhs: T, rhs: T) bool) vo | ... | @@ -568,7 +584,7 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn (lhs: T, rhs: T) bool) vo |
| 568 | index = pull[pull_index].from + 1; | 584 | index = pull[pull_index].from + 1; |
| 569 | count = 1; | 585 | count = 1; |
| 570 | while (count < length) : (count += 1) { | 586 | while (count < length) : (count += 1) { |
| 571 | index = findLastForward(T, items, items[index], Range.init(index, pull[pull_index].to), lessThan, length - count); | 587 | index = findLastForward(T, items, items[index], Range.init(index, pull[pull_index].to), context, lessThan, length - count); |
| 572 | const range = Range.init(pull[pull_index].from, index - 1); | 588 | const range = Range.init(pull[pull_index].from, index - 1); |
| 573 | mem.rotate(T, items[range.start..range.end], count); | 589 | mem.rotate(T, items[range.start..range.end], count); |
| 574 | pull[pull_index].from = index - 1 - count; | 590 | pull[pull_index].from = index - 1 - count; |
| ... | @@ -615,10 +631,10 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn (lhs: T, rhs: T) bool) vo | ... | @@ -615,10 +631,10 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn (lhs: T, rhs: T) bool) vo |
| 615 | } | 631 | } |
| 616 | } | 632 | } |
| 617 | | 633 | |
| 618 | if (lessThan(items[B.end - 1], items[A.start])) { | 634 | if (lessThan(context, items[B.end - 1], items[A.start])) { |
| 619 | // the two ranges are in reverse order, so a simple rotation should fix it | 635 | // the two ranges are in reverse order, so a simple rotation should fix it |
| 620 | mem.rotate(T, items[A.start..B.end], A.length()); | 636 | mem.rotate(T, items[A.start..B.end], A.length()); |
| 621 | } else if (lessThan(items[A.end], items[A.end - 1])) { | 637 | } else if (lessThan(context, items[A.end], items[A.end - 1])) { |
| 622 | // these two ranges weren't already in order, so we'll need to merge them! | 638 | // these two ranges weren't already in order, so we'll need to merge them! |
| 623 | var findA: usize = undefined; | 639 | var findA: usize = undefined; |
| 624 | | 640 | |
| ... | @@ -656,16 +672,16 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn (lhs: T, rhs: T) bool) vo | ... | @@ -656,16 +672,16 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn (lhs: T, rhs: T) bool) vo |
| 656 | while (true) { | 672 | while (true) { |
| 657 | // if there's a previous B block and the first value of the minimum A block is <= the last value of the previous B block, | 673 | // if there's a previous B block and the first value of the minimum A block is <= the last value of the previous B block, |
| 658 | // then drop that minimum A block behind. or if there are no B blocks left then keep dropping the remaining A blocks. | 674 | // then drop that minimum A block behind. or if there are no B blocks left then keep dropping the remaining A blocks. |
| 659 | if ((lastB.length() > 0 and !lessThan(items[lastB.end - 1], items[indexA])) or blockB.length() == 0) { | 675 | if ((lastB.length() > 0 and !lessThan(context, items[lastB.end - 1], items[indexA])) or blockB.length() == 0) { |
| 660 | // figure out where to split the previous B block, and rotate it at the split | 676 | // figure out where to split the previous B block, and rotate it at the split |
| 661 | const B_split = binaryFirst(T, items, items[indexA], lastB, lessThan); | 677 | const B_split = binaryFirst(T, items, items[indexA], lastB, context, lessThan); |
| 662 | const B_remaining = lastB.end - B_split; | 678 | const B_remaining = lastB.end - B_split; |
| 663 | | 679 | |
| 664 | // swap the minimum A block to the beginning of the rolling A blocks | 680 | // swap the minimum A block to the beginning of the rolling A blocks |
| 665 | var minA = blockA.start; | 681 | var minA = blockA.start; |
| 666 | findA = minA + block_size; | 682 | findA = minA + block_size; |
| 667 | while (findA < blockA.end) : (findA += block_size) { | 683 | while (findA < blockA.end) : (findA += block_size) { |
| 668 | if (lessThan(items[findA], items[minA])) { | 684 | if (lessThan(context, items[findA], items[minA])) { |
| 669 | minA = findA; | 685 | minA = findA; |
| 670 | } | 686 | } |
| 671 | } | 687 | } |
| ... | @@ -681,11 +697,11 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn (lhs: T, rhs: T) bool) vo | ... | @@ -681,11 +697,11 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn (lhs: T, rhs: T) bool) vo |
| 681 | // or failing that we'll use a strictly in-place merge algorithm (MergeInPlace) | 697 | // or failing that we'll use a strictly in-place merge algorithm (MergeInPlace) |
| 682 | | 698 | |
| 683 | if (lastA.length() <= cache.len) { | 699 | if (lastA.length() <= cache.len) { |
| 684 | mergeExternal(T, items, lastA, Range.init(lastA.end, B_split), lessThan, cache[0..]); | 700 | mergeExternal(T, items, lastA, Range.init(lastA.end, B_split), context, lessThan, cache[0..]); |
| 685 | } else if (buffer2.length() > 0) { | 701 | } else if (buffer2.length() > 0) { |
| 686 | mergeInternal(T, items, lastA, Range.init(lastA.end, B_split), lessThan, buffer2); | 702 | mergeInternal(T, items, lastA, Range.init(lastA.end, B_split), context, lessThan, buffer2); |
| 687 | } else { | 703 | } else { |
| 688 | mergeInPlace(T, items, lastA, Range.init(lastA.end, B_split), lessThan); | 704 | mergeInPlace(T, items, lastA, Range.init(lastA.end, B_split), context, lessThan); |
| 689 | } | 705 | } |
| 690 | | 706 | |
| 691 | if (buffer2.length() > 0 or block_size <= cache.len) { | 707 | if (buffer2.length() > 0 or block_size <= cache.len) { |
| ... | @@ -741,11 +757,11 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn (lhs: T, rhs: T) bool) vo | ... | @@ -741,11 +757,11 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn (lhs: T, rhs: T) bool) vo |
| 741 | | 757 | |
| 742 | // merge the last A block with the remaining B values | 758 | // merge the last A block with the remaining B values |
| 743 | if (lastA.length() <= cache.len) { | 759 | if (lastA.length() <= cache.len) { |
| 744 | mergeExternal(T, items, lastA, Range.init(lastA.end, B.end), lessThan, cache[0..]); | 760 | mergeExternal(T, items, lastA, Range.init(lastA.end, B.end), context, lessThan, cache[0..]); |
| 745 | } else if (buffer2.length() > 0) { | 761 | } else if (buffer2.length() > 0) { |
| 746 | mergeInternal(T, items, lastA, Range.init(lastA.end, B.end), lessThan, buffer2); | 762 | mergeInternal(T, items, lastA, Range.init(lastA.end, B.end), context, lessThan, buffer2); |
| 747 | } else { | 763 | } else { |
| 748 | mergeInPlace(T, items, lastA, Range.init(lastA.end, B.end), lessThan); | 764 | mergeInPlace(T, items, lastA, Range.init(lastA.end, B.end), context, lessThan); |
| 749 | } | 765 | } |
| 750 | } | 766 | } |
| 751 | } | 767 | } |
| ... | @@ -755,7 +771,7 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn (lhs: T, rhs: T) bool) vo | ... | @@ -755,7 +771,7 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn (lhs: T, rhs: T) bool) vo |
| 755 | | 771 | |
| 756 | // while an unstable sort like quicksort could be applied here, in benchmarks it was consistently slightly slower than a simple insertion sort, | 772 | // while an unstable sort like quicksort could be applied here, in benchmarks it was consistently slightly slower than a simple insertion sort, |
| 757 | // even for tens of millions of items. this may be because insertion sort is quite fast when the data is already somewhat sorted, like it is here | 773 | // even for tens of millions of items. this may be because insertion sort is quite fast when the data is already somewhat sorted, like it is here |
| 758 | insertionSort(T, items[buffer2.start..buffer2.end], lessThan); | 774 | insertionSort(T, items[buffer2.start..buffer2.end], context, lessThan); |
| 759 | | 775 | |
| 760 | pull_index = 0; | 776 | pull_index = 0; |
| 761 | while (pull_index < 2) : (pull_index += 1) { | 777 | while (pull_index < 2) : (pull_index += 1) { |
| ... | @@ -764,7 +780,7 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn (lhs: T, rhs: T) bool) vo | ... | @@ -764,7 +780,7 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn (lhs: T, rhs: T) bool) vo |
| 764 | // the values were pulled out to the left, so redistribute them back to the right | 780 | // the values were pulled out to the left, so redistribute them back to the right |
| 765 | var buffer = Range.init(pull[pull_index].range.start, pull[pull_index].range.start + pull[pull_index].count); | 781 | var buffer = Range.init(pull[pull_index].range.start, pull[pull_index].range.start + pull[pull_index].count); |
| 766 | while (buffer.length() > 0) { | 782 | while (buffer.length() > 0) { |
| 767 | index = findFirstForward(T, items, items[buffer.start], Range.init(buffer.end, pull[pull_index].range.end), lessThan, unique); | 783 | index = findFirstForward(T, items, items[buffer.start], Range.init(buffer.end, pull[pull_index].range.end), context, lessThan, unique); |
| 768 | const amount = index - buffer.end; | 784 | const amount = index - buffer.end; |
| 769 | mem.rotate(T, items[buffer.start..index], buffer.length()); | 785 | mem.rotate(T, items[buffer.start..index], buffer.length()); |
| 770 | buffer.start += (amount + 1); | 786 | buffer.start += (amount + 1); |
| ... | @@ -775,7 +791,7 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn (lhs: T, rhs: T) bool) vo | ... | @@ -775,7 +791,7 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn (lhs: T, rhs: T) bool) vo |
| 775 | // the values were pulled out to the right, so redistribute them back to the left | 791 | // the values were pulled out to the right, so redistribute them back to the left |
| 776 | var buffer = Range.init(pull[pull_index].range.end - pull[pull_index].count, pull[pull_index].range.end); | 792 | var buffer = Range.init(pull[pull_index].range.end - pull[pull_index].count, pull[pull_index].range.end); |
| 777 | while (buffer.length() > 0) { | 793 | while (buffer.length() > 0) { |
| 778 | index = findLastBackward(T, items, items[buffer.end - 1], Range.init(pull[pull_index].range.start, buffer.start), lessThan, unique); | 794 | index = findLastBackward(T, items, items[buffer.end - 1], Range.init(pull[pull_index].range.start, buffer.start), context, lessThan, unique); |
| 779 | const amount = buffer.start - index; | 795 | const amount = buffer.start - index; |
| 780 | mem.rotate(T, items[index..buffer.end], amount); | 796 | mem.rotate(T, items[index..buffer.end], amount); |
| 781 | buffer.start -= amount; | 797 | buffer.start -= amount; |
| ... | @@ -792,7 +808,14 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn (lhs: T, rhs: T) bool) vo | ... | @@ -792,7 +808,14 @@ pub fn sort(comptime T: type, items: []T, lessThan: fn (lhs: T, rhs: T) bool) vo |
| 792 | } | 808 | } |
| 793 | | 809 | |
| 794 | // merge operation without a buffer | 810 | // merge operation without a buffer |
| 795 | fn mergeInPlace(comptime T: type, items: []T, A_arg: Range, B_arg: Range, lessThan: fn (T, T) bool) void { | 811 | fn mergeInPlace( |
| | 812 | comptime T: type, |
| | 813 | items: []T, |
| | 814 | A_arg: Range, |
| | 815 | B_arg: Range, |
| | 816 | context: var, |
| | 817 | comptime lessThan: fn (@TypeOf(context), T, T) bool, |
| | 818 | ) void { |
| 796 | if (A_arg.length() == 0 or B_arg.length() == 0) return; | 819 | if (A_arg.length() == 0 or B_arg.length() == 0) return; |
| 797 | | 820 | |
| 798 | // this just repeatedly binary searches into B and rotates A into position. | 821 | // this just repeatedly binary searches into B and rotates A into position. |
| ... | @@ -818,7 +841,7 @@ fn mergeInPlace(comptime T: type, items: []T, A_arg: Range, B_arg: Range, lessTh | ... | @@ -818,7 +841,7 @@ fn mergeInPlace(comptime T: type, items: []T, A_arg: Range, B_arg: Range, lessTh |
| 818 | | 841 | |
| 819 | while (true) { | 842 | while (true) { |
| 820 | // find the first place in B where the first item in A needs to be inserted | 843 | // find the first place in B where the first item in A needs to be inserted |
| 821 | const mid = binaryFirst(T, items, items[A.start], B, lessThan); | 844 | const mid = binaryFirst(T, items, items[A.start], B, context, lessThan); |
| 822 | | 845 | |
| 823 | // rotate A into place | 846 | // rotate A into place |
| 824 | const amount = mid - A.end; | 847 | const amount = mid - A.end; |
| ... | @@ -828,13 +851,21 @@ fn mergeInPlace(comptime T: type, items: []T, A_arg: Range, B_arg: Range, lessTh | ... | @@ -828,13 +851,21 @@ fn mergeInPlace(comptime T: type, items: []T, A_arg: Range, B_arg: Range, lessTh |
| 828 | // calculate the new A and B ranges | 851 | // calculate the new A and B ranges |
| 829 | B.start = mid; | 852 | B.start = mid; |
| 830 | A = Range.init(A.start + amount, B.start); | 853 | A = Range.init(A.start + amount, B.start); |
| 831 | A.start = binaryLast(T, items, items[A.start], A, lessThan); | 854 | A.start = binaryLast(T, items, items[A.start], A, context, lessThan); |
| 832 | if (A.length() == 0) break; | 855 | if (A.length() == 0) break; |
| 833 | } | 856 | } |
| 834 | } | 857 | } |
| 835 | | 858 | |
| 836 | // merge operation using an internal buffer | 859 | // merge operation using an internal buffer |
| 837 | fn mergeInternal(comptime T: type, items: []T, A: Range, B: Range, lessThan: fn (T, T) bool, buffer: Range) void { | 860 | fn mergeInternal( |
| | 861 | comptime T: type, |
| | 862 | items: []T, |
| | 863 | A: Range, |
| | 864 | B: Range, |
| | 865 | context: var, |
| | 866 | comptime lessThan: fn (@TypeOf(context), T, T) bool, |
| | 867 | buffer: Range, |
| | 868 | ) void { |
| 838 | // whenever we find a value to add to the final array, swap it with the value that's already in that spot | 869 | // whenever we find a value to add to the final array, swap it with the value that's already in that spot |
| 839 | // when this algorithm is finished, 'buffer' will contain its original contents, but in a different order | 870 | // when this algorithm is finished, 'buffer' will contain its original contents, but in a different order |
| 840 | var A_count: usize = 0; | 871 | var A_count: usize = 0; |
| ... | @@ -843,7 +874,7 @@ fn mergeInternal(comptime T: type, items: []T, A: Range, B: Range, lessThan: fn | ... | @@ -843,7 +874,7 @@ fn mergeInternal(comptime T: type, items: []T, A: Range, B: Range, lessThan: fn |
| 843 | | 874 | |
| 844 | if (B.length() > 0 and A.length() > 0) { | 875 | if (B.length() > 0 and A.length() > 0) { |
| 845 | while (true) { | 876 | while (true) { |
| 846 | if (!lessThan(items[B.start + B_count], items[buffer.start + A_count])) { | 877 | if (!lessThan(context, items[B.start + B_count], items[buffer.start + A_count])) { |
| 847 | mem.swap(T, &items[A.start + insert], &items[buffer.start + A_count]); | 878 | mem.swap(T, &items[A.start + insert], &items[buffer.start + A_count]); |
| 848 | A_count += 1; | 879 | A_count += 1; |
| 849 | insert += 1; | 880 | insert += 1; |
| ... | @@ -870,63 +901,102 @@ fn blockSwap(comptime T: type, items: []T, start1: usize, start2: usize, block_s | ... | @@ -870,63 +901,102 @@ fn blockSwap(comptime T: type, items: []T, start1: usize, start2: usize, block_s |
| 870 | | 901 | |
| 871 | // combine a linear search with a binary search to reduce the number of comparisons in situations | 902 | // combine a linear search with a binary search to reduce the number of comparisons in situations |
| 872 | // where have some idea as to how many unique values there are and where the next value might be | 903 | // where have some idea as to how many unique values there are and where the next value might be |
| 873 | fn findFirstForward(comptime T: type, items: []T, value: T, range: Range, lessThan: fn (T, T) bool, unique: usize) usize { | 904 | fn findFirstForward( |
| | 905 | comptime T: type, |
| | 906 | items: []T, |
| | 907 | value: T, |
| | 908 | range: Range, |
| | 909 | context: var, |
| | 910 | comptime lessThan: fn (@TypeOf(context), T, T) bool, |
| | 911 | unique: usize, |
| | 912 | ) usize { |
| 874 | if (range.length() == 0) return range.start; | 913 | if (range.length() == 0) return range.start; |
| 875 | const skip = math.max(range.length() / unique, @as(usize, 1)); | 914 | const skip = math.max(range.length() / unique, @as(usize, 1)); |
| 876 | | 915 | |
| 877 | var index = range.start + skip; | 916 | var index = range.start + skip; |
| 878 | while (lessThan(items[index - 1], value)) : (index += skip) { | 917 | while (lessThan(context, items[index - 1], value)) : (index += skip) { |
| 879 | if (index >= range.end - skip) { | 918 | if (index >= range.end - skip) { |
| 880 | return binaryFirst(T, items, value, Range.init(index, range.end), lessThan); | 919 | return binaryFirst(T, items, value, Range.init(index, range.end), context, lessThan); |
| 881 | } | 920 | } |
| 882 | } | 921 | } |
| 883 | | 922 | |
| 884 | return binaryFirst(T, items, value, Range.init(index - skip, index), lessThan); | 923 | return binaryFirst(T, items, value, Range.init(index - skip, index), context, lessThan); |
| 885 | } | 924 | } |
| 886 | | 925 | |
| 887 | fn findFirstBackward(comptime T: type, items: []T, value: T, range: Range, lessThan: fn (T, T) bool, unique: usize) usize { | 926 | fn findFirstBackward( |
| | 927 | comptime T: type, |
| | 928 | items: []T, |
| | 929 | value: T, |
| | 930 | range: Range, |
| | 931 | context: var, |
| | 932 | comptime lessThan: fn (@TypeOf(context), T, T) bool, |
| | 933 | unique: usize, |
| | 934 | ) usize { |
| 888 | if (range.length() == 0) return range.start; | 935 | if (range.length() == 0) return range.start; |
| 889 | const skip = math.max(range.length() / unique, @as(usize, 1)); | 936 | const skip = math.max(range.length() / unique, @as(usize, 1)); |
| 890 | | 937 | |
| 891 | var index = range.end - skip; | 938 | var index = range.end - skip; |
| 892 | while (index > range.start and !lessThan(items[index - 1], value)) : (index -= skip) { | 939 | while (index > range.start and !lessThan(context, items[index - 1], value)) : (index -= skip) { |
| 893 | if (index < range.start + skip) { | 940 | if (index < range.start + skip) { |
| 894 | return binaryFirst(T, items, value, Range.init(range.start, index), lessThan); | 941 | return binaryFirst(T, items, value, Range.init(range.start, index), context, lessThan); |
| 895 | } | 942 | } |
| 896 | } | 943 | } |
| 897 | | 944 | |
| 898 | return binaryFirst(T, items, value, Range.init(index, index + skip), lessThan); | 945 | return binaryFirst(T, items, value, Range.init(index, index + skip), context, lessThan); |
| 899 | } | 946 | } |
| 900 | | 947 | |
| 901 | fn findLastForward(comptime T: type, items: []T, value: T, range: Range, lessThan: fn (T, T) bool, unique: usize) usize { | 948 | fn findLastForward( |
| | 949 | comptime T: type, |
| | 950 | items: []T, |
| | 951 | value: T, |
| | 952 | range: Range, |
| | 953 | context: var, |
| | 954 | comptime lessThan: fn (@TypeOf(context), T, T) bool, |
| | 955 | unique: usize, |
| | 956 | ) usize { |
| 902 | if (range.length() == 0) return range.start; | 957 | if (range.length() == 0) return range.start; |
| 903 | const skip = math.max(range.length() / unique, @as(usize, 1)); | 958 | const skip = math.max(range.length() / unique, @as(usize, 1)); |
| 904 | | 959 | |
| 905 | var index = range.start + skip; | 960 | var index = range.start + skip; |
| 906 | while (!lessThan(value, items[index - 1])) : (index += skip) { | 961 | while (!lessThan(context, value, items[index - 1])) : (index += skip) { |
| 907 | if (index >= range.end - skip) { | 962 | if (index >= range.end - skip) { |
| 908 | return binaryLast(T, items, value, Range.init(index, range.end), lessThan); | 963 | return binaryLast(T, items, value, Range.init(index, range.end), context, lessThan); |
| 909 | } | 964 | } |
| 910 | } | 965 | } |
| 911 | | 966 | |
| 912 | return binaryLast(T, items, value, Range.init(index - skip, index), lessThan); | 967 | return binaryLast(T, items, value, Range.init(index - skip, index), context, lessThan); |
| 913 | } | 968 | } |
| 914 | | 969 | |
| 915 | fn findLastBackward(comptime T: type, items: []T, value: T, range: Range, lessThan: fn (T, T) bool, unique: usize) usize { | 970 | fn findLastBackward( |
| | 971 | comptime T: type, |
| | 972 | items: []T, |
| | 973 | value: T, |
| | 974 | range: Range, |
| | 975 | context: var, |
| | 976 | comptime lessThan: fn (@TypeOf(context), T, T) bool, |
| | 977 | unique: usize, |
| | 978 | ) usize { |
| 916 | if (range.length() == 0) return range.start; | 979 | if (range.length() == 0) return range.start; |
| 917 | const skip = math.max(range.length() / unique, @as(usize, 1)); | 980 | const skip = math.max(range.length() / unique, @as(usize, 1)); |
| 918 | | 981 | |
| 919 | var index = range.end - skip; | 982 | var index = range.end - skip; |
| 920 | while (index > range.start and lessThan(value, items[index - 1])) : (index -= skip) { | 983 | while (index > range.start and lessThan(context, value, items[index - 1])) : (index -= skip) { |
| 921 | if (index < range.start + skip) { | 984 | if (index < range.start + skip) { |
| 922 | return binaryLast(T, items, value, Range.init(range.start, index), lessThan); | 985 | return binaryLast(T, items, value, Range.init(range.start, index), context, lessThan); |
| 923 | } | 986 | } |
| 924 | } | 987 | } |
| 925 | | 988 | |
| 926 | return binaryLast(T, items, value, Range.init(index, index + skip), lessThan); | 989 | return binaryLast(T, items, value, Range.init(index, index + skip), context, lessThan); |
| 927 | } | 990 | } |
| 928 | | 991 | |
| 929 | fn binaryFirst(comptime T: type, items: []T, value: T, range: Range, lessThan: fn (T, T) bool) usize { | 992 | fn binaryFirst( |
| | 993 | comptime T: type, |
| | 994 | items: []T, |
| | 995 | value: T, |
| | 996 | range: Range, |
| | 997 | context: var, |
| | 998 | comptime lessThan: fn (@TypeOf(context), T, T) bool, |
| | 999 | ) usize { |
| 930 | var curr = range.start; | 1000 | var curr = range.start; |
| 931 | var size = range.length(); | 1001 | var size = range.length(); |
| 932 | if (range.start >= range.end) return range.end; | 1002 | if (range.start >= range.end) return range.end; |
| ... | @@ -935,14 +1005,21 @@ fn binaryFirst(comptime T: type, items: []T, value: T, range: Range, lessThan: f | ... | @@ -935,14 +1005,21 @@ fn binaryFirst(comptime T: type, items: []T, value: T, range: Range, lessThan: f |
| 935 | | 1005 | |
| 936 | size /= 2; | 1006 | size /= 2; |
| 937 | const mid = items[curr + size]; | 1007 | const mid = items[curr + size]; |
| 938 | if (lessThan(mid, value)) { | 1008 | if (lessThan(context, mid, value)) { |
| 939 | curr += size + offset; | 1009 | curr += size + offset; |
| 940 | } | 1010 | } |
| 941 | } | 1011 | } |
| 942 | return curr; | 1012 | return curr; |
| 943 | } | 1013 | } |
| 944 | | 1014 | |
| 945 | fn binaryLast(comptime T: type, items: []T, value: T, range: Range, lessThan: fn (T, T) bool) usize { | 1015 | fn binaryLast( |
| | 1016 | comptime T: type, |
| | 1017 | items: []T, |
| | 1018 | value: T, |
| | 1019 | range: Range, |
| | 1020 | context: var, |
| | 1021 | comptime lessThan: fn (@TypeOf(context), T, T) bool, |
| | 1022 | ) usize { |
| 946 | var curr = range.start; | 1023 | var curr = range.start; |
| 947 | var size = range.length(); | 1024 | var size = range.length(); |
| 948 | if (range.start >= range.end) return range.end; | 1025 | if (range.start >= range.end) return range.end; |
| ... | @@ -951,14 +1028,22 @@ fn binaryLast(comptime T: type, items: []T, value: T, range: Range, lessThan: fn | ... | @@ -951,14 +1028,22 @@ fn binaryLast(comptime T: type, items: []T, value: T, range: Range, lessThan: fn |
| 951 | | 1028 | |
| 952 | size /= 2; | 1029 | size /= 2; |
| 953 | const mid = items[curr + size]; | 1030 | const mid = items[curr + size]; |
| 954 | if (!lessThan(value, mid)) { | 1031 | if (!lessThan(context, value, mid)) { |
| 955 | curr += size + offset; | 1032 | curr += size + offset; |
| 956 | } | 1033 | } |
| 957 | } | 1034 | } |
| 958 | return curr; | 1035 | return curr; |
| 959 | } | 1036 | } |
| 960 | | 1037 | |
| 961 | fn mergeInto(comptime T: type, from: []T, A: Range, B: Range, lessThan: fn (T, T) bool, into: []T) void { | 1038 | fn mergeInto( |
| | 1039 | comptime T: type, |
| | 1040 | from: []T, |
| | 1041 | A: Range, |
| | 1042 | B: Range, |
| | 1043 | context: var, |
| | 1044 | comptime lessThan: fn (@TypeOf(context), T, T) bool, |
| | 1045 | into: []T, |
| | 1046 | ) void { |
| 962 | var A_index: usize = A.start; | 1047 | var A_index: usize = A.start; |
| 963 | var B_index: usize = B.start; | 1048 | var B_index: usize = B.start; |
| 964 | const A_last = A.end; | 1049 | const A_last = A.end; |
| ... | @@ -966,7 +1051,7 @@ fn mergeInto(comptime T: type, from: []T, A: Range, B: Range, lessThan: fn (T, T | ... | @@ -966,7 +1051,7 @@ fn mergeInto(comptime T: type, from: []T, A: Range, B: Range, lessThan: fn (T, T |
| 966 | var insert_index: usize = 0; | 1051 | var insert_index: usize = 0; |
| 967 | | 1052 | |
| 968 | while (true) { | 1053 | while (true) { |
| 969 | if (!lessThan(from[B_index], from[A_index])) { | 1054 | if (!lessThan(context, from[B_index], from[A_index])) { |
| 970 | into[insert_index] = from[A_index]; | 1055 | into[insert_index] = from[A_index]; |
| 971 | A_index += 1; | 1056 | A_index += 1; |
| 972 | insert_index += 1; | 1057 | insert_index += 1; |
| ... | @@ -988,7 +1073,15 @@ fn mergeInto(comptime T: type, from: []T, A: Range, B: Range, lessThan: fn (T, T | ... | @@ -988,7 +1073,15 @@ fn mergeInto(comptime T: type, from: []T, A: Range, B: Range, lessThan: fn (T, T |
| 988 | } | 1073 | } |
| 989 | } | 1074 | } |
| 990 | | 1075 | |
| 991 | fn mergeExternal(comptime T: type, items: []T, A: Range, B: Range, lessThan: fn (T, T) bool, cache: []T) void { | 1076 | fn mergeExternal( |
| | 1077 | comptime T: type, |
| | 1078 | items: []T, |
| | 1079 | A: Range, |
| | 1080 | B: Range, |
| | 1081 | context: var, |
| | 1082 | comptime lessThan: fn (@TypeOf(context), T, T) bool, |
| | 1083 | cache: []T, |
| | 1084 | ) void { |
| 992 | // A fits into the cache, so use that instead of the internal buffer | 1085 | // A fits into the cache, so use that instead of the internal buffer |
| 993 | var A_index: usize = 0; | 1086 | var A_index: usize = 0; |
| 994 | var B_index: usize = B.start; | 1087 | var B_index: usize = B.start; |
| ... | @@ -998,7 +1091,7 @@ fn mergeExternal(comptime T: type, items: []T, A: Range, B: Range, lessThan: fn | ... | @@ -998,7 +1091,7 @@ fn mergeExternal(comptime T: type, items: []T, A: Range, B: Range, lessThan: fn |
| 998 | | 1091 | |
| 999 | if (B.length() > 0 and A.length() > 0) { | 1092 | if (B.length() > 0 and A.length() > 0) { |
| 1000 | while (true) { | 1093 | while (true) { |
| 1001 | if (!lessThan(items[B_index], cache[A_index])) { | 1094 | if (!lessThan(context, items[B_index], cache[A_index])) { |
| 1002 | items[insert_index] = cache[A_index]; | 1095 | items[insert_index] = cache[A_index]; |
| 1003 | A_index += 1; | 1096 | A_index += 1; |
| 1004 | insert_index += 1; | 1097 | insert_index += 1; |
| ... | @@ -1016,17 +1109,25 @@ fn mergeExternal(comptime T: type, items: []T, A: Range, B: Range, lessThan: fn | ... | @@ -1016,17 +1109,25 @@ fn mergeExternal(comptime T: type, items: []T, A: Range, B: Range, lessThan: fn |
| 1016 | mem.copy(T, items[insert_index..], cache[A_index..A_last]); | 1109 | mem.copy(T, items[insert_index..], cache[A_index..A_last]); |
| 1017 | } | 1110 | } |
| 1018 | | 1111 | |
| 1019 | fn swap(comptime T: type, items: []T, lessThan: fn (lhs: T, rhs: T) bool, order: *[8]u8, x: usize, y: usize) void { | 1112 | fn swap( |
| 1020 | if (lessThan(items[y], items[x]) or ((order.*)[x] > (order.*)[y] and !lessThan(items[x], items[y]))) { | 1113 | comptime T: type, |
| | 1114 | items: []T, |
| | 1115 | context: var, |
| | 1116 | comptime lessThan: fn (@TypeOf(context), lhs: T, rhs: T) bool, |
| | 1117 | order: *[8]u8, |
| | 1118 | x: usize, |
| | 1119 | y: usize, |
| | 1120 | ) void { |
| | 1121 | if (lessThan(context, items[y], items[x]) or ((order.*)[x] > (order.*)[y] and !lessThan(context, items[x], items[y]))) { |
| 1021 | mem.swap(T, &items[x], &items[y]); | 1122 | mem.swap(T, &items[x], &items[y]); |
| 1022 | mem.swap(u8, &(order.*)[x], &(order.*)[y]); | 1123 | mem.swap(u8, &(order.*)[x], &(order.*)[y]); |
| 1023 | } | 1124 | } |
| 1024 | } | 1125 | } |
| 1025 | | 1126 | |
| 1026 | // Use these to generate a comparator function for a given type. e.g. `sort(u8, slice, asc(u8))`. | 1127 | /// Use to generate a comparator function for a given type. e.g. `sort(u8, slice, asc(u8))`. |
| 1027 | pub fn asc(comptime T: type) fn (T, T) bool { | 1128 | pub fn asc(comptime T: type) fn (void, T, T) bool { |
| 1028 | const impl = struct { | 1129 | const impl = struct { |
| 1029 | fn inner(a: T, b: T) bool { | 1130 | fn inner(context: void, a: T, b: T) bool { |
| 1030 | return a < b; | 1131 | return a < b; |
| 1031 | } | 1132 | } |
| 1032 | }; | 1133 | }; |
| ... | @@ -1034,9 +1135,10 @@ pub fn asc(comptime T: type) fn (T, T) bool { | ... | @@ -1034,9 +1135,10 @@ pub fn asc(comptime T: type) fn (T, T) bool { |
| 1034 | return impl.inner; | 1135 | return impl.inner; |
| 1035 | } | 1136 | } |
| 1036 | | 1137 | |
| 1037 | pub fn desc(comptime T: type) fn (T, T) bool { | 1138 | /// Use to generate a comparator function for a given type. e.g. `sort(u8, slice, asc(u8))`. |
| | 1139 | pub fn desc(comptime T: type) fn (void, T, T) bool { |
| 1038 | const impl = struct { | 1140 | const impl = struct { |
| 1039 | fn inner(a: T, b: T) bool { | 1141 | fn inner(context: void, a: T, b: T) bool { |
| 1040 | return a > b; | 1142 | return a > b; |
| 1041 | } | 1143 | } |
| 1042 | }; | 1144 | }; |
| ... | @@ -1085,7 +1187,7 @@ fn testStableSort() void { | ... | @@ -1085,7 +1187,7 @@ fn testStableSort() void { |
| 1085 | }, | 1187 | }, |
| 1086 | }; | 1188 | }; |
| 1087 | for (cases) |*case| { | 1189 | for (cases) |*case| { |
| 1088 | insertionSort(IdAndValue, (case.*)[0..], cmpByValue); | 1190 | insertionSort(IdAndValue, (case.*)[0..], {}, cmpByValue); |
| 1089 | for (case.*) |item, i| { | 1191 | for (case.*) |item, i| { |
| 1090 | testing.expect(item.id == expected[i].id); | 1192 | testing.expect(item.id == expected[i].id); |
| 1091 | testing.expect(item.value == expected[i].value); | 1193 | testing.expect(item.value == expected[i].value); |
| ... | @@ -1096,11 +1198,16 @@ const IdAndValue = struct { | ... | @@ -1096,11 +1198,16 @@ const IdAndValue = struct { |
| 1096 | id: usize, | 1198 | id: usize, |
| 1097 | value: i32, | 1199 | value: i32, |
| 1098 | }; | 1200 | }; |
| 1099 | fn cmpByValue(a: IdAndValue, b: IdAndValue) bool { | 1201 | fn cmpByValue(context: void, a: IdAndValue, b: IdAndValue) bool { |
| 1100 | return asc(i32)(a.value, b.value); | 1202 | return asc_i32(context, a.value, b.value); |
| 1101 | } | 1203 | } |
| 1102 | | 1204 | |
| 1103 | test "std.sort" { | 1205 | const asc_u8 = asc(u8); |
| | 1206 | const asc_i32 = asc(i32); |
| | 1207 | const desc_u8 = desc(u8); |
| | 1208 | const desc_i32 = desc(i32); |
| | 1209 | |
| | 1210 | test "sort" { |
| 1104 | const u8cases = [_][]const []const u8{ | 1211 | const u8cases = [_][]const []const u8{ |
| 1105 | &[_][]const u8{ | 1212 | &[_][]const u8{ |
| 1106 | "", | 1213 | "", |
| ... | @@ -1132,7 +1239,7 @@ test "std.sort" { | ... | @@ -1132,7 +1239,7 @@ test "std.sort" { |
| 1132 | var buf: [8]u8 = undefined; | 1239 | var buf: [8]u8 = undefined; |
| 1133 | const slice = buf[0..case[0].len]; | 1240 | const slice = buf[0..case[0].len]; |
| 1134 | mem.copy(u8, slice, case[0]); | 1241 | mem.copy(u8, slice, case[0]); |
| 1135 | sort(u8, slice, asc(u8)); | 1242 | sort(u8, slice, {}, asc_u8); |
| 1136 | testing.expect(mem.eql(u8, slice, case[1])); | 1243 | testing.expect(mem.eql(u8, slice, case[1])); |
| 1137 | } | 1244 | } |
| 1138 | | 1245 | |
| ... | @@ -1167,12 +1274,12 @@ test "std.sort" { | ... | @@ -1167,12 +1274,12 @@ test "std.sort" { |
| 1167 | var buf: [8]i32 = undefined; | 1274 | var buf: [8]i32 = undefined; |
| 1168 | const slice = buf[0..case[0].len]; | 1275 | const slice = buf[0..case[0].len]; |
| 1169 | mem.copy(i32, slice, case[0]); | 1276 | mem.copy(i32, slice, case[0]); |
| 1170 | sort(i32, slice, asc(i32)); | 1277 | sort(i32, slice, {}, asc_i32); |
| 1171 | testing.expect(mem.eql(i32, slice, case[1])); | 1278 | testing.expect(mem.eql(i32, slice, case[1])); |
| 1172 | } | 1279 | } |
| 1173 | } | 1280 | } |
| 1174 | | 1281 | |
| 1175 | test "std.sort descending" { | 1282 | test "sort descending" { |
| 1176 | const rev_cases = [_][]const []const i32{ | 1283 | const rev_cases = [_][]const []const i32{ |
| 1177 | &[_][]const i32{ | 1284 | &[_][]const i32{ |
| 1178 | &[_]i32{}, | 1285 | &[_]i32{}, |
| ... | @@ -1204,14 +1311,14 @@ test "std.sort descending" { | ... | @@ -1204,14 +1311,14 @@ test "std.sort descending" { |
| 1204 | var buf: [8]i32 = undefined; | 1311 | var buf: [8]i32 = undefined; |
| 1205 | const slice = buf[0..case[0].len]; | 1312 | const slice = buf[0..case[0].len]; |
| 1206 | mem.copy(i32, slice, case[0]); | 1313 | mem.copy(i32, slice, case[0]); |
| 1207 | sort(i32, slice, desc(i32)); | 1314 | sort(i32, slice, {}, desc_i32); |
| 1208 | testing.expect(mem.eql(i32, slice, case[1])); | 1315 | testing.expect(mem.eql(i32, slice, case[1])); |
| 1209 | } | 1316 | } |
| 1210 | } | 1317 | } |
| 1211 | | 1318 | |
| 1212 | test "another sort case" { | 1319 | test "another sort case" { |
| 1213 | var arr = [_]i32{ 5, 3, 1, 2, 4 }; | 1320 | var arr = [_]i32{ 5, 3, 1, 2, 4 }; |
| 1214 | sort(i32, arr[0..], asc(i32)); | 1321 | sort(i32, arr[0..], {}, asc_i32); |
| 1215 | | 1322 | |
| 1216 | testing.expect(mem.eql(i32, &arr, &[_]i32{ 1, 2, 3, 4, 5 })); | 1323 | testing.expect(mem.eql(i32, &arr, &[_]i32{ 1, 2, 3, 4, 5 })); |
| 1217 | } | 1324 | } |
| ... | @@ -1236,7 +1343,7 @@ fn fuzzTest(rng: *std.rand.Random) !void { | ... | @@ -1236,7 +1343,7 @@ fn fuzzTest(rng: *std.rand.Random) !void { |
| 1236 | item.id = index; | 1343 | item.id = index; |
| 1237 | item.value = rng.intRangeLessThan(i32, 0, 100); | 1344 | item.value = rng.intRangeLessThan(i32, 0, 100); |
| 1238 | } | 1345 | } |
| 1239 | sort(IdAndValue, array, cmpByValue); | 1346 | sort(IdAndValue, array, {}, cmpByValue); |
| 1240 | | 1347 | |
| 1241 | var index: usize = 1; | 1348 | var index: usize = 1; |
| 1242 | while (index < array.len) : (index += 1) { | 1349 | while (index < array.len) : (index += 1) { |
| ... | @@ -1248,7 +1355,12 @@ fn fuzzTest(rng: *std.rand.Random) !void { | ... | @@ -1248,7 +1355,12 @@ fn fuzzTest(rng: *std.rand.Random) !void { |
| 1248 | } | 1355 | } |
| 1249 | } | 1356 | } |
| 1250 | | 1357 | |
| 1251 | pub fn argMin(comptime T: type, items: []const T, lessThan: fn (lhs: T, rhs: T) bool) ?usize { | 1358 | pub fn argMin( |
| | 1359 | comptime T: type, |
| | 1360 | items: []const T, |
| | 1361 | context: var, |
| | 1362 | comptime lessThan: fn (@TypeOf(context), lhs: T, rhs: T) bool, |
| | 1363 | ) ?usize { |
| 1252 | if (items.len == 0) { | 1364 | if (items.len == 0) { |
| 1253 | return null; | 1365 | return null; |
| 1254 | } | 1366 | } |
| ... | @@ -1256,7 +1368,7 @@ pub fn argMin(comptime T: type, items: []const T, lessThan: fn (lhs: T, rhs: T) | ... | @@ -1256,7 +1368,7 @@ pub fn argMin(comptime T: type, items: []const T, lessThan: fn (lhs: T, rhs: T) |
| 1256 | var smallest = items[0]; | 1368 | var smallest = items[0]; |
| 1257 | var smallest_index: usize = 0; | 1369 | var smallest_index: usize = 0; |
| 1258 | for (items[1..]) |item, i| { | 1370 | for (items[1..]) |item, i| { |
| 1259 | if (lessThan(item, smallest)) { | 1371 | if (lessThan(context, item, smallest)) { |
| 1260 | smallest = item; | 1372 | smallest = item; |
| 1261 | smallest_index = i + 1; | 1373 | smallest_index = i + 1; |
| 1262 | } | 1374 | } |
| ... | @@ -1265,32 +1377,42 @@ pub fn argMin(comptime T: type, items: []const T, lessThan: fn (lhs: T, rhs: T) | ... | @@ -1265,32 +1377,42 @@ pub fn argMin(comptime T: type, items: []const T, lessThan: fn (lhs: T, rhs: T) |
| 1265 | return smallest_index; | 1377 | return smallest_index; |
| 1266 | } | 1378 | } |
| 1267 | | 1379 | |
| 1268 | test "std.sort.argMin" { | 1380 | test "argMin" { |
| 1269 | testing.expectEqual(@as(?usize, null), argMin(i32, &[_]i32{}, asc(i32))); | 1381 | testing.expectEqual(@as(?usize, null), argMin(i32, &[_]i32{}, {}, asc_i32)); |
| 1270 | testing.expectEqual(@as(?usize, 0), argMin(i32, &[_]i32{1}, asc(i32))); | 1382 | testing.expectEqual(@as(?usize, 0), argMin(i32, &[_]i32{1}, {}, asc_i32)); |
| 1271 | testing.expectEqual(@as(?usize, 0), argMin(i32, &[_]i32{ 1, 2, 3, 4, 5 }, asc(i32))); | 1383 | testing.expectEqual(@as(?usize, 0), argMin(i32, &[_]i32{ 1, 2, 3, 4, 5 }, {}, asc_i32)); |
| 1272 | testing.expectEqual(@as(?usize, 3), argMin(i32, &[_]i32{ 9, 3, 8, 2, 5 }, asc(i32))); | 1384 | testing.expectEqual(@as(?usize, 3), argMin(i32, &[_]i32{ 9, 3, 8, 2, 5 }, {}, asc_i32)); |
| 1273 | testing.expectEqual(@as(?usize, 0), argMin(i32, &[_]i32{ 1, 1, 1, 1, 1 }, asc(i32))); | 1385 | testing.expectEqual(@as(?usize, 0), argMin(i32, &[_]i32{ 1, 1, 1, 1, 1 }, {}, asc_i32)); |
| 1274 | testing.expectEqual(@as(?usize, 0), argMin(i32, &[_]i32{ -10, 1, 10 }, asc(i32))); | 1386 | testing.expectEqual(@as(?usize, 0), argMin(i32, &[_]i32{ -10, 1, 10 }, {}, asc_i32)); |
| 1275 | testing.expectEqual(@as(?usize, 3), argMin(i32, &[_]i32{ 6, 3, 5, 7, 6 }, desc(i32))); | 1387 | testing.expectEqual(@as(?usize, 3), argMin(i32, &[_]i32{ 6, 3, 5, 7, 6 }, {}, desc_i32)); |
| 1276 | } | 1388 | } |
| 1277 | | 1389 | |
| 1278 | pub fn min(comptime T: type, items: []const T, lessThan: fn (lhs: T, rhs: T) bool) ?T { | 1390 | pub fn min( |
| 1279 | const i = argMin(T, items, lessThan) orelse return null; | 1391 | comptime T: type, |
| | 1392 | items: []const T, |
| | 1393 | context: var, |
| | 1394 | comptime lessThan: fn (context: @TypeOf(context), lhs: T, rhs: T) bool, |
| | 1395 | ) ?T { |
| | 1396 | const i = argMin(T, items, context, lessThan) orelse return null; |
| 1280 | return items[i]; | 1397 | return items[i]; |
| 1281 | } | 1398 | } |
| 1282 | | 1399 | |
| 1283 | test "std.sort.min" { | 1400 | test "min" { |
| 1284 | testing.expectEqual(@as(?i32, null), min(i32, &[_]i32{}, asc(i32))); | 1401 | testing.expectEqual(@as(?i32, null), min(i32, &[_]i32{}, {}, asc_i32)); |
| 1285 | testing.expectEqual(@as(?i32, 1), min(i32, &[_]i32{1}, asc(i32))); | 1402 | testing.expectEqual(@as(?i32, 1), min(i32, &[_]i32{1}, {}, asc_i32)); |
| 1286 | testing.expectEqual(@as(?i32, 1), min(i32, &[_]i32{ 1, 2, 3, 4, 5 }, asc(i32))); | 1403 | testing.expectEqual(@as(?i32, 1), min(i32, &[_]i32{ 1, 2, 3, 4, 5 }, {}, asc_i32)); |
| 1287 | testing.expectEqual(@as(?i32, 2), min(i32, &[_]i32{ 9, 3, 8, 2, 5 }, asc(i32))); | 1404 | testing.expectEqual(@as(?i32, 2), min(i32, &[_]i32{ 9, 3, 8, 2, 5 }, {}, asc_i32)); |
| 1288 | testing.expectEqual(@as(?i32, 1), min(i32, &[_]i32{ 1, 1, 1, 1, 1 }, asc(i32))); | 1405 | testing.expectEqual(@as(?i32, 1), min(i32, &[_]i32{ 1, 1, 1, 1, 1 }, {}, asc_i32)); |
| 1289 | testing.expectEqual(@as(?i32, -10), min(i32, &[_]i32{ -10, 1, 10 }, asc(i32))); | 1406 | testing.expectEqual(@as(?i32, -10), min(i32, &[_]i32{ -10, 1, 10 }, {}, asc_i32)); |
| 1290 | testing.expectEqual(@as(?i32, 7), min(i32, &[_]i32{ 6, 3, 5, 7, 6 }, desc(i32))); | 1407 | testing.expectEqual(@as(?i32, 7), min(i32, &[_]i32{ 6, 3, 5, 7, 6 }, {}, desc_i32)); |
| 1291 | } | 1408 | } |
| 1292 | | 1409 | |
| 1293 | pub fn argMax(comptime T: type, items: []const T, lessThan: fn (lhs: T, rhs: T) bool) ?usize { | 1410 | pub fn argMax( |
| | 1411 | comptime T: type, |
| | 1412 | items: []const T, |
| | 1413 | context: var, |
| | 1414 | comptime lessThan: fn (context: @TypeOf(context), lhs: T, rhs: T) bool, |
| | 1415 | ) ?usize { |
| 1294 | if (items.len == 0) { | 1416 | if (items.len == 0) { |
| 1295 | return null; | 1417 | return null; |
| 1296 | } | 1418 | } |
| ... | @@ -1298,7 +1420,7 @@ pub fn argMax(comptime T: type, items: []const T, lessThan: fn (lhs: T, rhs: T) | ... | @@ -1298,7 +1420,7 @@ pub fn argMax(comptime T: type, items: []const T, lessThan: fn (lhs: T, rhs: T) |
| 1298 | var biggest = items[0]; | 1420 | var biggest = items[0]; |
| 1299 | var biggest_index: usize = 0; | 1421 | var biggest_index: usize = 0; |
| 1300 | for (items[1..]) |item, i| { | 1422 | for (items[1..]) |item, i| { |
| 1301 | if (lessThan(biggest, item)) { | 1423 | if (lessThan(context, biggest, item)) { |
| 1302 | biggest = item; | 1424 | biggest = item; |
| 1303 | biggest_index = i + 1; | 1425 | biggest_index = i + 1; |
| 1304 | } | 1426 | } |
| ... | @@ -1307,35 +1429,45 @@ pub fn argMax(comptime T: type, items: []const T, lessThan: fn (lhs: T, rhs: T) | ... | @@ -1307,35 +1429,45 @@ pub fn argMax(comptime T: type, items: []const T, lessThan: fn (lhs: T, rhs: T) |
| 1307 | return biggest_index; | 1429 | return biggest_index; |
| 1308 | } | 1430 | } |
| 1309 | | 1431 | |
| 1310 | test "std.sort.argMax" { | 1432 | test "argMax" { |
| 1311 | testing.expectEqual(@as(?usize, null), argMax(i32, &[_]i32{}, asc(i32))); | 1433 | testing.expectEqual(@as(?usize, null), argMax(i32, &[_]i32{}, {}, asc_i32)); |
| 1312 | testing.expectEqual(@as(?usize, 0), argMax(i32, &[_]i32{1}, asc(i32))); | 1434 | testing.expectEqual(@as(?usize, 0), argMax(i32, &[_]i32{1}, {}, asc_i32)); |
| 1313 | testing.expectEqual(@as(?usize, 4), argMax(i32, &[_]i32{ 1, 2, 3, 4, 5 }, asc(i32))); | 1435 | testing.expectEqual(@as(?usize, 4), argMax(i32, &[_]i32{ 1, 2, 3, 4, 5 }, {}, asc_i32)); |
| 1314 | testing.expectEqual(@as(?usize, 0), argMax(i32, &[_]i32{ 9, 3, 8, 2, 5 }, asc(i32))); | 1436 | testing.expectEqual(@as(?usize, 0), argMax(i32, &[_]i32{ 9, 3, 8, 2, 5 }, {}, asc_i32)); |
| 1315 | testing.expectEqual(@as(?usize, 0), argMax(i32, &[_]i32{ 1, 1, 1, 1, 1 }, asc(i32))); | 1437 | testing.expectEqual(@as(?usize, 0), argMax(i32, &[_]i32{ 1, 1, 1, 1, 1 }, {}, asc_i32)); |
| 1316 | testing.expectEqual(@as(?usize, 2), argMax(i32, &[_]i32{ -10, 1, 10 }, asc(i32))); | 1438 | testing.expectEqual(@as(?usize, 2), argMax(i32, &[_]i32{ -10, 1, 10 }, {}, asc_i32)); |
| 1317 | testing.expectEqual(@as(?usize, 1), argMax(i32, &[_]i32{ 6, 3, 5, 7, 6 }, desc(i32))); | 1439 | testing.expectEqual(@as(?usize, 1), argMax(i32, &[_]i32{ 6, 3, 5, 7, 6 }, {}, desc_i32)); |
| 1318 | } | 1440 | } |
| 1319 | | 1441 | |
| 1320 | pub fn max(comptime T: type, items: []const T, lessThan: fn (lhs: T, rhs: T) bool) ?T { | 1442 | pub fn max( |
| 1321 | const i = argMax(T, items, lessThan) orelse return null; | 1443 | comptime T: type, |
| | 1444 | items: []const T, |
| | 1445 | context: var, |
| | 1446 | comptime lessThan: fn (context: @TypeOf(context), lhs: T, rhs: T) bool, |
| | 1447 | ) ?T { |
| | 1448 | const i = argMax(T, items, context, lessThan) orelse return null; |
| 1322 | return items[i]; | 1449 | return items[i]; |
| 1323 | } | 1450 | } |
| 1324 | | 1451 | |
| 1325 | test "std.sort.max" { | 1452 | test "max" { |
| 1326 | testing.expectEqual(@as(?i32, null), max(i32, &[_]i32{}, asc(i32))); | 1453 | testing.expectEqual(@as(?i32, null), max(i32, &[_]i32{}, {}, asc_i32)); |
| 1327 | testing.expectEqual(@as(?i32, 1), max(i32, &[_]i32{1}, asc(i32))); | 1454 | testing.expectEqual(@as(?i32, 1), max(i32, &[_]i32{1}, {}, asc_i32)); |
| 1328 | testing.expectEqual(@as(?i32, 5), max(i32, &[_]i32{ 1, 2, 3, 4, 5 }, asc(i32))); | 1455 | testing.expectEqual(@as(?i32, 5), max(i32, &[_]i32{ 1, 2, 3, 4, 5 }, {}, asc_i32)); |
| 1329 | testing.expectEqual(@as(?i32, 9), max(i32, &[_]i32{ 9, 3, 8, 2, 5 }, asc(i32))); | 1456 | testing.expectEqual(@as(?i32, 9), max(i32, &[_]i32{ 9, 3, 8, 2, 5 }, {}, asc_i32)); |
| 1330 | testing.expectEqual(@as(?i32, 1), max(i32, &[_]i32{ 1, 1, 1, 1, 1 }, asc(i32))); | 1457 | testing.expectEqual(@as(?i32, 1), max(i32, &[_]i32{ 1, 1, 1, 1, 1 }, {}, asc_i32)); |
| 1331 | testing.expectEqual(@as(?i32, 10), max(i32, &[_]i32{ -10, 1, 10 }, asc(i32))); | 1458 | testing.expectEqual(@as(?i32, 10), max(i32, &[_]i32{ -10, 1, 10 }, {}, asc_i32)); |
| 1332 | testing.expectEqual(@as(?i32, 3), max(i32, &[_]i32{ 6, 3, 5, 7, 6 }, desc(i32))); | 1459 | testing.expectEqual(@as(?i32, 3), max(i32, &[_]i32{ 6, 3, 5, 7, 6 }, {}, desc_i32)); |
| 1333 | } | 1460 | } |
| 1334 | | 1461 | |
| 1335 | pub fn isSorted(comptime T: type, items: []const T, lessThan: fn (lhs: T, rhs: T) bool) bool { | 1462 | pub fn isSorted( |
| | 1463 | comptime T: type, |
| | 1464 | items: []const T, |
| | 1465 | context: var, |
| | 1466 | comptime lessThan: fn (context: @TypeOf(context), lhs: T, rhs: T) bool, |
| | 1467 | ) bool { |
| 1336 | var i: usize = 1; | 1468 | var i: usize = 1; |
| 1337 | while (i < items.len) : (i += 1) { | 1469 | while (i < items.len) : (i += 1) { |
| 1338 | if (lessThan(items[i], items[i - 1])) { | 1470 | if (lessThan(context, items[i], items[i - 1])) { |
| 1339 | return false; | 1471 | return false; |
| 1340 | } | 1472 | } |
| 1341 | } | 1473 | } |
| ... | @@ -1343,29 +1475,29 @@ pub fn isSorted(comptime T: type, items: []const T, lessThan: fn (lhs: T, rhs: T | ... | @@ -1343,29 +1475,29 @@ pub fn isSorted(comptime T: type, items: []const T, lessThan: fn (lhs: T, rhs: T |
| 1343 | return true; | 1475 | return true; |
| 1344 | } | 1476 | } |
| 1345 | | 1477 | |
| 1346 | test "std.sort.isSorted" { | 1478 | test "isSorted" { |
| 1347 | testing.expect(isSorted(i32, &[_]i32{}, asc(i32))); | 1479 | testing.expect(isSorted(i32, &[_]i32{}, {}, asc_i32)); |
| 1348 | testing.expect(isSorted(i32, &[_]i32{10}, asc(i32))); | 1480 | testing.expect(isSorted(i32, &[_]i32{10}, {}, asc_i32)); |
| 1349 | testing.expect(isSorted(i32, &[_]i32{ 1, 2, 3, 4, 5 }, asc(i32))); | 1481 | testing.expect(isSorted(i32, &[_]i32{ 1, 2, 3, 4, 5 }, {}, asc_i32)); |
| 1350 | testing.expect(isSorted(i32, &[_]i32{ -10, 1, 1, 1, 10 }, asc(i32))); | 1482 | testing.expect(isSorted(i32, &[_]i32{ -10, 1, 1, 1, 10 }, {}, asc_i32)); |
| 1351 | | 1483 | |
| 1352 | testing.expect(isSorted(i32, &[_]i32{}, desc(i32))); | 1484 | testing.expect(isSorted(i32, &[_]i32{}, {}, desc_i32)); |
| 1353 | testing.expect(isSorted(i32, &[_]i32{-20}, desc(i32))); | 1485 | testing.expect(isSorted(i32, &[_]i32{-20}, {}, desc_i32)); |
| 1354 | testing.expect(isSorted(i32, &[_]i32{ 3, 2, 1, 0, -1 }, desc(i32))); | 1486 | testing.expect(isSorted(i32, &[_]i32{ 3, 2, 1, 0, -1 }, {}, desc_i32)); |
| 1355 | testing.expect(isSorted(i32, &[_]i32{ 10, -10 }, desc(i32))); | 1487 | testing.expect(isSorted(i32, &[_]i32{ 10, -10 }, {}, desc_i32)); |
| 1356 | | 1488 | |
| 1357 | testing.expect(isSorted(i32, &[_]i32{ 1, 1, 1, 1, 1 }, asc(i32))); | 1489 | testing.expect(isSorted(i32, &[_]i32{ 1, 1, 1, 1, 1 }, {}, asc_i32)); |
| 1358 | testing.expect(isSorted(i32, &[_]i32{ 1, 1, 1, 1, 1 }, desc(i32))); | 1490 | testing.expect(isSorted(i32, &[_]i32{ 1, 1, 1, 1, 1 }, {}, desc_i32)); |
| 1359 | | 1491 | |
| 1360 | testing.expectEqual(false, isSorted(i32, &[_]i32{ 5, 4, 3, 2, 1 }, asc(i32))); | 1492 | testing.expectEqual(false, isSorted(i32, &[_]i32{ 5, 4, 3, 2, 1 }, {}, asc_i32)); |
| 1361 | testing.expectEqual(false, isSorted(i32, &[_]i32{ 1, 2, 3, 4, 5 }, desc(i32))); | 1493 | testing.expectEqual(false, isSorted(i32, &[_]i32{ 1, 2, 3, 4, 5 }, {}, desc_i32)); |
| 1362 | | 1494 | |
| 1363 | testing.expect(isSorted(u8, "abcd", asc(u8))); | 1495 | testing.expect(isSorted(u8, "abcd", {}, asc_u8)); |
| 1364 | testing.expect(isSorted(u8, "zyxw", desc(u8))); | 1496 | testing.expect(isSorted(u8, "zyxw", {}, desc_u8)); |
| 1365 | | 1497 | |
| 1366 | testing.expectEqual(false, isSorted(u8, "abcd", desc(u8))); | 1498 | testing.expectEqual(false, isSorted(u8, "abcd", {}, desc_u8)); |
| 1367 | testing.expectEqual(false, isSorted(u8, "zyxw", asc(u8))); | 1499 | testing.expectEqual(false, isSorted(u8, "zyxw", {}, asc_u8)); |
| 1368 | | 1500 | |
| 1369 | testing.expect(isSorted(u8, "ffff", asc(u8))); | 1501 | testing.expect(isSorted(u8, "ffff", {}, asc_u8)); |
| 1370 | testing.expect(isSorted(u8, "ffff", desc(u8))); | 1502 | testing.expect(isSorted(u8, "ffff", {}, desc_u8)); |
| 1371 | } | 1503 | } |