authorgravatar for marc@tiehu.isMarc Tiehuis <marc@tiehu.is> 2023-09-30 22:15:47+13:00
committergravatar for marc@tiehu.isMarc Tiehuis <marc@tiehu.is> 2023-09-30 22:15:47+13:00
log08635f08a9afe38b2b9eec3ce7ccb583c402252a
treeecacf7f76b86f562910374f4c14be3b7dcfd5eab
parent5b5da0ef8c8be40c25106f17a264950d25ba82c9

fix indexOfSentinel alignment for types larger than 1 byte


1 files changed, 52 insertions(+), 3 deletions(-)

lib/std/mem.zig+52-3
......@@ -985,19 +985,19 @@ pub fn indexOfSentinel(comptime T: type, comptime sentinel: T, p: [*:sentinel]co
985985 return i + std.simd.firstTrue(matches).?;
986986 }
987987
988 i += std.mem.alignForward(usize, start_addr, block_len) - start_addr;
988 i += (std.mem.alignForward(usize, start_addr, @alignOf(Block)) - start_addr) / @sizeOf(T);
989989 } else {
990990 // Would read over a page boundary. Per-byte at a time until aligned or found.
991991 // 0.39% chance this branch is taken for 4K pages at 16b block length.
992992 //
993993 // An alternate strategy is to do read a full block (the last in the page) and
994994 // mask the entries before the pointer.
995 while ((@intFromPtr(&p[i]) & (block_len - 1)) != 0) : (i += 1) {
995 while ((@intFromPtr(&p[i]) & (@alignOf(Block) - 1)) != 0) : (i += 1) {
996996 if (p[i] == sentinel) return i;
997997 }
998998 }
999999
1000 std.debug.assert(std.mem.isAligned(@intFromPtr(&p[i]), block_len));
1000 std.debug.assert(std.mem.isAligned(@intFromPtr(&p[i]), @alignOf(Block)));
10011001 while (true) {
10021002 const block: *const Block = @ptrCast(@alignCast(p[i..][0..block_len]));
10031003 const matches = block.* == mask;
......@@ -1017,6 +1017,41 @@ pub fn indexOfSentinel(comptime T: type, comptime sentinel: T, p: [*:sentinel]co
10171017 return i;
10181018}
10191019
1020test "indexOfSentinel vector paths" {
1021 const Types = [_]type{ u8, u16, u32, u64 };
1022 const allocator = std.testing.allocator;
1023
1024 inline for (Types) |T| {
1025 const block_len = comptime std.simd.suggestVectorSize(T) orelse continue;
1026
1027 // Allocate three pages so we guarantee a page-crossing address with a full page after
1028 const memory = try allocator.alloc(T, 3 * std.mem.page_size / @sizeOf(T));
1029 defer allocator.free(memory);
1030 @memset(memory, 0xaa);
1031
1032 // Find starting page-alignment = 0
1033 var start: usize = 0;
1034 const start_addr = @intFromPtr(&memory);
1035 start += (std.mem.alignForward(usize, start_addr, std.mem.page_size) - start_addr) / @sizeOf(T);
1036 try testing.expect(start < std.mem.page_size / @sizeOf(T));
1037
1038 // Validate all sub-block alignments
1039 const search_len = std.mem.page_size / @sizeOf(T);
1040 memory[start + search_len] = 0;
1041 for (0..block_len) |offset| {
1042 try testing.expectEqual(search_len - offset, indexOfSentinel(T, 0, @ptrCast(&memory[start + offset])));
1043 }
1044 memory[start + search_len] = 0xaa;
1045
1046 // Validate page boundary crossing
1047 const start_page_boundary = start + (std.mem.page_size / @sizeOf(T));
1048 memory[start_page_boundary + block_len] = 0;
1049 for (0..block_len) |offset| {
1050 try testing.expectEqual(2 * block_len - offset, indexOfSentinel(T, 0, @ptrCast(&memory[start_page_boundary - block_len + offset])));
1051 }
1052 }
1053}
1054
10201055/// Returns true if all elements in a slice are equal to the scalar value provided
10211056pub fn allEqual(comptime T: type, slice: []const T, scalar: T) bool {
10221057 for (slice) |item| {
......@@ -1131,6 +1166,20 @@ pub fn indexOfScalarPos(comptime T: type, slice: []const T, start_index: usize,
11311166 return null;
11321167}
11331168
1169test "indexOfScalarPos" {
1170 const Types = [_]type{ u8, u16, u32, u64 };
1171
1172 inline for (Types) |T| {
1173 var memory: [64 / @sizeOf(T)]T = undefined;
1174 @memset(&memory, 0xaa);
1175 memory[memory.len - 1] = 0;
1176
1177 for (0..memory.len) |i| {
1178 try testing.expectEqual(memory.len - i - 1, indexOfScalarPos(T, memory[i..], 0, 0).?);
1179 }
1180 }
1181}
1182
11341183pub fn indexOfAny(comptime T: type, slice: []const T, values: []const T) ?usize {
11351184 return indexOfAnyPos(T, slice, 0, values);
11361185}