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 @@...@@ -1,5 +1,4 @@
1const std = @import("std");1const std = @import("std");
2const mem = std.mem;
32
4pub const Token = struct {3pub const Token = struct {
5 id: Id,4 id: Id,
lib/std/comptime_string_map.zig+15-8
...@@ -9,18 +9,12 @@ const mem = std.mem;...@@ -9,18 +9,12 @@ const mem = std.mem;
9/// You can pass `struct { []const u8 }` (only keys) tuples if `V` is `void`.9/// You can pass `struct { []const u8 }` (only keys) tuples if `V` is `void`.
10pub fn ComptimeStringMap(comptime V: type, comptime kvs_list: anytype) type {10pub fn ComptimeStringMap(comptime V: type, comptime kvs_list: anytype) type {
11 const precomputed = comptime blk: {11 const precomputed = comptime blk: {
12 @setEvalBranchQuota(2000);12 @setEvalBranchQuota(1500);
13 const KV = struct {13 const KV = struct {
14 key: []const u8,14 key: []const u8,
15 value: V,15 value: V,
16 };16 };
17 var sorted_kvs: [kvs_list.len]KV = undefined;17 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;
24 for (kvs_list, 0..) |kv, i| {18 for (kvs_list, 0..) |kv, i| {
25 if (V != void) {19 if (V != void) {
26 sorted_kvs[i] = .{ .key = kv.@"0", .value = kv.@"1" };20 sorted_kvs[i] = .{ .key = kv.@"0", .value = kv.@"1" };
...@@ -28,7 +22,20 @@ pub fn ComptimeStringMap(comptime V: type, comptime kvs_list: anytype) type {...@@ -28,7 +22,20 @@ pub fn ComptimeStringMap(comptime V: type, comptime kvs_list: anytype) type {
28 sorted_kvs[i] = .{ .key = kv.@"0", .value = {} };22 sorted_kvs[i] = .{ .key = kv.@"0", .value = {} };
29 }23 }
30 }24 }
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
32 const min_len = sorted_kvs[0].key.len;39 const min_len = sorted_kvs[0].key.len;
33 const max_len = sorted_kvs[sorted_kvs.len - 1].key.len;40 const max_len = sorted_kvs[sorted_kvs.len - 1].key.len;
34 var len_indexes: [max_len + 1]usize = undefined;41 var len_indexes: [max_len + 1]usize = undefined;
lib/std/enums.zig+18-9
...@@ -1289,10 +1289,6 @@ test "std.enums.ensureIndexer" {...@@ -1289,10 +1289,6 @@ test "std.enums.ensureIndexer" {
1289 });1289 });
1290}1290}
12911291
1292fn ascByValue(ctx: void, comptime a: EnumField, comptime b: EnumField) bool {
1293 _ = ctx;
1294 return a.value < b.value;
1295}
1296pub fn EnumIndexer(comptime E: type) type {1292pub fn EnumIndexer(comptime E: type) type {
1297 if (!@typeInfo(E).Enum.is_exhaustive) {1293 if (!@typeInfo(E).Enum.is_exhaustive) {
1298 @compileError("Cannot create an enum indexer for a non-exhaustive enum.");1294 @compileError("Cannot create an enum indexer for a non-exhaustive enum.");
...@@ -1300,7 +1296,10 @@ pub fn EnumIndexer(comptime E: type) type {...@@ -1300,7 +1296,10 @@ pub fn EnumIndexer(comptime E: type) type {
13001296
1301 const const_fields = std.meta.fields(E);1297 const const_fields = std.meta.fields(E);
1302 var fields = const_fields[0..const_fields.len].*;1298 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) {
1304 return struct {1303 return struct {
1305 pub const Key = E;1304 pub const Key = E;
1306 pub const count: usize = 0;1305 pub const count: usize = 0;
...@@ -1314,10 +1313,20 @@ pub fn EnumIndexer(comptime E: type) type {...@@ -1314,10 +1313,20 @@ pub fn EnumIndexer(comptime E: type) type {
1314 }1313 }
1315 };1314 };
1316 }1315 }
1317 std.mem.sort(EnumField, &fields, {}, ascByValue);1316
1318 const min = fields[0].value;1317 const SortContext = struct {
1319 const max = fields[fields.len - 1].value;1318 fields: []EnumField,
1320 const fields_len = fields.len;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
1321 if (max - min == fields.len - 1) {1330 if (max - min == fields.len - 1) {
1322 return struct {1331 return struct {
1323 pub const Key = E;1332 pub const Key = E;
lib/std/sort.zig+1-1
...@@ -366,7 +366,7 @@ test "sort with context in the middle of a slice" {...@@ -366,7 +366,7 @@ test "sort with context in the middle of a slice" {
366 const slice = buf[0..case[0].len];366 const slice = buf[0..case[0].len];
367 @memcpy(slice, case[0]);367 @memcpy(slice, case[0]);
368 sortFn(range.start, range.end, Context{ .items = slice });368 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]);
370 }370 }
371 }371 }
372 }372 }
lib/std/sort/block.zig+10-1
...@@ -1,3 +1,4 @@...@@ -1,3 +1,4 @@
1const builtin = @import("builtin");
1const std = @import("../std.zig");2const std = @import("../std.zig");
2const sort = std.sort;3const sort = std.sort;
3const math = std.math;4const math = std.math;
...@@ -100,8 +101,16 @@ pub fn block(...@@ -100,8 +101,16 @@ pub fn block(
100 comptime T: type,101 comptime T: type,
101 items: []T,102 items: []T,
102 context: anytype,103 context: anytype,
103 comptime lessThan: fn (@TypeOf(context), lhs: T, rhs: T) bool,104 comptime lessThanFn: fn (@TypeOf(context), lhs: T, rhs: T) bool,
104) void {105) 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
106 // Implementation ported from https://github.com/BonzaiThePenguin/WikiSort/blob/master/WikiSort.c115 // Implementation ported from https://github.com/BonzaiThePenguin/WikiSort/blob/master/WikiSort.c
107 var cache: [512]T = undefined;116 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...@@ -767,7 +767,7 @@ fn estimateInstructionLength(prefix: Prefix, encoding: Encoding, ops: []const Op
767}767}
768768
769const mnemonic_to_encodings_map = init: {769const mnemonic_to_encodings_map = init: {
770 @setEvalBranchQuota(30_000);770 @setEvalBranchQuota(50_000);
771 const encodings = @import("encodings.zig");771 const encodings = @import("encodings.zig");
772 var entries = encodings.table;772 var entries = encodings.table;
773 std.mem.sort(encodings.Entry, &entries, {}, struct {773 std.mem.sort(encodings.Entry, &entries, {}, struct {