Skip to content

Commit 0a96d78

Browse files
alichraghivoroskoi
andcommitted
std.sort: add pdqsort and heapsort
pdqsort (Pattern-defeating quicksort): A novel sorting algorithm that combines the fast average case of randomized quicksort with the fast worst case of heapsort, while achieving linear time on inputs with certain patterns. This implementation is based on https://github.com/zhangyunhao116/pdqsort which later replaced Go's original sort algorithm also: - compareFn now returns `std.math.Order` - moved *blocksort* (default stable algorithm) and *pdqsort* (default unstable algorithm) to lib/std/sort/ - made tests run for each algorithm Co-authored-by: VÖRÖSKŐI András <[email protected]>
1 parent d8bdfd8 commit 0a96d78

35 files changed

+1930
-1307
lines changed

lib/std/array_hash_map.zig

+2-2
Original file line numberDiff line numberDiff line change
@@ -2291,8 +2291,8 @@ test "sort" {
22912291
const C = struct {
22922292
keys: []i32,
22932293

2294-
pub fn lessThan(ctx: @This(), a_index: usize, b_index: usize) bool {
2295-
return ctx.keys[a_index] < ctx.keys[b_index];
2294+
pub fn compare(ctx: @This(), a_index: usize, b_index: usize) std.math.Order {
2295+
return std.math.order(ctx.keys[a_index], ctx.keys[b_index]);
22962296
}
22972297
};
22982298

lib/std/compress/deflate/huffman_code.zig

+5-6
Original file line numberDiff line numberDiff line change
@@ -346,17 +346,16 @@ pub fn generateFixedOffsetEncoding(allocator: Allocator) !HuffmanEncoder {
346346
return h;
347347
}
348348

349-
fn byLiteral(context: void, a: LiteralNode, b: LiteralNode) bool {
349+
fn byLiteral(context: void, a: LiteralNode, b: LiteralNode) math.Order {
350350
_ = context;
351-
return a.literal < b.literal;
351+
return math.order(a.literal, b.literal);
352352
}
353353

354-
fn byFreq(context: void, a: LiteralNode, b: LiteralNode) bool {
355-
_ = context;
354+
fn byFreq(context: void, a: LiteralNode, b: LiteralNode) math.Order {
356355
if (a.freq == b.freq) {
357-
return a.literal < b.literal;
356+
return byLiteral(context, a, b);
358357
}
359-
return a.freq < b.freq;
358+
return math.order(a.freq, b.freq);
360359
}
361360

362361
test "generate a Huffman code from an array of frequencies" {

lib/std/compress/zstandard/decode/huffman.zig

+4-4
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,7 @@ fn assignSymbols(weight_sorted_prefixed_symbols: []LiteralsSection.HuffmanTree.P
128128
LiteralsSection.HuffmanTree.PrefixedSymbol,
129129
weight_sorted_prefixed_symbols,
130130
weights,
131-
lessThanByWeight,
131+
compareByWeight,
132132
);
133133

134134
var prefix: u16 = 0;
@@ -222,13 +222,13 @@ pub fn decodeHuffmanTreeSlice(
222222
return buildHuffmanTree(&weights, symbol_count);
223223
}
224224

225-
fn lessThanByWeight(
225+
fn compareByWeight(
226226
weights: [256]u4,
227227
lhs: LiteralsSection.HuffmanTree.PrefixedSymbol,
228228
rhs: LiteralsSection.HuffmanTree.PrefixedSymbol,
229-
) bool {
229+
) std.math.Order {
230230
// NOTE: this function relies on the use of a stable sorting algorithm,
231231
// otherwise a special case of if (weights[lhs] == weights[rhs]) return lhs < rhs;
232232
// should be added
233-
return weights[lhs.symbol] < weights[rhs.symbol];
233+
return std.math.order(weights[lhs.symbol], weights[rhs.symbol]);
234234
}

lib/std/comptime_string_map.zig

+3-3
Original file line numberDiff line numberDiff line change
@@ -9,16 +9,16 @@ const mem = std.mem;
99
/// You can pass `struct { []const u8 }` (only keys) tuples if `V` is `void`.
1010
pub fn ComptimeStringMap(comptime V: type, comptime kvs_list: anytype) type {
1111
const precomputed = comptime blk: {
12-
@setEvalBranchQuota(2000);
12+
@setEvalBranchQuota(4000);
1313
const KV = struct {
1414
key: []const u8,
1515
value: V,
1616
};
1717
var sorted_kvs: [kvs_list.len]KV = undefined;
1818
const lenAsc = (struct {
19-
fn lenAsc(context: void, a: KV, b: KV) bool {
19+
fn lenAsc(context: void, a: KV, b: KV) std.math.Order {
2020
_ = context;
21-
return a.key.len < b.key.len;
21+
return std.math.order(a.key.len, b.key.len);
2222
}
2323
}).lenAsc;
2424
for (kvs_list, 0..) |kv, i| {

lib/std/debug.zig

+3-3
Original file line numberDiff line numberDiff line change
@@ -1211,7 +1211,7 @@ fn readMachODebugInfo(allocator: mem.Allocator, macho_file: File) !ModuleDebugIn
12111211
// Even though lld emits symbols in ascending order, this debug code
12121212
// should work for programs linked in any valid way.
12131213
// This sort is so that we can binary search later.
1214-
std.sort.sort(MachoSymbol, symbols, {}, MachoSymbol.addressLessThan);
1214+
std.sort.sort(MachoSymbol, symbols, {}, MachoSymbol.addressCompare);
12151215

12161216
return ModuleDebugInfo{
12171217
.base_address = undefined,
@@ -1269,9 +1269,9 @@ const MachoSymbol = struct {
12691269
return self.addr;
12701270
}
12711271

1272-
fn addressLessThan(context: void, lhs: MachoSymbol, rhs: MachoSymbol) bool {
1272+
fn addressCompare(context: void, lhs: MachoSymbol, rhs: MachoSymbol) std.math.Order {
12731273
_ = context;
1274-
return lhs.addr < rhs.addr;
1274+
return std.math.order(lhs.addr, rhs.addr);
12751275
}
12761276
};
12771277

lib/std/enums.zig

+2-2
Original file line numberDiff line numberDiff line change
@@ -1279,9 +1279,9 @@ test "std.enums.ensureIndexer" {
12791279
});
12801280
}
12811281

1282-
fn ascByValue(ctx: void, comptime a: EnumField, comptime b: EnumField) bool {
1282+
fn ascByValue(ctx: void, comptime a: EnumField, comptime b: EnumField) std.math.Order {
12831283
_ = ctx;
1284-
return a.value < b.value;
1284+
return std.math.order(a.value, b.value);
12851285
}
12861286
pub fn EnumIndexer(comptime E: type) type {
12871287
if (!@typeInfo(E).Enum.is_exhaustive) {

lib/std/http/Headers.zig

+4-4
Original file line numberDiff line numberDiff line change
@@ -46,11 +46,11 @@ pub const Field = struct {
4646
}
4747
}
4848

49-
fn lessThan(ctx: void, a: Field, b: Field) bool {
49+
fn compare(ctx: void, a: Field, b: Field) std.math.Order {
5050
_ = ctx;
51-
if (a.name.ptr == b.name.ptr) return false;
51+
if (a.name.ptr == b.name.ptr) return .eq;
5252

53-
return ascii.lessThanIgnoreCase(a.name, b.name);
53+
return ascii.orderIgnoreCase(a.name, b.name);
5454
}
5555
};
5656

@@ -201,7 +201,7 @@ pub const Headers = struct {
201201

202202
/// Sorts the headers in lexicographical order.
203203
pub fn sort(headers: *Headers) void {
204-
std.sort.sort(Field, headers.list.items, {}, Field.lessThan);
204+
std.sort.sort(Field, headers.list.items, {}, Field.compare);
205205
headers.rebuildIndex();
206206
}
207207

lib/std/multi_array_list.zig

+5-5
Original file line numberDiff line numberDiff line change
@@ -155,12 +155,12 @@ pub fn MultiArrayList(comptime T: type) type {
155155
};
156156
}
157157
const Sort = struct {
158-
fn lessThan(context: void, lhs: Data, rhs: Data) bool {
158+
fn compare(context: void, lhs: Data, rhs: Data) std.math.Order {
159159
_ = context;
160-
return lhs.alignment > rhs.alignment;
160+
return std.math.order(rhs.alignment, lhs.alignment);
161161
}
162162
};
163-
std.sort.sort(Data, &data, {}, Sort.lessThan);
163+
std.sort.sort(Data, &data, {}, Sort.compare);
164164
var sizes_bytes: [fields.len]usize = undefined;
165165
var field_indexes: [fields.len]usize = undefined;
166166
for (data, 0..) |elem, i| {
@@ -484,8 +484,8 @@ pub fn MultiArrayList(comptime T: type) type {
484484
}
485485
}
486486

487-
pub fn lessThan(sc: @This(), a_index: usize, b_index: usize) bool {
488-
return sc.sub_ctx.lessThan(a_index, b_index);
487+
pub fn compare(sc: @This(), a_index: usize, b_index: usize) std.math.Order {
488+
return sc.sub_ctx.compare(a_index, b_index);
489489
}
490490
};
491491

lib/std/net.zig

+2-2
Original file line numberDiff line numberDiff line change
@@ -1199,9 +1199,9 @@ fn IN6_IS_ADDR_SITELOCAL(a: [16]u8) bool {
11991199
}
12001200

12011201
// Parameters `b` and `a` swapped to make this descending.
1202-
fn addrCmpLessThan(context: void, b: LookupAddr, a: LookupAddr) bool {
1202+
fn addrCmpLessThan(context: void, b: LookupAddr, a: LookupAddr) std.math.Order {
12031203
_ = context;
1204-
return a.sortkey < b.sortkey;
1204+
return std.math.order(a.sortkey, b.sortkey);
12051205
}
12061206

12071207
fn linuxLookupNameFromNull(

0 commit comments

Comments
 (0)