authorgravatar for alichraghi@proton.meAli Chraghi <alichraghi@proton.me> 2023-06-24 17:31:50+03:30
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-06-26 17:50:10-07:00
log6bd54793060191ffce2c7492a90a40a30f9e2a1d
treea330c7f4d0882653cb2840a5faa2d04d38fa8fd6
parent88284c124a0d930541f02ae9727118c0724f93f9

std.sort.block: add safety check for lessThan return value


6 files changed, 45 insertions(+), 21 deletions(-)

lib/std/c/tokenizer.zig-1
......@@ -1,5 +1,4 @@
11const std = @import("std");
2const mem = std.mem;
32
43pub const Token = struct {
54 id: Id,
lib/std/comptime_string_map.zig+15-8
......@@ -9,18 +9,12 @@ const mem = std.mem;
99/// You can pass `struct { []const u8 }` (only keys) tuples if `V` is `void`.
1010pub fn ComptimeStringMap(comptime V: type, comptime kvs_list: anytype) type {
1111 const precomputed = comptime blk: {
12 @setEvalBranchQuota(2000);
12 @setEvalBranchQuota(1500);
1313 const KV = struct {
1414 key: []const u8,
1515 value: V,
1616 };
1717 var sorted_kvs: [kvs_list.len]KV = undefined;
18 const lenAsc = (struct {
19 fn lenAsc(context: void, a: KV, b: KV) bool {
20 _ = context;
21 return a.key.len < b.key.len;
22 }
23 }).lenAsc;
2418 for (kvs_list, 0..) |kv, i| {
2519 if (V != void) {
2620 sorted_kvs[i] = .{ .key = kv.@"0", .value = kv.@"1" };
......@@ -28,7 +22,20 @@ pub fn ComptimeStringMap(comptime V: type, comptime kvs_list: anytype) type {
2822 sorted_kvs[i] = .{ .key = kv.@"0", .value = {} };
2923 }
3024 }
31 mem.sort(KV, &sorted_kvs, {}, lenAsc);
25
26 const SortContext = struct {
27 kvs: []KV,
28
29 pub fn lessThan(ctx: @This(), a: usize, b: usize) bool {
30 return ctx.kvs[a].key.len < ctx.kvs[b].key.len;
31 }
32
33 pub fn swap(ctx: @This(), a: usize, b: usize) void {
34 return std.mem.swap(KV, &ctx.kvs[a], &ctx.kvs[b]);
35 }
36 };
37 mem.sortUnstableContext(0, sorted_kvs.len, SortContext{ .kvs = &sorted_kvs });
38
3239 const min_len = sorted_kvs[0].key.len;
3340 const max_len = sorted_kvs[sorted_kvs.len - 1].key.len;
3441 var len_indexes: [max_len + 1]usize = undefined;
lib/std/enums.zig+18-9
......@@ -1289,10 +1289,6 @@ test "std.enums.ensureIndexer" {
12891289 });
12901290}
12911291
1292fn ascByValue(ctx: void, comptime a: EnumField, comptime b: EnumField) bool {
1293 _ = ctx;
1294 return a.value < b.value;
1295}
12961292pub fn EnumIndexer(comptime E: type) type {
12971293 if (!@typeInfo(E).Enum.is_exhaustive) {
12981294 @compileError("Cannot create an enum indexer for a non-exhaustive enum.");
......@@ -1300,7 +1296,10 @@ pub fn EnumIndexer(comptime E: type) type {
13001296
13011297 const const_fields = std.meta.fields(E);
13021298 var fields = const_fields[0..const_fields.len].*;
1303 if (fields.len == 0) {
1299 const min = fields[0].value;
1300 const max = fields[fields.len - 1].value;
1301 const fields_len = fields.len;
1302 if (fields_len == 0) {
13041303 return struct {
13051304 pub const Key = E;
13061305 pub const count: usize = 0;
......@@ -1314,10 +1313,20 @@ pub fn EnumIndexer(comptime E: type) type {
13141313 }
13151314 };
13161315 }
1317 std.mem.sort(EnumField, &fields, {}, ascByValue);
1318 const min = fields[0].value;
1319 const max = fields[fields.len - 1].value;
1320 const fields_len = fields.len;
1316
1317 const SortContext = struct {
1318 fields: []EnumField,
1319
1320 pub fn lessThan(comptime ctx: @This(), comptime a: usize, comptime b: usize) bool {
1321 return ctx.fields[a].value < ctx.fields[b].value;
1322 }
1323
1324 pub fn swap(comptime ctx: @This(), comptime a: usize, comptime b: usize) void {
1325 return std.mem.swap(EnumField, &ctx.fields[a], &ctx.fields[b]);
1326 }
1327 };
1328 std.sort.insertionContext(0, fields_len, SortContext{ .fields = &fields });
1329
13211330 if (max - min == fields.len - 1) {
13221331 return struct {
13231332 pub const Key = E;
lib/std/sort.zig+1-1
......@@ -366,7 +366,7 @@ test "sort with context in the middle of a slice" {
366366 const slice = buf[0..case[0].len];
367367 @memcpy(slice, case[0]);
368368 sortFn(range.start, range.end, Context{ .items = slice });
369 try testing.expectEqualSlices(i32, slice[range.start..range.end], case[1][range.start..range.end]);
369 try testing.expectEqualSlices(i32, case[1][range.start..range.end], slice[range.start..range.end]);
370370 }
371371 }
372372 }
lib/std/sort/block.zig+10-1
......@@ -1,3 +1,4 @@
1const builtin = @import("builtin");
12const std = @import("../std.zig");
23const sort = std.sort;
34const math = std.math;
......@@ -100,8 +101,16 @@ pub fn block(
100101 comptime T: type,
101102 items: []T,
102103 context: anytype,
103 comptime lessThan: fn (@TypeOf(context), lhs: T, rhs: T) bool,
104 comptime lessThanFn: fn (@TypeOf(context), lhs: T, rhs: T) bool,
104105) void {
106 const lessThan = if (builtin.mode == .Debug) struct {
107 fn lessThan(ctx: @TypeOf(context), lhs: T, rhs: T) bool {
108 const lt = lessThanFn(ctx, lhs, rhs);
109 const gt = lessThanFn(ctx, rhs, lhs);
110 std.debug.assert(!(lt and gt));
111 return lt;
112 }
113 }.lessThan else lessThanFn;
105114
106115 // Implementation ported from https://github.com/BonzaiThePenguin/WikiSort/blob/master/WikiSort.c
107116 var cache: [512]T = undefined;
src/arch/x86_64/Encoding.zig+1-1
......@@ -767,7 +767,7 @@ fn estimateInstructionLength(prefix: Prefix, encoding: Encoding, ops: []const Op
767767}
768768
769769const mnemonic_to_encodings_map = init: {
770 @setEvalBranchQuota(30_000);
770 @setEvalBranchQuota(50_000);
771771 const encodings = @import("encodings.zig");
772772 var entries = encodings.table;
773773 std.mem.sort(encodings.Entry, &entries, {}, struct {