| ... | ... | @@ -2989,52 +2989,107 @@ test "reverse" { |
| 2989 | 2989 | } |
| 2990 | 2990 | |
| 2991 | 2991 | fn ReverseIterator(comptime T: type) type { |
| 2992 | | const info: struct { Child: type, Pointer: type } = blk: { |
| 2992 | const Pointer = blk: { |
| 2993 | 2993 | 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 }); |
| 3007 | 3009 | }, |
| 3008 | 3010 | else => {}, |
| 3009 | 3011 | }, |
| 3010 | 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); |
| 3017 | const ElementPointer = @TypeOf(&@as(Pointer, undefined)[0]); |
| 3014 | 3018 | return struct { |
| 3015 | | ptr: info.Pointer, |
| 3019 | ptr: Pointer, |
| 3016 | 3020 | index: usize, |
| 3017 | | pub fn next(self: *@This()) ?info.Child { |
| 3021 | pub fn next(self: *@This()) ?Element { |
| 3018 | 3022 | if (self.index == 0) return null; |
| 3019 | 3023 | self.index -= 1; |
| 3020 | 3024 | return self.ptr[self.index]; |
| 3021 | 3025 | } |
| 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 | } |
| 3022 | 3031 | }; |
| 3023 | 3032 | } |
| 3024 | 3033 | |
| 3025 | | /// Iterate over a slice in reverse. |
| 3034 | /// Iterates over a slice in reverse. |
| 3026 | 3035 | pub 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 | } |
| 3028 | 3043 | } |
| 3029 | 3044 | |
| 3030 | 3045 | test "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 | } |
| 3038 | 3093 | } |
| 3039 | 3094 | |
| 3040 | 3095 | /// In-place rotation of the values in an array ([0 1 2 3] becomes [1 2 3 0] if we rotate by 1) |