Skip to content

Commit 3c14327

Browse files
committed
Merge branch 'daurnimator-fmt-sentinel-pointers'
closes #3972
2 parents b99c6d5 + ef3d761 commit 3c14327

File tree

11 files changed

+171
-27
lines changed

11 files changed

+171
-27
lines changed

lib/std/builtin.zig

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,7 @@ pub const TypeInfo = union(enum) {
185185
child: type,
186186
is_allowzero: bool,
187187

188+
/// This field is an optional type.
188189
/// The type of the sentinel is the element type of the pointer, which is
189190
/// the value of the `child` field in this struct. However there is no way
190191
/// to refer to that type here, so we use `var`.
@@ -206,6 +207,7 @@ pub const TypeInfo = union(enum) {
206207
len: comptime_int,
207208
child: type,
208209

210+
/// This field is an optional type.
209211
/// The type of the sentinel is the element type of the array, which is
210212
/// the value of the `child` field in this struct. However there is no way
211213
/// to refer to that type here, so we use `var`.

lib/std/cstr.zig

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ test "cstr fns" {
2828

2929
fn testCStrFnsImpl() void {
3030
testing.expect(cmp("aoeu", "aoez") == -1);
31-
testing.expect(mem.len(u8, "123456789") == 9);
31+
testing.expect(mem.len("123456789") == 9);
3232
}
3333

3434
/// Returns a mutable, null-terminated slice with the same length as `slice`.

lib/std/fmt.zig

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -441,10 +441,12 @@ pub fn formatType(
441441
else => return format(context, Errors, output, "{}@{x}", .{ @typeName(T.Child), @ptrToInt(value) }),
442442
},
443443
.Many, .C => {
444+
if (ptr_info.sentinel) |sentinel| {
445+
return formatType(mem.span(value), fmt, options, context, Errors, output, max_depth);
446+
}
444447
if (ptr_info.child == u8) {
445448
if (fmt.len > 0 and fmt[0] == 's') {
446-
const len = mem.len(u8, value);
447-
return formatText(value[0..len], fmt, options, context, Errors, output);
449+
return formatText(mem.span(value), fmt, options, context, Errors, output);
448450
}
449451
}
450452
return format(context, Errors, output, "{}@{x}", .{ @typeName(T.Child), @ptrToInt(value) });

lib/std/mem.zig

Lines changed: 126 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -333,8 +333,20 @@ pub fn zeroes(comptime T: type) T {
333333
}
334334
return array;
335335
},
336-
.Vector, .ErrorUnion, .ErrorSet, .Union, .Fn, .BoundFn, .Type, .NoReturn, .Undefined, .Opaque, .Frame, .AnyFrame, => {
337-
@compileError("Can't set a "++ @typeName(T) ++" to zero.");
336+
.Vector,
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.");
338350
},
339351
}
340352
}
@@ -470,18 +482,115 @@ pub fn eql(comptime T: type, a: []const T, b: []const T) bool {
470482
return true;
471483
}
472484

473-
pub fn len(comptime T: type, ptr: [*:0]const T) usize {
474-
var count: usize = 0;
475-
while (ptr[count] != 0) : (count += 1) {}
476-
return count;
477-
}
478-
485+
/// Deprecated. Use `span`.
479486
pub 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];
481488
}
482489

490+
/// Deprecated. Use `span`.
483491
pub 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.
500+
pub 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+
520+
test "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.
537+
pub 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+
547+
test "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.
556+
pub 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+
575+
test "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+
588+
pub 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;
485594
}
486595

487596
/// 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 {
17531862
return *[length]meta.Child(meta.Child(T));
17541863
}
17551864

