aboutsummaryrefslogtreecommitdiff
path: root/lib/std
diff options
context:
space:
mode:
authorAndrew Kelley <andrew@ziglang.org>2020-03-01 13:53:13 -0500
committerAndrew Kelley <andrew@ziglang.org>2020-03-01 13:53:13 -0500
commit3c1432701129bacf95b944f0f86af2d96ae72c69 (patch)
treed05e7ddf19d709975f432e60f5a2321309078517 /lib/std
parentb99c6d56da3d2db995c268fb07f48548ea6d1148 (diff)
parentef3d761da545a3a72928ed0e0ba3b749a4cb74d8 (diff)
downloadzig-3c1432701129bacf95b944f0f86af2d96ae72c69.tar.gz
zig-3c1432701129bacf95b944f0f86af2d96ae72c69.zip
Merge branch 'daurnimator-fmt-sentinel-pointers'
closes #3972
Diffstat (limited to 'lib/std')
-rw-r--r--lib/std/builtin.zig2
-rw-r--r--lib/std/cstr.zig2
-rw-r--r--lib/std/fmt.zig6
-rw-r--r--lib/std/mem.zig138
-rw-r--r--lib/std/meta.zig26
-rw-r--r--lib/std/net.zig2
-rw-r--r--lib/std/os.zig2
-rw-r--r--lib/std/special/c.zig2
8 files changed, 162 insertions, 18 deletions
diff --git a/lib/std/builtin.zig b/lib/std/builtin.zig
index de37fda903..a4f0ef269f 100644
--- a/lib/std/builtin.zig
+++ b/lib/std/builtin.zig
@@ -185,6 +185,7 @@ pub const TypeInfo = union(enum) {
child: type,
is_allowzero: bool,
+ /// This field is an optional type.
/// The type of the sentinel is the element type of the pointer, which is
/// the value of the `child` field in this struct. However there is no way
/// to refer to that type here, so we use `var`.
@@ -206,6 +207,7 @@ pub const TypeInfo = union(enum) {
len: comptime_int,
child: type,
+ /// This field is an optional type.
/// The type of the sentinel is the element type of the array, which is
/// the value of the `child` field in this struct. However there is no way
/// to refer to that type here, so we use `var`.
diff --git a/lib/std/cstr.zig b/lib/std/cstr.zig
index 4057d4b62b..9cb16b0ed3 100644
--- a/lib/std/cstr.zig
+++ b/lib/std/cstr.zig
@@ -28,7 +28,7 @@ test "cstr fns" {
fn testCStrFnsImpl() void {
testing.expect(cmp("aoeu", "aoez") == -1);
- testing.expect(mem.len(u8, "123456789") == 9);
+ testing.expect(mem.len("123456789") == 9);
}
/// Returns a mutable, null-terminated slice with the same length as `slice`.
diff --git a/lib/std/fmt.zig b/lib/std/fmt.zig
index d093101646..3729b7dc87 100644
--- a/lib/std/fmt.zig
+++ b/lib/std/fmt.zig
@@ -441,10 +441,12 @@ pub fn formatType(
else => return format(context, Errors, output, "{}@{x}", .{ @typeName(T.Child), @ptrToInt(value) }),
},
.Many, .C => {
+ if (ptr_info.sentinel) |sentinel| {
+ return formatType(mem.span(value), fmt, options, context, Errors, output, max_depth);
+ }
if (ptr_info.child == u8) {
if (fmt.len > 0 and fmt[0] == 's') {
- const len = mem.len(u8, value);
- return formatText(value[0..len], fmt, options, context, Errors, output);
+ return formatText(mem.span(value), fmt, options, context, Errors, output);
}
}
return format(context, Errors, output, "{}@{x}", .{ @typeName(T.Child), @ptrToInt(value) });
diff --git a/lib/std/mem.zig b/lib/std/mem.zig
index a4b48bbc1c..a6c4d0057e 100644
--- a/lib/std/mem.zig
+++ b/lib/std/mem.zig
@@ -333,8 +333,20 @@ pub fn zeroes(comptime T: type) T {
}
return array;
},
- .Vector, .ErrorUnion, .ErrorSet, .Union, .Fn, .BoundFn, .Type, .NoReturn, .Undefined, .Opaque, .Frame, .AnyFrame, => {
- @compileError("Can't set a "++ @typeName(T) ++" to zero.");
+ .Vector,
+ .ErrorUnion,
+ .ErrorSet,
+ .Union,
+ .Fn,
+ .BoundFn,
+ .Type,
+ .NoReturn,
+ .Undefined,
+ .Opaque,
+ .Frame,
+ .AnyFrame,
+ => {
+ @compileError("Can't set a " ++ @typeName(T) ++ " to zero.");
},
}
}
@@ -470,18 +482,115 @@ pub fn eql(comptime T: type, a: []const T, b: []const T) bool {
return true;
}
-pub fn len(comptime T: type, ptr: [*:0]const T) usize {
- var count: usize = 0;
- while (ptr[count] != 0) : (count += 1) {}
- return count;
-}
-
+/// Deprecated. Use `span`.
pub fn toSliceConst(comptime T: type, ptr: [*:0]const T) [:0]const T {
- return ptr[0..len(T, ptr) :0];
+ return ptr[0..len(ptr) :0];
}
+/// Deprecated. Use `span`.
pub fn toSlice(comptime T: type, ptr: [*:0]T) [:0]T {
- return ptr[0..len(T, ptr) :0];
+ return ptr[0..len(ptr) :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 {
+ var ptr_info = @typeInfo(T).Pointer;
+ switch (ptr_info.size) {
+ .One => switch (@typeInfo(ptr_info.child)) {
+ .Array => |info| {
+ ptr_info.child = info.child;
+ ptr_info.sentinel = info.sentinel;
+ },
+ else => @compileError("invalid type given to std.mem.Span"),
+ },
+ .C => {
+ ptr_info.sentinel = 0;
+ ptr_info.is_allowzero = false;
+ },
+ .Many, .Slice => {},
+ }
+ ptr_info.size = .Slice;
+ return @Type(std.builtin.TypeInfo{ .Pointer = ptr_info });
+}
+
+test "Span" {
+ testing.expect(Span(*[5]u16) == []u16);
+ testing.expect(Span(*const [5]u16) == []const u16);
+ testing.expect(Span([]u16) == []u16);
+ testing.expect(Span([]const u8) == []const u8);
+ testing.expect(Span([:1]u16) == [:1]u16);
+ testing.expect(Span([:1]const u8) == [:1]const u8);
+ testing.expect(Span([*:1]u16) == [:1]u16);
+ testing.expect(Span([*:1]const u8) == [:1]const u8);
+ testing.expect(Span([*c]u16) == [:0]u16);
+ 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.
+pub fn span(ptr: var) Span(@TypeOf(ptr)) {
+ const Result = Span(@TypeOf(ptr));
+ const l = len(ptr);
+ if (@typeInfo(Result).Pointer.sentinel) |s| {
+ return ptr[0..l :s];
+ } else {
+ return ptr[0..l];
+ }
+}
+
+test "span" {
+ var array: [5]u16 = [_]u16{ 1, 2, 3, 4, 5 };
+ const ptr = array[0..2 :3].ptr;
+ testing.expect(eql(u16, span(ptr), &[_]u16{ 1, 2 }));
+ testing.expect(eql(u16, span(&array), &[_]u16{ 1, 2, 3, 4, 5 }));
+}
+
+/// Takes a pointer to an array, an array, a sentinel-terminated pointer,
+/// or a slice, and returns the length.
+pub fn len(ptr: var) usize {
+ return switch (@typeInfo(@TypeOf(ptr))) {
+ .Array => |info| info.len,
+ .Pointer => |info| switch (info.size) {
+ .One => switch (@typeInfo(info.child)) {
+ .Array => |x| x.len,
+ else => @compileError("invalid type given to std.mem.length"),
+ },
+ .Many => if (info.sentinel) |sentinel|
+ indexOfSentinel(info.child, sentinel, ptr)
+ else
+ @compileError("length of pointer with no sentinel"),
+ .C => indexOfSentinel(info.child, 0, ptr),
+ .Slice => ptr.len,
+ },
+ else => @compileError("invalid type given to std.mem.length"),
+ };
+}
+
+test "len" {
+ testing.expect(len("aoeu") == 4);
+
+ {
+ var array: [5]u16 = [_]u16{ 1, 2, 3, 4, 5 };
+ testing.expect(len(&array) == 5);
+ testing.expect(len(array[0..3]) == 3);
+ array[2] = 0;
+ const ptr = array[0..2 :0].ptr;
+ testing.expect(len(ptr) == 2);
+ }
+}
+
+pub fn indexOfSentinel(comptime Elem: type, comptime sentinel: Elem, ptr: [*:sentinel]const Elem) usize {
+ var i: usize = 0;
+ while (ptr[i] != sentinel) {
+ i += 1;
+ }
+ return i;
}
/// Returns true if all elements in a slice are equal to the scalar value provided
@@ -1753,8 +1862,13 @@ fn SubArrayPtrReturnType(comptime T: type, comptime length: usize) type {
return *[length]meta.Child(meta.Child(T));
}
-///Given a pointer to an array, returns a pointer to a portion of that array, preserving constness.
-pub fn subArrayPtr(ptr: var, comptime start: usize, comptime length: usize) SubArrayPtrReturnType(@TypeOf(ptr), length) {
+/// Given a pointer to an array, returns a pointer to a portion of that array, preserving constness.
+/// TODO this will be obsoleted by https://github.com/ziglang/zig/issues/863
+pub fn subArrayPtr(
+ ptr: var,
+ comptime start: usize,
+ comptime length: usize,
+) SubArrayPtrReturnType(@TypeOf(ptr), length) {
assert(start + length <= ptr.*.len);
const ReturnType = SubArrayPtrReturnType(@TypeOf(ptr), length);
diff --git a/lib/std/meta.zig b/lib/std/meta.zig
index 58fd6b9da7..65809abb5c 100644
--- a/lib/std/meta.zig
+++ b/lib/std/meta.zig
@@ -115,6 +115,32 @@ test "std.meta.Child" {
testing.expect(Child(?u8) == u8);
}
+/// Given a type with a sentinel e.g. `[:0]u8`, returns the sentinel
+pub fn Sentinel(comptime T: type) Child(T) {
+ // comptime asserts that ptr has a sentinel
+ switch (@typeInfo(T)) {
+ .Array => |arrayInfo| {
+ return comptime arrayInfo.sentinel.?;
+ },
+ .Pointer => |ptrInfo| {
+ switch (ptrInfo.size) {
+ .Many, .Slice => {
+ return comptime ptrInfo.sentinel.?;
+ },
+ else => {},
+ }
+ },
+ else => {},
+ }
+ @compileError("not a sentinel type, found '" ++ @typeName(T) ++ "'");
+}
+
+test "std.meta.Sentinel" {
+ testing.expectEqual(@as(u8, 0), Sentinel([:0]u8));
+ testing.expectEqual(@as(u8, 0), Sentinel([*:0]u8));
+ testing.expectEqual(@as(u8, 0), Sentinel([5:0]u8));
+}
+
pub fn containerLayout(comptime T: type) TypeInfo.ContainerLayout {
return switch (@typeInfo(T)) {
.Struct => |info| info.layout,
diff --git a/lib/std/net.zig b/lib/std/net.zig
index b54803cd39..6d0daefdc0 100644
--- a/lib/std/net.zig
+++ b/lib/std/net.zig
@@ -352,7 +352,7 @@ pub const Address = extern union {
unreachable;
}
- const path_len = std.mem.len(u8, @ptrCast([*:0]const u8, &self.un.path));
+ const path_len = std.mem.len(@ptrCast([*:0]const u8, &self.un.path));
return @intCast(os.socklen_t, @sizeOf(os.sockaddr_un) - self.un.path.len + path_len);
},
else => unreachable,
diff --git a/lib/std/os.zig b/lib/std/os.zig
index 24d78bec9a..127ada8fe5 100644
--- a/lib/std/os.zig
+++ b/lib/std/os.zig
@@ -1095,7 +1095,7 @@ pub fn createNullDelimitedEnvMap(allocator: *mem.Allocator, env_map: *const std.
pub fn freeNullDelimitedEnvMap(allocator: *mem.Allocator, envp_buf: []?[*:0]u8) void {
for (envp_buf) |env| {
- const env_buf = if (env) |ptr| ptr[0 .. mem.len(u8, ptr) + 1] else break;
+ const env_buf = if (env) |ptr| ptr[0 .. mem.len(ptr) + 1] else break;
allocator.free(env_buf);
}
allocator.free(envp_buf);
diff --git a/lib/std/special/c.zig b/lib/std/special/c.zig
index 1f11fabca0..e0c2636df1 100644
--- a/lib/std/special/c.zig
+++ b/lib/std/special/c.zig
@@ -47,7 +47,7 @@ fn strcmp(s1: [*:0]const u8, s2: [*:0]const u8) callconv(.C) c_int {
}
fn strlen(s: [*:0]const u8) callconv(.C) usize {
- return std.mem.len(u8, s);
+ return std.mem.len(s);
}
fn strncmp(_l: [*:0]const u8, _r: [*:0]const u8, _n: usize) callconv(.C) c_int {