authorgravatar for carl@astholm.seCarl Åstholm <carl@astholm.se> 2023-03-31 22:48:32+02:00
committergravatar for carl@astholm.seCarl Åstholm <carl@astholm.se> 2023-03-31 22:48:32+02:00
log0bbc1ec2061b116093d3a85e955c5e6c1e7a28cd
tree98349f99df097a6fa718591e243b1e57e6cb42bc
parent9cb2919d500520d280e09d0990809d538aa32b56

std.mem.reverseIterator: accept pointer to array


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

lib/std/mem.zig+51-26
...@@ -2989,32 +2989,35 @@ test "reverse" {...@@ -2989,32 +2989,35 @@ test "reverse" {
2989}2989}
29902990
2991fn ReverseIterator(comptime T: type) type {2991fn ReverseIterator(comptime T: type) type {
2992 const info: struct { Child: type, Pointer: type } = blk: {2992 const Pointer = blk: {
2993 switch (@typeInfo(T)) {2993 switch (@typeInfo(T)) {
2994 .Pointer => |info| switch (info.size) {2994 .Pointer => |ptr_info| switch (ptr_info.size) {
2995 .Slice => break :blk .{2995 .One => switch (@typeInfo(ptr_info.child)) {
2996 .Child = info.child,2996 .Array => |array_info| {
2997 .Pointer = @Type(.{ .Pointer = .{2997 var new_ptr_info = ptr_info;
2998 .size = .Many,2998 new_ptr_info.size = .Many;
2999 .is_const = info.is_const,2999 new_ptr_info.child = array_info.child;
3000 .is_volatile = info.is_volatile,3000 new_ptr_info.sentinel = array_info.sentinel;
3001 .alignment = info.alignment,3001 break :blk @Type(.{ .Pointer = new_ptr_info });
3002 .address_space = info.address_space,3002 },
3003 .child = info.child,3003 else => {},
3004 .is_allowzero = info.is_allowzero,3004 },
3005 .sentinel = info.sentinel,3005 .Slice => {
3006 } }),3006 var new_ptr_info = ptr_info;
3007 new_ptr_info.size = .Many;
3008 break :blk @Type(.{ .Pointer = new_ptr_info });
3007 },3009 },
3008 else => {},3010 else => {},
3009 },3011 },
3010 else => {},3012 else => {},
3011 }3013 }
3012 @compileError("reverse iterator expects slice, found " ++ @typeName(T));3014 @compileError("expected slice or pointer to array, found '" ++ @typeName(T) ++ "'");
3013 };3015 };
3016 const Element = std.meta.Elem(Pointer);
3014 return struct {3017 return struct {
3015 ptr: info.Pointer,3018 ptr: Pointer,
3016 index: usize,3019 index: usize,
3017 pub fn next(self: *@This()) ?info.Child {3020 pub fn next(self: *@This()) ?Element {
3018 if (self.index == 0) return null;3021 if (self.index == 0) return null;
3019 self.index -= 1;3022 self.index -= 1;
3020 return self.ptr[self.index];3023 return self.ptr[self.index];
...@@ -3022,19 +3025,41 @@ fn ReverseIterator(comptime T: type) type {...@@ -3022,19 +3025,41 @@ fn ReverseIterator(comptime T: type) type {
3022 };3025 };
3023}3026}
30243027
3025/// Iterate over a slice in reverse.3028/// Iterates over a slice in reverse.
3026pub fn reverseIterator(slice: anytype) ReverseIterator(@TypeOf(slice)) {3029pub fn reverseIterator(slice: anytype) ReverseIterator(@TypeOf(slice)) {
3027 return .{ .ptr = slice.ptr, .index = slice.len };3030 const T = @TypeOf(slice);
3031 if (comptime trait.isPtrTo(.Array)(T)) {
3032 return .{ .ptr = slice, .index = slice.len };
3033 } else {
3034 comptime assert(trait.isSlice(T));
3035 return .{ .ptr = slice.ptr, .index = slice.len };
3036 }
3028}3037}
30293038
3030test "reverseIterator" {3039test "reverseIterator" {
3031 const slice: []const i32 = &[_]i32{ 5, 3, 1, 2 };3040 {
3032 var it = reverseIterator(slice);3041 var it = reverseIterator("abc");
3033 try testing.expectEqual(@as(?i32, 2), it.next());3042 try testing.expectEqual(@as(?u8, 'c'), it.next());
3034 try testing.expectEqual(@as(?i32, 1), it.next());3043 try testing.expectEqual(@as(?u8, 'b'), it.next());
3035 try testing.expectEqual(@as(?i32, 3), it.next());3044 try testing.expectEqual(@as(?u8, 'a'), it.next());
3036 try testing.expectEqual(@as(?i32, 5), it.next());3045 try testing.expectEqual(@as(?u8, null), it.next());
3037 try testing.expectEqual(@as(?i32, null), it.next());3046 }
3047 {
3048 var array = [2]i32{ 3, 7 };
3049 const slice: []const i32 = &array;
3050 var it = reverseIterator(slice);
3051 try testing.expectEqual(@as(?i32, 7), it.next());
3052 try testing.expectEqual(@as(?i32, 3), it.next());
3053 try testing.expectEqual(@as(?i32, null), it.next());
3054 }
3055 {
3056 var array = [2]i32{ 3, 7 };
3057 const ptr_to_array: *const [2]i32 = &array;
3058 var it = reverseIterator(ptr_to_array);
3059 try testing.expectEqual(@as(?i32, 7), it.next());
3060 try testing.expectEqual(@as(?i32, 3), it.next());
3061 try testing.expectEqual(@as(?i32, null), it.next());
3062 }
3038}3063}
30393064
3040/// In-place rotation of the values in an array ([0 1 2 3] becomes [1 2 3 0] if we rotate by 1)3065/// In-place rotation of the values in an array ([0 1 2 3] becomes [1 2 3 0] if we rotate by 1)