1756-
///Given a pointer to an array, returns a pointer to a portion of that array, preserving constness.
1757-
pub fn subArrayPtr(ptr: var, comptime start: usize, comptime length: usize) SubArrayPtrReturnType(@TypeOf(ptr), length) {
1865+
/// Given a pointer to an array, returns a pointer to a portion of that array, preserving constness.
1866+
/// TODO this will be obsoleted by https://github.com/ziglang/zig/issues/863
1867+
pub fn subArrayPtr(
1868+
ptr: var,
1869+
comptime start: usize,
1870+
comptime length: usize,
1871+
) SubArrayPtrReturnType(@TypeOf(ptr), length) {
17581872
assert(start + length <= ptr.*.len);
17591873

17601874
const ReturnType = SubArrayPtrReturnType(@TypeOf(ptr), length);

lib/std/meta.zig

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,32 @@ test "std.meta.Child" {
115115
testing.expect(Child(?u8) == u8);
116116
}
117117

118+
/// Given a type with a sentinel e.g. `[:0]u8`, returns the sentinel
119+
pub 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+
138+
test "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+
118144
pub fn containerLayout(comptime T: type) TypeInfo.ContainerLayout {
119145
return switch (@typeInfo(T)) {
120146
.Struct => |info| info.layout,

lib/std/net.zig

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -352,7 +352,7 @@ pub const Address = extern union {
352352
unreachable;
353353
}
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));
356356
return @intCast(os.socklen_t, @sizeOf(os.sockaddr_un) - self.un.path.len + path_len);
357357
},
358358
else => unreachable,

lib/std/os.zig

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1095,7 +1095,7 @@ pub fn createNullDelimitedEnvMap(allocator: *mem.Allocator, env_map: *const std.
10951095

10961096
pub fn freeNullDelimitedEnvMap(allocator: *mem.Allocator, envp_buf: []?[*:0]u8) void {
10971097
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;
10991099
allocator.free(env_buf);
11001100
}
11011101
allocator.free(envp_buf);

lib/std/special/c.zig

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ fn strcmp(s1: [*:0]const u8, s2: [*:0]const u8) callconv(.C) c_int {
4747
}
4848

4949
fn strlen(s: [*:0]const u8) callconv(.C) usize {
50-
return std.mem.len(u8, s);
50+
return std.mem.len(s);
5151
}
5252

5353
fn strncmp(_l: [*:0]const u8, _r: [*:0]const u8, _n: usize) callconv(.C) c_int {

src-self-hosted/main.zig

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -792,7 +792,7 @@ async fn fmtPath(fmt: *Fmt, file_path_ref: []const u8, check_mode: bool) FmtErro
792792
}
793793

794794
fn 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});
796796
}
797797

798798
fn cmdHelp(allocator: *Allocator, args: []const []const u8) !void {
@@ -863,12 +863,12 @@ fn cmdInternalBuildInfo(allocator: *Allocator, args: []const []const u8) !void {
863863
\\ZIG_DIA_GUIDS_LIB {}
864864
\\
865865
, .{
866-
std.mem.toSliceConst(u8, c.ZIG_CMAKE_BINARY_DIR),
867-
std.mem.toSliceConst(u8, c.ZIG_CXX_COMPILER),
868-
std.mem.toSliceConst(u8, c.ZIG_LLD_INCLUDE_PATH),
869-
std.mem.toSliceConst(u8, c.ZIG_LLD_LIBRARIES),
870-
std.mem.toSliceConst(u8, c.ZIG_LLVM_CONFIG_EXE),
871-
std.mem.toSliceConst(u8, c.ZIG_DIA_GUIDS_LIB),
866+
c.ZIG_CMAKE_BINARY_DIR,
867+
c.ZIG_CXX_COMPILER,
868+
c.ZIG_LLD_INCLUDE_PATH,
869+
c.ZIG_LLD_LIBRARIES,
870+
c.ZIG_LLVM_CONFIG_EXE,
871+
c.ZIG_DIA_GUIDS_LIB,
872872
});
873873
}
874874

src-self-hosted/translate_c.zig

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4849,7 +4849,7 @@ fn transPreprocessorEntities(c: *Context, unit: *ZigClangASTUnit) Error!void {
48494849
}
48504850

48514851
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

48544854
tok_list.shrink(0);
48554855
var tokenizer = std.c.Tokenizer{

test/stage1/behavior/misc.zig

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -335,7 +335,7 @@ test "string concatenation" {
335335
comptime expect(@TypeOf(a) == *const [12:0]u8);
336336
comptime expect(@TypeOf(b) == *const [12:0]u8);
337337

338-
const len = mem.len(u8, b);
338+
const len = mem.len(b);
339339
const len_with_null = len + 1;
340340
{
341341
var i: u32 = 0;

0 commit comments

Comments
 (0)