authorgravatar for thatlemon@gmail.comLemonBoy <thatlemon@gmail.com> 2020-10-29 22:22:25+01:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-01-02 17:12:57-07:00
log6f53653db17933fe2c8502d5bfc60857097b8bff
treecfb5be60b1361bab1a5a25c36edbc09e0a7c87f6
parent5275280ede72fbc3eb702ff7f01fac07b306ca46

std: Refactor the slice formatting code

Also fix the `*` specifier for more types, print an error message if we can't show the value address.

1 files changed, 49 insertions(+), 20 deletions(-)

lib/std/fmt.zig+49-20
...@@ -367,6 +367,36 @@ pub fn format(...@@ -367,6 +367,36 @@ pub fn format(
367 }367 }
368}368}
369369
370pub fn formatAddress(value: anytype, options: FormatOptions, writer: anytype) @TypeOf(writer).Error!void {
371 const T = @TypeOf(value);
372
373 switch (@typeInfo(T)) {
374 .Pointer => |info| {
375 try writer.writeAll(@typeName(info.child) ++ "@");
376 if (info.size == .Slice)
377 try formatInt(@ptrToInt(value.ptr), 16, false, FormatOptions{}, writer)
378 else
379 try formatInt(@ptrToInt(value), 16, false, FormatOptions{}, writer);
380 return;
381 },
382 .Optional => |info| {
383 if (@typeInfo(info.child) == .Pointer) {
384 try writer.writeAll(@typeName(info.child) ++ "@");
385 try formatInt(@ptrToInt(value), 16, false, FormatOptions{}, writer);
386 return;
387 }
388 },
389 .Array => |info| {
390 try writer.writeAll(@typeName(info.child) ++ "@");
391 try formatInt(@ptrToInt(value), 16, false, FormatOptions{}, writer);
392 return;
393 },
394 else => {},
395 }
396
397 @compileError("Cannot format non-pointer type " ++ @typeName(T) ++ " with * specifier");
398}
399
370pub fn formatType(400pub fn formatType(
371 value: anytype,401 value: anytype,
372 comptime fmt: []const u8,402 comptime fmt: []const u8,
...@@ -375,10 +405,7 @@ pub fn formatType(...@@ -375,10 +405,7 @@ pub fn formatType(
375 max_depth: usize,405 max_depth: usize,
376) @TypeOf(writer).Error!void {406) @TypeOf(writer).Error!void {
377 if (comptime std.mem.eql(u8, fmt, "*")) {407 if (comptime std.mem.eql(u8, fmt, "*")) {
378 try writer.writeAll(@typeName(std.meta.Child(@TypeOf(value))));408 return formatAddress(value, options, writer);
379 try writer.writeAll("@");
380 try formatInt(@ptrToInt(value), 16, false, FormatOptions{}, writer);
381 return;
382 }409 }
383410
384 const T = @TypeOf(value);411 const T = @TypeOf(value);
...@@ -499,25 +526,18 @@ pub fn formatType(...@@ -499,25 +526,18 @@ pub fn formatType(
499 return format(writer, "{}@{x}", .{ @typeName(@typeInfo(T).Pointer.child), @ptrToInt(value) });526 return format(writer, "{}@{x}", .{ @typeName(@typeInfo(T).Pointer.child), @ptrToInt(value) });
500 },527 },
501 .Slice => {528 .Slice => {
502 if (fmt.len > 0 and ((fmt[0] == 'x') or (fmt[0] == 'X'))) {
503 return formatText(value, fmt, options, writer);
504 }
505 if (ptr_info.child == u8) {529 if (ptr_info.child == u8) {
506 return formatText(value, fmt, options, writer);530 return formatText(value, fmt, options, writer);
507 } else if (fmt.len > 0 and ((fmt[0] == 'v') or (fmt[0] == 'V'))) {531 }
508 try format(writer, "[", .{});532
509 var i: usize = 0;533 try writer.writeAll("[");
510 for (value) |one| {534 for (value) |elem, i| {
511 if (i == value.len - 1) {535 try formatType(elem, fmt, options, writer, max_depth);
512 try format(writer, "{}", .{one});536 if (i != value.len - 1) {
513 } else { 537 try writer.writeAll(", ");
514 try format(writer, "{}, ", .{one});
515 }
516 i += 1;
517 }538 }
518 return format(writer, "]", .{});
519 }539 }
520 return format(writer, "{}@{x}", .{ @typeName(ptr_info.child), @ptrToInt(value.ptr) });540 try writer.writeAll("]");
521 },541 },
522 },542 },
523 .Array => |info| {543 .Array => |info| {
...@@ -1553,7 +1573,7 @@ test "slice" {...@@ -1553,7 +1573,7 @@ test "slice" {
1553 {1573 {
1554 var runtime_zero: usize = 0;1574 var runtime_zero: usize = 0;
1555 const value = @intToPtr([*]align(1) const []const u8, 0xdeadbeef)[runtime_zero..runtime_zero];1575 const value = @intToPtr([*]align(1) const []const u8, 0xdeadbeef)[runtime_zero..runtime_zero];
1556 try testFmt("slice: []const u8@deadbeef\n", "slice: {}\n", .{value});1576 try testFmt("slice: []const u8@deadbeef\n", "slice: {*}\n", .{value});
1557 }1577 }
1558 {1578 {
1559 const null_term_slice: [:0]const u8 = "\x00hello\x00";1579 const null_term_slice: [:0]const u8 = "\x00hello\x00";
...@@ -1562,6 +1582,15 @@ test "slice" {...@@ -1562,6 +1582,15 @@ test "slice" {
15621582
1563 try testFmt("buf: Test\n", "buf: {s:5}\n", .{"Test"});1583 try testFmt("buf: Test\n", "buf: {s:5}\n", .{"Test"});
1564 try testFmt("buf: Test\n Other text", "buf: {s}\n Other text", .{"Test"});1584 try testFmt("buf: Test\n Other text", "buf: {s}\n Other text", .{"Test"});
1585
1586 {
1587 var int_slice = [_]u32{ 1, 4096, 391891, 1111111111 };
1588 var runtime_zero: usize = 0;
1589 try testFmt("int: [1, 4096, 391891, 1111111111]", "int: {}", .{int_slice[runtime_zero..]});
1590 try testFmt("int: [1, 4096, 391891, 1111111111]", "int: {d}", .{int_slice[runtime_zero..]});
1591 try testFmt("int: [1, 1000, 5fad3, 423a35c7]", "int: {x}", .{int_slice[runtime_zero..]});
1592 try testFmt("int: [00001, 01000, 5fad3, 423a35c7]", "int: {x:0>5}", .{int_slice[runtime_zero..]});
1593 }
1565}1594}
15661595
1567test "escape non-printable" {1596test "escape non-printable" {