Skip to content

Commit 4fb0898

Browse files
rpkakandrewrk
authored andcommitted
optimize std.mem.swap
1 parent 5bf52a6 commit 4fb0898

File tree

1 file changed

+28
-4
lines changed

1 file changed

+28
-4
lines changed

lib/std/mem.zig

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3633,10 +3633,34 @@ test indexOfMinMax {
36333633
}
36343634

36353635
/// Exchanges contents of two memory locations.
3636-
pub fn swap(comptime T: type, a: *T, b: *T) void {
3637-
const tmp = a.*;
3638-
a.* = b.*;
3639-
b.* = tmp;
3636+
pub fn swap(comptime T: type, noalias a: *T, noalias b: *T) void {
3637+
if (@inComptime()) {
3638+
// In comptime, accessing bytes of values with no defined layout is a compile error.
3639+
const tmp = a.*;
3640+
a.* = b.*;
3641+
b.* = tmp;
3642+
} else {
3643+
// Swapping in streaming nature from start to end instead of swapping
3644+
// everything in one step allows easier optimizations and less stack usage.
3645+
const a_bytes: []align(@alignOf(T)) u8 = @ptrCast(a);
3646+
const b_bytes: []align(@alignOf(T)) u8 = @ptrCast(b);
3647+
for (a_bytes, b_bytes) |*ab, *bb| {
3648+
const tmp = ab.*;
3649+
ab.* = bb.*;
3650+
bb.* = tmp;
3651+
}
3652+
}
3653+
}
3654+
3655+
test "swap works at comptime with types with no defined layout" {
3656+
comptime {
3657+
const T = struct { val: u64 };
3658+
var a: T = .{ .val = 0 };
3659+
var b: T = .{ .val = 1 };
3660+
swap(T, &a, &b);
3661+
try testing.expectEqual(T{ .val = 1 }, a);
3662+
try testing.expectEqual(T{ .val = 0 }, b);
3663+
}
36403664
}
36413665

36423666
inline fn reverseVector(comptime N: usize, comptime T: type, a: []T) [N]T {

0 commit comments

Comments
 (0)