aboutsummaryrefslogtreecommitdiff
path: root/lib/std/mem.zig
diff options
context:
space:
mode:
authorAndrew Kelley <andrew@ziglang.org>2023-02-03 12:49:40 -0700
committerAndrew Kelley <andrew@ziglang.org>2023-02-03 12:49:40 -0700
commitfab9b7110ed1fa7bb082aad5e095047441db2b24 (patch)
tree81fef60aa45e7980dab8f3e23e5b5e92b40ee0a9 /lib/std/mem.zig
parentd20d69b59e6b65a99f45cb6a45c14e887034dd18 (diff)
parent60935decd318498529a016eeb1379d943a7e830d (diff)
downloadzig-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.zig102
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 {