authorgravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2023-04-02 18:06:55+03:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2023-04-02 18:06:55+03:00
loga31450375eaadfead340c28c32dd414160a99e65
tree02a011b64faa6132d06dabebf4dc99c44372f809
parentf4b411314ccf8e852d3febddc8b31ce1f533938b
parent3cd72951c037db69645a634fb063621512091ed3
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #15134 from castholm/reverse-iterator

std.mem.reverseIterator: misc improvements

1 files changed, 81 insertions(+), 26 deletions(-)

lib/std/mem.zig+81-26
......@@ -2989,52 +2989,107 @@ test "reverse" {
29892989}
29902990
29912991fn ReverseIterator(comptime T: type) type {
2992 const info: struct { Child: type, Pointer: type } = blk: {
2992 const Pointer = blk: {
29932993 switch (@typeInfo(T)) {
2994 .Pointer => |info| switch (info.size) {
2995 .Slice => break :blk .{
2996 .Child = info.child,
2997 .Pointer = @Type(.{ .Pointer = .{
2998 .size = .Many,
2999 .is_const = info.is_const,
3000 .is_volatile = info.is_volatile,
3001 .alignment = info.alignment,
3002 .address_space = info.address_space,
3003 .child = info.child,
3004 .is_allowzero = info.is_allowzero,
3005 .sentinel = info.sentinel,
3006 } }),
2994 .Pointer => |ptr_info| switch (ptr_info.size) {
2995 .One => switch (@typeInfo(ptr_info.child)) {
2996 .Array => |array_info| {
2997 var new_ptr_info = ptr_info;
2998 new_ptr_info.size = .Many;
2999 new_ptr_info.child = array_info.child;
3000 new_ptr_info.sentinel = array_info.sentinel;
3001 break :blk @Type(.{ .Pointer = new_ptr_info });
3002 },
3003 else => {},
3004 },
3005 .Slice => {
3006 var new_ptr_info = ptr_info;
3007 new_ptr_info.size = .Many;
3008 break :blk @Type(.{ .Pointer = new_ptr_info });
30073009 },
30083010 else => {},
30093011 },
30103012 else => {},
30113013 }
3012 @compileError("reverse iterator expects slice, found " ++ @typeName(T));
3014 @compileError("expected slice or pointer to array, found '" ++ @typeName(T) ++ "'");
30133015 };
3016 const Element = std.meta.Elem(Pointer);
3017 const ElementPointer = @TypeOf(&@as(Pointer, undefined)[0]);
30143018 return struct {
3015 ptr: info.Pointer,
3019 ptr: Pointer,
30163020 index: usize,
3017 pub fn next(self: *@This()) ?info.Child {
3021 pub fn next(self: *@This()) ?Element {
30183022 if (self.index == 0) return null;
30193023 self.index -= 1;
30203024 return self.ptr[self.index];
30213025 }
3026 pub fn nextPtr(self: *@This()) ?ElementPointer {
3027 if (self.index == 0) return null;
3028 self.index -= 1;
3029 return &self.ptr[self.index];
3030 }
30223031 };
30233032}
30243033
3025/// Iterate over a slice in reverse.
3034/// Iterates over a slice in reverse.
30263035pub fn reverseIterator(slice: anytype) ReverseIterator(@TypeOf(slice)) {
3027 return .{ .ptr = slice.ptr, .index = slice.len };
3036 const T = @TypeOf(slice);
3037 if (comptime trait.isPtrTo(.Array)(T)) {
3038 return .{ .ptr = slice, .index = slice.len };
3039 } else {
3040 comptime assert(trait.isSlice(T));
3041 return .{ .ptr = slice.ptr, .index = slice.len };
3042 }
30283043}
30293044
30303045test "reverseIterator" {
3031 const slice: []const i32 = &[_]i32{ 5, 3, 1, 2 };
3032 var it = reverseIterator(slice);
3033 try testing.expectEqual(@as(?i32, 2), it.next());
3034 try testing.expectEqual(@as(?i32, 1), it.next());
3035 try testing.expectEqual(@as(?i32, 3), it.next());
3036 try testing.expectEqual(@as(?i32, 5), it.next());
3037 try testing.expectEqual(@as(?i32, null), it.next());
3046 {
3047 var it = reverseIterator("abc");
3048 try testing.expectEqual(@as(?u8, 'c'), it.next());
3049 try testing.expectEqual(@as(?u8, 'b'), it.next());
3050 try testing.expectEqual(@as(?u8, 'a'), it.next());
3051 try testing.expectEqual(@as(?u8, null), it.next());
3052 }
3053 {
3054 var array = [2]i32{ 3, 7 };
3055 const slice: []const i32 = &array;
3056 var it = reverseIterator(slice);
3057 try testing.expectEqual(@as(?i32, 7), it.next());
3058 try testing.expectEqual(@as(?i32, 3), it.next());
3059 try testing.expectEqual(@as(?i32, null), it.next());
3060
3061 it = reverseIterator(slice);
3062 try testing.expect(trait.isConstPtr(@TypeOf(it.nextPtr().?)));
3063 try testing.expectEqual(@as(?i32, 7), it.nextPtr().?.*);
3064 try testing.expectEqual(@as(?i32, 3), it.nextPtr().?.*);
3065 try testing.expectEqual(@as(?*const i32, null), it.nextPtr());
3066
3067 var mut_slice: []i32 = &array;
3068 var mut_it = reverseIterator(mut_slice);
3069 mut_it.nextPtr().?.* += 1;
3070 mut_it.nextPtr().?.* += 2;
3071 try testing.expectEqual([2]i32{ 5, 8 }, array);
3072 }
3073 {
3074 var array = [2]i32{ 3, 7 };
3075 const ptr_to_array: *const [2]i32 = &array;
3076 var it = reverseIterator(ptr_to_array);
3077 try testing.expectEqual(@as(?i32, 7), it.next());
3078 try testing.expectEqual(@as(?i32, 3), it.next());
3079 try testing.expectEqual(@as(?i32, null), it.next());
3080
3081 it = reverseIterator(ptr_to_array);
3082 try testing.expect(trait.isConstPtr(@TypeOf(it.nextPtr().?)));
3083 try testing.expectEqual(@as(?i32, 7), it.nextPtr().?.*);
3084 try testing.expectEqual(@as(?i32, 3), it.nextPtr().?.*);
3085 try testing.expectEqual(@as(?*const i32, null), it.nextPtr());
3086
3087 var mut_ptr_to_array: *[2]i32 = &array;
3088 var mut_it = reverseIterator(mut_ptr_to_array);
3089 mut_it.nextPtr().?.* += 1;
3090 mut_it.nextPtr().?.* += 2;
3091 try testing.expectEqual([2]i32{ 5, 8 }, array);
3092 }
30383093}
30393094
30403095/// In-place rotation of the values in an array ([0 1 2 3] becomes [1 2 3 0] if we rotate by 1)