diff options
| author | Andrew Kelley <andrew@ziglang.org> | 2023-02-03 12:49:40 -0700 |
|---|---|---|
| committer | Andrew Kelley <andrew@ziglang.org> | 2023-02-03 12:49:40 -0700 |
| commit | fab9b7110ed1fa7bb082aad5e095047441db2b24 (patch) | |
| tree | 81fef60aa45e7980dab8f3e23e5b5e92b40ee0a9 /lib/std/mem.zig | |
| parent | d20d69b59e6b65a99f45cb6a45c14e887034dd18 (diff) | |
| parent | 60935decd318498529a016eeb1379d943a7e830d (diff) | |
| download | zig-fab9b7110ed1fa7bb082aad5e095047441db2b24.tar.gz zig-fab9b7110ed1fa7bb082aad5e095047441db2b24.zip | |
Merge remote-tracking branch 'origin/master' into llvm16
Diffstat (limited to 'lib/std/mem.zig')
| -rw-r--r-- | lib/std/mem.zig | 102 |
1 files changed, 24 insertions, 78 deletions
diff --git a/lib/std/mem.zig b/lib/std/mem.zig index 8691c5bbad..371ef8fd8d 100644 --- a/lib/std/mem.zig +++ b/lib/std/mem.zig @@ -636,12 +636,9 @@ test "indexOfDiff" { try testing.expectEqual(indexOfDiff(u8, "xne", "one"), 0); } -/// Takes a pointer to an array, a sentinel-terminated pointer, or a slice, and -/// returns a slice. If there is a sentinel on the input type, there will be a -/// sentinel on the output type. The constness of the output type matches -/// the constness of the input type. `[*c]` pointers are assumed to be 0-terminated, -/// and assumed to not allow null. -pub fn Span(comptime T: type) type { +/// Takes a sentinel-terminated pointer and returns a slice preserving pointer attributes. +/// `[*c]` pointers are assumed to be 0-terminated and assumed to not be allowzero. +fn Span(comptime T: type) type { switch (@typeInfo(T)) { .Optional => |optional_info| { return ?Span(optional_info.child); @@ -649,39 +646,22 @@ pub fn Span(comptime T: type) type { .Pointer => |ptr_info| { var new_ptr_info = ptr_info; switch (ptr_info.size) { - .One => switch (@typeInfo(ptr_info.child)) { - .Array => |info| { - new_ptr_info.child = info.child; - new_ptr_info.sentinel = info.sentinel; - }, - else => @compileError("invalid type given to std.mem.Span"), - }, .C => { new_ptr_info.sentinel = &@as(ptr_info.child, 0); new_ptr_info.is_allowzero = false; }, - .Many, .Slice => {}, + .Many => if (ptr_info.sentinel == null) @compileError("invalid type given to std.mem.span: " ++ @typeName(T)), + .One, .Slice => @compileError("invalid type given to std.mem.span: " ++ @typeName(T)), } new_ptr_info.size = .Slice; return @Type(.{ .Pointer = new_ptr_info }); }, - else => @compileError("invalid type given to std.mem.Span"), + else => {}, } + @compileError("invalid type given to std.mem.span: " ++ @typeName(T)); } test "Span" { - try testing.expect(Span(*[5]u16) == []u16); - try testing.expect(Span(?*[5]u16) == ?[]u16); - try testing.expect(Span(*const [5]u16) == []const u16); - try testing.expect(Span(?*const [5]u16) == ?[]const u16); - try testing.expect(Span([]u16) == []u16); - try testing.expect(Span(?[]u16) == ?[]u16); - try testing.expect(Span([]const u8) == []const u8); - try testing.expect(Span(?[]const u8) == ?[]const u8); - try testing.expect(Span([:1]u16) == [:1]u16); - try testing.expect(Span(?[:1]u16) == ?[:1]u16); - try testing.expect(Span([:1]const u8) == [:1]const u8); - try testing.expect(Span(?[:1]const u8) == ?[:1]const u8); try testing.expect(Span([*:1]u16) == [:1]u16); try testing.expect(Span(?[*:1]u16) == ?[:1]u16); try testing.expect(Span([*:1]const u8) == [:1]const u8); @@ -692,13 +672,10 @@ test "Span" { try testing.expect(Span(?[*c]const u8) == ?[:0]const u8); } -/// Takes a pointer to an array, a sentinel-terminated pointer, or a slice, and -/// returns a slice. If there is a sentinel on the input type, there will be a -/// sentinel on the output type. The constness of the output type matches -/// the constness of the input type. -/// -/// When there is both a sentinel and an array length or slice length, the -/// length value is used instead of the sentinel. +/// Takes a sentinel-terminated pointer and returns a slice, iterating over the +/// memory to find the sentinel and determine the length. +/// Ponter attributes such as const are preserved. +/// `[*c]` pointers are assumed to be non-null and 0-terminated. pub fn span(ptr: anytype) Span(@TypeOf(ptr)) { if (@typeInfo(@TypeOf(ptr)) == .Optional) { if (ptr) |non_null| { @@ -722,7 +699,6 @@ test "span" { var array: [5]u16 = [_]u16{ 1, 2, 3, 4, 5 }; const ptr = @as([*:3]u16, array[0..2 :3]); try testing.expect(eql(u16, span(ptr), &[_]u16{ 1, 2 })); - try testing.expect(eql(u16, span(&array), &[_]u16{ 1, 2, 3, 4, 5 })); try testing.expectEqual(@as(?[:0]u16, null), span(@as(?[*:0]u16, null))); } @@ -919,22 +895,15 @@ test "lenSliceTo" { } } -/// Takes a pointer to an array, an array, a vector, a sentinel-terminated pointer, -/// a slice or a tuple, and returns the length. -/// In the case of a sentinel-terminated array, it uses the array length. -/// For C pointers it assumes it is a pointer-to-many with a 0 sentinel. +/// Takes a sentinel-terminated pointer and iterates over the memory to find the +/// sentinel and determine the length. +/// `[*c]` pointers are assumed to be non-null and 0-terminated. pub fn len(value: anytype) usize { - return switch (@typeInfo(@TypeOf(value))) { - .Array => |info| info.len, - .Vector => |info| info.len, + switch (@typeInfo(@TypeOf(value))) { .Pointer => |info| switch (info.size) { - .One => switch (@typeInfo(info.child)) { - .Array => value.len, - else => @compileError("invalid type given to std.mem.len"), - }, .Many => { const sentinel_ptr = info.sentinel orelse - @compileError("length of pointer with no sentinel"); + @compileError("invalid type given to std.mem.len: " ++ @typeName(@TypeOf(value))); const sentinel = @ptrCast(*align(1) const info.child, sentinel_ptr).*; return indexOfSentinel(info.child, sentinel, value); }, @@ -942,41 +911,18 @@ pub fn len(value: anytype) usize { assert(value != null); return indexOfSentinel(info.child, 0, value); }, - .Slice => value.len, + else => @compileError("invalid type given to std.mem.len: " ++ @typeName(@TypeOf(value))), }, - .Struct => |info| if (info.is_tuple) { - return info.fields.len; - } else @compileError("invalid type given to std.mem.len"), - else => @compileError("invalid type given to std.mem.len"), - }; + else => @compileError("invalid type given to std.mem.len: " ++ @typeName(@TypeOf(value))), + } } test "len" { - try testing.expect(len("aoeu") == 4); - - { - var array: [5]u16 = [_]u16{ 1, 2, 3, 4, 5 }; - try testing.expect(len(&array) == 5); - try testing.expect(len(array[0..3]) == 3); - array[2] = 0; - const ptr = @as([*:0]u16, array[0..2 :0]); - try testing.expect(len(ptr) == 2); - } - { - var array: [5:0]u16 = [_:0]u16{ 1, 2, 3, 4, 5 }; - try testing.expect(len(&array) == 5); - array[2] = 0; - try testing.expect(len(&array) == 5); - } - { - const vector: meta.Vector(2, u32) = [2]u32{ 1, 2 }; - try testing.expect(len(vector) == 2); - } - { - const tuple = .{ 1, 2 }; - try testing.expect(len(tuple) == 2); - try testing.expect(tuple[0] == 1); - } + var array: [5]u16 = [_]u16{ 1, 2, 0, 4, 5 }; + const ptr = @as([*:4]u16, array[0..3 :4]); + try testing.expect(len(ptr) == 3); + const c_ptr = @as([*c]u16, ptr); + try testing.expect(len(c_ptr) == 2); } pub fn indexOfSentinel(comptime Elem: type, comptime sentinel: Elem, ptr: [*:sentinel]const Elem) usize { |
