Skip to content

print contents of sentinel-terminated pointers in std.fmt #3972

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 6 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion lib/std/cstr.zig
Original file line number Diff line number Diff line change
Expand Up @@ -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(u8, "123456789".*) == 9);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The way the test was before is testing what it intends to test - calculating the length of a null terminated pointer. e.g. the zig equivalent of strlen.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should it perhaps be .ptr instead?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The type of a string literal is *const [9:0]u8; IMO asking for the length of a pointer seems weird, and we need to .* to make sense...

}

/// Returns a mutable, null-terminated slice with the same length as `slice`.
Expand Down
8 changes: 6 additions & 2 deletions lib/std/fmt.zig
Original file line number Diff line number Diff line change
Expand Up @@ -442,10 +442,14 @@ pub fn formatType(
else => return format(context, Errors, output, "{}@{x}", .{ @typeName(T.Child), @ptrToInt(value) }),
},
.Many, .C => {
if (ptr_info.sentinel) |sentinel| {
const slice = mem.pointerToSlice([:sentinel]const ptr_info.child, value);
return formatType(slice, 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);
const slice = mem.pointerToSlice([:0]const u8, @as([*:0]const u8, value));
return formatText(slice, fmt, options, context, Errors, output);
}
}
return format(context, Errors, output, "{}@{x}", .{ @typeName(T.Child), @ptrToInt(value) });
Expand Down
21 changes: 17 additions & 4 deletions lib/std/mem.zig
Original file line number Diff line number Diff line change
Expand Up @@ -365,18 +365,31 @@ 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 {
pub fn len(comptime T: type, ptr: var) usize {
const sentinel: T = comptime meta.Sentinel(@TypeOf(ptr));
var count: usize = 0;
while (ptr[count] != 0) : (count += 1) {}
while (ptr[count] != sentinel) : (count += 1) {}
return count;
}

/// Given a sentintel-terminated pointer-to-many, find the sentintel and return a slice.
pub fn pointerToSlice(comptime T: type, ptr: blk: {
var info = @typeInfo(T).Pointer;
info.size = .Many;
break :blk @Type(std.builtin.TypeInfo{ .Pointer = info });
}) T {
const sentinel = comptime meta.Sentinel(T);
return ptr[0..len(meta.Child(T), ptr) :sentinel];
}

/// Deprecated; use pointerToSlice instead
pub fn toSliceConst(comptime T: type, ptr: [*:0]const T) [:0]const T {
return ptr[0..len(T, ptr) :0];
return pointerToSlice([:0]const T, ptr);
}

/// Deprecated; use pointerToSlice instead
pub fn toSlice(comptime T: type, ptr: [*:0]T) [:0]T {
return ptr[0..len(T, ptr) :0];
return pointerToSlice([:0]T, ptr);
}

/// Returns true if all elements in a slice are equal to the scalar value provided
Expand Down
26 changes: 26 additions & 0 deletions lib/std/meta.zig
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,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)) {
TypeId.Struct => |info| info.layout,
Expand Down
14 changes: 7 additions & 7 deletions src-self-hosted/main.zig
Original file line number Diff line number Diff line change
Expand Up @@ -792,7 +792,7 @@ async fn fmtPath(fmt: *Fmt, file_path_ref: []const u8, check_mode: bool) FmtErro
}

fn cmdVersion(allocator: *Allocator, args: []const []const u8) !void {
try stdout.print("{}\n", .{std.mem.toSliceConst(u8, c.ZIG_VERSION_STRING)});
try stdout.print("{}\n", .{c.ZIG_VERSION_STRING});
}

fn cmdHelp(allocator: *Allocator, args: []const []const u8) !void {
Expand Down Expand Up @@ -863,12 +863,12 @@ fn cmdInternalBuildInfo(allocator: *Allocator, args: []const []const u8) !void {
\\ZIG_DIA_GUIDS_LIB {}
\\
, .{
std.mem.toSliceConst(u8, c.ZIG_CMAKE_BINARY_DIR),
std.mem.toSliceConst(u8, c.ZIG_CXX_COMPILER),
std.mem.toSliceConst(u8, c.ZIG_LLD_INCLUDE_PATH),
std.mem.toSliceConst(u8, c.ZIG_LLD_LIBRARIES),
std.mem.toSliceConst(u8, c.ZIG_LLVM_CONFIG_EXE),
std.mem.toSliceConst(u8, c.ZIG_DIA_GUIDS_LIB),
c.ZIG_CMAKE_BINARY_DIR,
c.ZIG_CXX_COMPILER,
c.ZIG_LLD_INCLUDE_PATH,
c.ZIG_LLD_LIBRARIES,
c.ZIG_LLVM_CONFIG_EXE,
c.ZIG_DIA_GUIDS_LIB,
});
}

Expand Down
2 changes: 1 addition & 1 deletion test/stage1/behavior/misc.zig
Original file line number Diff line number Diff line change
Expand Up @@ -365,7 +365,7 @@ test "string concatenation" {
comptime expect(@TypeOf(a) == *const [12:0]u8);
comptime expect(@TypeOf(b) == *const [12:0]u8);

const len = mem.len(u8, b);
const len = b.len;
const len_with_null = len + 1;
{
var i: u32 = 0;
Expand Down