authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-03-01 13:53:13-05:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-03-01 13:53:13-05:00
log3c1432701129bacf95b944f0f86af2d96ae72c69
treed05e7ddf19d709975f432e60f5a2321309078517
parentb99c6d56da3d2db995c268fb07f48548ea6d1148
parentef3d761da545a3a72928ed0e0ba3b749a4cb74d8
signaturelock-open Commit is signed but in an unrecognized format.

Merge branch 'daurnimator-fmt-sentinel-pointers'

closes #3972

11 files changed, 171 insertions(+), 27 deletions(-)

lib/std/builtin.zig+2
...@@ -185,6 +185,7 @@ pub const TypeInfo = union(enum) {...@@ -185,6 +185,7 @@ pub const TypeInfo = union(enum) {
185 child: type,185 child: type,
186 is_allowzero: bool,186 is_allowzero: bool,
187187
188 /// This field is an optional type.
188 /// The type of the sentinel is the element type of the pointer, which is189 /// The type of the sentinel is the element type of the pointer, which is
189 /// the value of the `child` field in this struct. However there is no way190 /// the value of the `child` field in this struct. However there is no way
190 /// to refer to that type here, so we use `var`.191 /// to refer to that type here, so we use `var`.
...@@ -206,6 +207,7 @@ pub const TypeInfo = union(enum) {...@@ -206,6 +207,7 @@ pub const TypeInfo = union(enum) {
206 len: comptime_int,207 len: comptime_int,
207 child: type,208 child: type,
208209
210 /// This field is an optional type.
209 /// The type of the sentinel is the element type of the array, which is211 /// The type of the sentinel is the element type of the array, which is
210 /// the value of the `child` field in this struct. However there is no way212 /// the value of the `child` field in this struct. However there is no way
211 /// to refer to that type here, so we use `var`.213 /// to refer to that type here, so we use `var`.
lib/std/cstr.zig+1-1
...@@ -28,7 +28,7 @@ test "cstr fns" {...@@ -28,7 +28,7 @@ test "cstr fns" {
2828
29fn testCStrFnsImpl() void {29fn testCStrFnsImpl() void {
30 testing.expect(cmp("aoeu", "aoez") == -1);30 testing.expect(cmp("aoeu", "aoez") == -1);
31 testing.expect(mem.len(u8, "123456789") == 9);31 testing.expect(mem.len("123456789") == 9);
32}32}
3333
34/// Returns a mutable, null-terminated slice with the same length as `slice`.34/// Returns a mutable, null-terminated slice with the same length as `slice`.
lib/std/fmt.zig+4-2
...@@ -441,10 +441,12 @@ pub fn formatType(...@@ -441,10 +441,12 @@ pub fn formatType(
441 else => return format(context, Errors, output, "{}@{x}", .{ @typeName(T.Child), @ptrToInt(value) }),441 else => return format(context, Errors, output, "{}@{x}", .{ @typeName(T.Child), @ptrToInt(value) }),
442 },442 },
443 .Many, .C => {443 .Many, .C => {
444 if (ptr_info.sentinel) |sentinel| {
445 return formatType(mem.span(value), fmt, options, context, Errors, output, max_depth);
446 }
444 if (ptr_info.child == u8) {447 if (ptr_info.child == u8) {
445 if (fmt.len > 0 and fmt[0] == 's') {448 if (fmt.len > 0 and fmt[0] == 's') {
446 const len = mem.len(u8, value);449 return formatText(mem.span(value), fmt, options, context, Errors, output);
447 return formatText(value[0..len], fmt, options, context, Errors, output);
448 }450 }
449 }451 }
450 return format(context, Errors, output, "{}@{x}", .{ @typeName(T.Child), @ptrToInt(value) });452 return format(context, Errors, output, "{}@{x}", .{ @typeName(T.Child), @ptrToInt(value) });
lib/std/mem.zig+126-12
...@@ -333,8 +333,20 @@ pub fn zeroes(comptime T: type) T {...@@ -333,8 +333,20 @@ pub fn zeroes(comptime T: type) T {
333 }333 }
334 return array;334 return array;
335 },335 },
336 .Vector, .ErrorUnion, .ErrorSet, .Union, .Fn, .BoundFn, .Type, .NoReturn, .Undefined, .Opaque, .Frame, .AnyFrame, => {336 .Vector,
337 @compileError("Can't set a "++ @typeName(T) ++" to zero.");337 .ErrorUnion,
338 .ErrorSet,
339 .Union,
340 .Fn,
341 .BoundFn,
342 .Type,
343 .NoReturn,
344 .Undefined,
345 .Opaque,
346 .Frame,
347 .AnyFrame,
348 => {
349 @compileError("Can't set a " ++ @typeName(T) ++ " to zero.");
338 },350 },
339 }351 }
340}352}
...@@ -470,18 +482,115 @@ pub fn eql(comptime T: type, a: []const T, b: []const T) bool {...@@ -470,18 +482,115 @@ pub fn eql(comptime T: type, a: []const T, b: []const T) bool {
470 return true;482 return true;
471}483}
472484
473pub fn len(comptime T: type, ptr: [*:0]const T) usize {485/// Deprecated. Use `span`.
474 var count: usize = 0;
475 while (ptr[count] != 0) : (count += 1) {}
476 return count;
477}
478
479pub fn toSliceConst(comptime T: type, ptr: [*:0]const T) [:0]const T {486pub fn toSliceConst(comptime T: type, ptr: [*:0]const T) [:0]const T {
480 return ptr[0..len(T, ptr) :0];487 return ptr[0..len(ptr) :0];
481}488}
482489
490/// Deprecated. Use `span`.
483pub fn toSlice(comptime T: type, ptr: [*:0]T) [:0]T {491pub fn toSlice(comptime T: type, ptr: [*:0]T) [:0]T {
484 return ptr[0..len(T, ptr) :0];492 return ptr[0..len(ptr) :0];
493}
494
495/// Takes a pointer to an array, a sentinel-terminated pointer, or a slice, and
496/// returns a slice. If there is a sentinel on the input type, there will be a
497/// sentinel on the output type. The constness of the output type matches
498/// the constness of the input type. `[*c]` pointers are assumed to be 0-terminated,
499/// and assumed to not allow null.
500pub fn Span(comptime T: type) type {
501 var ptr_info = @typeInfo(T).Pointer;
502 switch (ptr_info.size) {
503 .One => switch (@typeInfo(ptr_info.child)) {
504 .Array => |info| {
505 ptr_info.child = info.child;
506 ptr_info.sentinel = info.sentinel;
507 },
508 else => @compileError("invalid type given to std.mem.Span"),
509 },
510 .C => {
511 ptr_info.sentinel = 0;
512 ptr_info.is_allowzero = false;
513 },
514 .Many, .Slice => {},
515 }
516 ptr_info.size = .Slice;
517 return @Type(std.builtin.TypeInfo{ .Pointer = ptr_info });
518}
519
520test "Span" {
521 testing.expect(Span(*[5]u16) == []u16);
522 testing.expect(Span(*const [5]u16) == []const u16);
523 testing.expect(Span([]u16) == []u16);
524 testing.expect(Span([]const u8) == []const u8);
525 testing.expect(Span([:1]u16) == [:1]u16);
526 testing.expect(Span([:1]const u8) == [:1]const u8);
527 testing.expect(Span([*:1]u16) == [:1]u16);
528 testing.expect(Span([*:1]const u8) == [:1]const u8);
529 testing.expect(Span([*c]u16) == [:0]u16);
530 testing.expect(Span([*c]const u8) == [:0]const u8);
531}
532
533/// Takes a pointer to an array, a sentinel-terminated pointer, or a slice, and
534/// returns a slice. If there is a sentinel on the input type, there will be a
535/// sentinel on the output type. The constness of the output type matches
536/// the constness of the input type.
537pub fn span(ptr: var) Span(@TypeOf(ptr)) {
538 const Result = Span(@TypeOf(ptr));
539 const l = len(ptr);
540 if (@typeInfo(Result).Pointer.sentinel) |s| {
541 return ptr[0..l :s];
542 } else {
543 return ptr[0..l];
544 }
545}
546
547test "span" {
548 var array: [5]u16 = [_]u16{ 1, 2, 3, 4, 5 };
549 const ptr = array[0..2 :3].ptr;
550 testing.expect(eql(u16, span(ptr), &[_]u16{ 1, 2 }));
551 testing.expect(eql(u16, span(&array), &[_]u16{ 1, 2, 3, 4, 5 }));
552}
553
554/// Takes a pointer to an array, an array, a sentinel-terminated pointer,
555/// or a slice, and returns the length.
556pub fn len(ptr: var) usize {
557 return switch (@typeInfo(@TypeOf(ptr))) {
558 .Array => |info| info.len,
559 .Pointer => |info| switch (info.size) {
560 .One => switch (@typeInfo(info.child)) {
561 .Array => |x| x.len,
562 else => @compileError("invalid type given to std.mem.length"),
563 },
564 .Many => if (info.sentinel) |sentinel|
565 indexOfSentinel(info.child, sentinel, ptr)
566 else
567 @compileError("length of pointer with no sentinel"),
568 .C => indexOfSentinel(info.child, 0, ptr),
569 .Slice => ptr.len,
570 },
571 else => @compileError("invalid type given to std.mem.length"),
572 };
573}
574
575test "len" {
576 testing.expect(len("aoeu") == 4);
577
578 {
579 var array: [5]u16 = [_]u16{ 1, 2, 3, 4, 5 };
580 testing.expect(len(&array) == 5);
581 testing.expect(len(array[0..3]) == 3);
582 array[2] = 0;
583 const ptr = array[0..2 :0].ptr;
584 testing.expect(len(ptr) == 2);
585 }
586}
587
588pub fn indexOfSentinel(comptime Elem: type, comptime sentinel: Elem, ptr: [*:sentinel]const Elem) usize {
589 var i: usize = 0;
590 while (ptr[i] != sentinel) {
591 i += 1;
592 }
593 return i;
485}594}
486595
487/// Returns true if all elements in a slice are equal to the scalar value provided596/// 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 {...@@ -1753,8 +1862,13 @@ fn SubArrayPtrReturnType(comptime T: type, comptime length: usize) type {
1753 return *[length]meta.Child(meta.Child(T));1862 return *[length]meta.Child(meta.Child(T));
1754}1863}
17551864
1756///Given a pointer to an array, returns a pointer to a portion of that array, preserving constness.1865/// Given a pointer to an array, returns a pointer to a portion of that array, preserving constness.
1757pub fn subArrayPtr(ptr: var, comptime start: usize, comptime length: usize) SubArrayPtrReturnType(@TypeOf(ptr), length) {1866/// TODO this will be obsoleted by https://github.com/ziglang/zig/issues/863
1867pub fn subArrayPtr(
1868 ptr: var,
1869 comptime start: usize,
1870 comptime length: usize,
1871) SubArrayPtrReturnType(@TypeOf(ptr), length) {
1758 assert(start + length <= ptr.*.len);1872 assert(start + length <= ptr.*.len);
17591873
1760 const ReturnType = SubArrayPtrReturnType(@TypeOf(ptr), length);1874 const ReturnType = SubArrayPtrReturnType(@TypeOf(ptr), length);
lib/std/meta.zig+26
...@@ -115,6 +115,32 @@ test "std.meta.Child" {...@@ -115,6 +115,32 @@ test "std.meta.Child" {
115 testing.expect(Child(?u8) == u8);115 testing.expect(Child(?u8) == u8);
116}116}
117117
118/// Given a type with a sentinel e.g. `[:0]u8`, returns the sentinel
119pub fn Sentinel(comptime T: type) Child(T) {
120 // comptime asserts that ptr has a sentinel
121 switch (@typeInfo(T)) {
122 .Array => |arrayInfo| {
123 return comptime arrayInfo.sentinel.?;
124 },
125 .Pointer => |ptrInfo| {
126 switch (ptrInfo.size) {
127 .Many, .Slice => {
128 return comptime ptrInfo.sentinel.?;
129 },
130 else => {},
131 }
132 },
133 else => {},
134 }
135 @compileError("not a sentinel type, found '" ++ @typeName(T) ++ "'");
136}
137
138test "std.meta.Sentinel" {
139 testing.expectEqual(@as(u8, 0), Sentinel([:0]u8));
140 testing.expectEqual(@as(u8, 0), Sentinel([*:0]u8));
141 testing.expectEqual(@as(u8, 0), Sentinel([5:0]u8));
142}
143
118pub fn containerLayout(comptime T: type) TypeInfo.ContainerLayout {144pub fn containerLayout(comptime T: type) TypeInfo.ContainerLayout {
119 return switch (@typeInfo(T)) {145 return switch (@typeInfo(T)) {
120 .Struct => |info| info.layout,146 .Struct => |info| info.layout,
lib/std/net.zig+1-1
...@@ -352,7 +352,7 @@ pub const Address = extern union {...@@ -352,7 +352,7 @@ pub const Address = extern union {
352 unreachable;352 unreachable;
353 }353 }
354354
355 const path_len = std.mem.len(u8, @ptrCast([*:0]const u8, &self.un.path));355 const path_len = std.mem.len(@ptrCast([*:0]const u8, &self.un.path));
356 return @intCast(os.socklen_t, @sizeOf(os.sockaddr_un) - self.un.path.len + path_len);356 return @intCast(os.socklen_t, @sizeOf(os.sockaddr_un) - self.un.path.len + path_len);
357 },357 },
358 else => unreachable,358 else => unreachable,
lib/std/os.zig+1-1
...@@ -1095,7 +1095,7 @@ pub fn createNullDelimitedEnvMap(allocator: *mem.Allocator, env_map: *const std....@@ -1095,7 +1095,7 @@ pub fn createNullDelimitedEnvMap(allocator: *mem.Allocator, env_map: *const std.
10951095
1096pub fn freeNullDelimitedEnvMap(allocator: *mem.Allocator, envp_buf: []?[*:0]u8) void {1096pub fn freeNullDelimitedEnvMap(allocator: *mem.Allocator, envp_buf: []?[*:0]u8) void {
1097 for (envp_buf) |env| {1097 for (envp_buf) |env| {
1098 const env_buf = if (env) |ptr| ptr[0 .. mem.len(u8, ptr) + 1] else break;1098 const env_buf = if (env) |ptr| ptr[0 .. mem.len(ptr) + 1] else break;
1099 allocator.free(env_buf);1099 allocator.free(env_buf);
1100 }1100 }
1101 allocator.free(envp_buf);1101 allocator.free(envp_buf);
lib/std/special/c.zig+1-1
...@@ -47,7 +47,7 @@ fn strcmp(s1: [*:0]const u8, s2: [*:0]const u8) callconv(.C) c_int {...@@ -47,7 +47,7 @@ fn strcmp(s1: [*:0]const u8, s2: [*:0]const u8) callconv(.C) c_int {
47}47}
4848
49fn strlen(s: [*:0]const u8) callconv(.C) usize {49fn strlen(s: [*:0]const u8) callconv(.C) usize {
50 return std.mem.len(u8, s);50 return std.mem.len(s);
51}51}
5252
53fn strncmp(_l: [*:0]const u8, _r: [*:0]const u8, _n: usize) callconv(.C) c_int {53fn strncmp(_l: [*:0]const u8, _r: [*:0]const u8, _n: usize) callconv(.C) c_int {
src-self-hosted/main.zig+7-7
...@@ -792,7 +792,7 @@ async fn fmtPath(fmt: *Fmt, file_path_ref: []const u8, check_mode: bool) FmtErro...@@ -792,7 +792,7 @@ async fn fmtPath(fmt: *Fmt, file_path_ref: []const u8, check_mode: bool) FmtErro
792}792}
793793
794fn cmdVersion(allocator: *Allocator, args: []const []const u8) !void {794fn cmdVersion(allocator: *Allocator, args: []const []const u8) !void {
795 try stdout.print("{}\n", .{std.mem.toSliceConst(u8, c.ZIG_VERSION_STRING)});795 try stdout.print("{}\n", .{c.ZIG_VERSION_STRING});
796}796}
797797
798fn cmdHelp(allocator: *Allocator, args: []const []const u8) !void {798fn cmdHelp(allocator: *Allocator, args: []const []const u8) !void {
...@@ -863,12 +863,12 @@ fn cmdInternalBuildInfo(allocator: *Allocator, args: []const []const u8) !void {...@@ -863,12 +863,12 @@ fn cmdInternalBuildInfo(allocator: *Allocator, args: []const []const u8) !void {
863 \\ZIG_DIA_GUIDS_LIB {}863 \\ZIG_DIA_GUIDS_LIB {}
864 \\864 \\
865 , .{865 , .{
866 std.mem.toSliceConst(u8, c.ZIG_CMAKE_BINARY_DIR),866 c.ZIG_CMAKE_BINARY_DIR,
867 std.mem.toSliceConst(u8, c.ZIG_CXX_COMPILER),867 c.ZIG_CXX_COMPILER,
868 std.mem.toSliceConst(u8, c.ZIG_LLD_INCLUDE_PATH),868 c.ZIG_LLD_INCLUDE_PATH,
869 std.mem.toSliceConst(u8, c.ZIG_LLD_LIBRARIES),869 c.ZIG_LLD_LIBRARIES,
870 std.mem.toSliceConst(u8, c.ZIG_LLVM_CONFIG_EXE),870 c.ZIG_LLVM_CONFIG_EXE,
871 std.mem.toSliceConst(u8, c.ZIG_DIA_GUIDS_LIB),871 c.ZIG_DIA_GUIDS_LIB,
872 });872 });
873}873}
874874
src-self-hosted/translate_c.zig+1-1
...@@ -4849,7 +4849,7 @@ fn transPreprocessorEntities(c: *Context, unit: *ZigClangASTUnit) Error!void {...@@ -4849,7 +4849,7 @@ fn transPreprocessorEntities(c: *Context, unit: *ZigClangASTUnit) Error!void {
4849 }4849 }
48504850
4851 const begin_c = ZigClangSourceManager_getCharacterData(c.source_manager, begin_loc);4851 const begin_c = ZigClangSourceManager_getCharacterData(c.source_manager, begin_loc);
4852 const slice = begin_c[0..mem.len(u8, begin_c)];4852 const slice = begin_c[0..mem.len(begin_c)];
48534853
4854 tok_list.shrink(0);4854 tok_list.shrink(0);
4855 var tokenizer = std.c.Tokenizer{4855 var tokenizer = std.c.Tokenizer{
test/stage1/behavior/misc.zig+1-1
...@@ -335,7 +335,7 @@ test "string concatenation" {...@@ -335,7 +335,7 @@ test "string concatenation" {
335 comptime expect(@TypeOf(a) == *const [12:0]u8);335 comptime expect(@TypeOf(a) == *const [12:0]u8);
336 comptime expect(@TypeOf(b) == *const [12:0]u8);336 comptime expect(@TypeOf(b) == *const [12:0]u8);
337337
338 const len = mem.len(u8, b);338 const len = mem.len(b);
339 const len_with_null = len + 1;339 const len_with_null = len + 1;
340 {340 {
341 var i: u32 = 0;341 var i: u32 = 0;