authorgravatar for lmj.hallstrom@gmail.comJonathanHallstrom <lmj.hallstrom@gmail.com> 2024-07-21 10:17:43+02:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2024-07-21 01:17:43-07:00
logfae742a6804fcd1e9c901a49d91f265a7b0c1709
tree75839fe2627443ee5970a61bc9a7e52359c1d53a
parent7591df5172e9f8e80130b619b7eaa60846d3e851
signaturebadge-check Signed by PGP key B5690EEEBB952194

std.mem.reverse: Improve performance (#20455)


1 files changed, 60 insertions(+), 5 deletions(-)

lib/std/mem.zig+60-5
...@@ -3448,22 +3448,77 @@ pub fn swap(comptime T: type, a: *T, b: *T) void {...@@ -3448,22 +3448,77 @@ pub fn swap(comptime T: type, a: *T, b: *T) void {
3448 b.* = tmp;3448 b.* = tmp;
3449}3449}
34503450
3451inline fn reverseVector(comptime N: usize, comptime T: type, a: []T) [N]T {
3452 var res: [N]T = undefined;
3453 inline for (0..N) |i| {
3454 res[i] = a[N - i - 1];
3455 }
3456 return res;
3457}
3458
3451/// In-place order reversal of a slice3459/// In-place order reversal of a slice
3452pub fn reverse(comptime T: type, items: []T) void {3460pub fn reverse(comptime T: type, items: []T) void {
3453 var i: usize = 0;3461 var i: usize = 0;
3454 const end = items.len / 2;3462 const end = items.len / 2;
3463 if (backend_supports_vectors and
3464 !@inComptime() and
3465 @bitSizeOf(T) > 0 and
3466 std.math.isPowerOfTwo(@bitSizeOf(T)))
3467 {
3468 if (std.simd.suggestVectorLength(T)) |simd_size| {
3469 if (simd_size <= end) {
3470 const simd_end = end - (simd_size - 1);
3471 while (i < simd_end) : (i += simd_size) {
3472 const left_slice = items[i .. i + simd_size];
3473 const right_slice = items[items.len - i - simd_size .. items.len - i];
3474
3475 const left_shuffled: [simd_size]T = reverseVector(simd_size, T, left_slice);
3476 const right_shuffled: [simd_size]T = reverseVector(simd_size, T, right_slice);
3477
3478 @memcpy(right_slice, &left_shuffled);
3479 @memcpy(left_slice, &right_shuffled);
3480 }
3481 }
3482 }
3483 }
3484
3455 while (i < end) : (i += 1) {3485 while (i < end) : (i += 1) {
3456 swap(T, &items[i], &items[items.len - i - 1]);3486 swap(T, &items[i], &items[items.len - i - 1]);
3457 }3487 }
3458}3488}
34593489
3460test reverse {3490test reverse {
3461 var arr = [_]i32{ 5, 3, 1, 2, 4 };3491 {
3462 reverse(i32, arr[0..]);3492 var arr = [_]i32{ 5, 3, 1, 2, 4 };
34633493 reverse(i32, arr[0..]);
3464 try testing.expect(eql(i32, &arr, &[_]i32{ 4, 2, 1, 3, 5 }));3494 try testing.expectEqualSlices(i32, &arr, &.{ 4, 2, 1, 3, 5 });
3495 }
3496 {
3497 var arr = [_]u0{};
3498 reverse(u0, arr[0..]);
3499 try testing.expectEqualSlices(u0, &arr, &.{});
3500 }
3501 {
3502 var arr = [_]i64{ 19, 17, 15, 13, 11, 9, 7, 5, 3, 1, 2, 4, 6, 8, 10, 12, 14, 16, 18 };
3503 reverse(i64, arr[0..]);
3504 try testing.expectEqualSlices(i64, &arr, &.{ 18, 16, 14, 12, 10, 8, 6, 4, 2, 1, 3, 5, 7, 9, 11, 13, 15, 17, 19 });
3505 }
3506 {
3507 var arr = [_][]const u8{ "a", "b", "c", "d" };
3508 reverse([]const u8, arr[0..]);
3509 try testing.expectEqualSlices([]const u8, &arr, &.{ "d", "c", "b", "a" });
3510 }
3511 {
3512 const MyType = union(enum) {
3513 a: [3]u8,
3514 b: u24,
3515 c,
3516 };
3517 var arr = [_]MyType{ .{ .a = .{ 0, 0, 0 } }, .{ .b = 0 }, .c };
3518 reverse(MyType, arr[0..]);
3519 try testing.expectEqualSlices(MyType, &arr, &([_]MyType{ .c, .{ .b = 0 }, .{ .a = .{ 0, 0, 0 } } }));
3520 }
3465}3521}
3466
3467fn ReverseIterator(comptime T: type) type {3522fn ReverseIterator(comptime T: type) type {
3468 const Pointer = blk: {3523 const Pointer = blk: {
3469 switch (@typeInfo(T)) {3524 switch (@typeInfo(T)) {