| ... | @@ -3633,10 +3633,34 @@ test indexOfMinMax { | ... | @@ -3633,10 +3633,34 @@ test indexOfMinMax { |
| 3633 | } | 3633 | } |
| 3634 | | 3634 | |
| 3635 | /// Exchanges contents of two memory locations. | 3635 | /// Exchanges contents of two memory locations. |
| 3636 | pub fn swap(comptime T: type, a: *T, b: *T) void { | 3636 | pub fn swap(comptime T: type, noalias a: *T, noalias b: *T) void { |
| 3637 | const tmp = a.*; | 3637 | if (@inComptime()) { |
| 3638 | a.* = b.*; | 3638 | // In comptime, accessing bytes of values with no defined layout is a compile error. |
| 3639 | b.* = tmp; | 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 | } |
| 3640 | } | 3664 | } |
| 3641 | | 3665 | |
| 3642 | inline fn reverseVector(comptime N: usize, comptime T: type, a: []T) [N]T { | 3666 | inline fn reverseVector(comptime N: usize, comptime T: type, a: []T) [N]T { |