authorgravatar for vitalijusv.h4qjc@slmail.meVitalijus Valantiejus <vitalijusv.h4qjc@slmail.me> 2023-12-21 22:43:12+00:00
committergravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2023-12-22 16:35:28+02:00
logfd98fc1c5f83224cf1f128df7ba1cd24e4d40808
tree6e15dbdc84426d886a0ec86cf8cca73dede6c227
parent70b248497ab87471997c62a515bf4bb4109899b9

std.fmt: fix formatting of array pointers

- Clean up array formatting code. Remove buggy formatting of array pointers, deference pointer to reuse existing array formatting logic. - Change default specifier for array pointers to be "{any}", to be consistent with slices. - Allow using "{x}" and "{e}" for arrays and slices for all number types, including u8. Fixes #18185

1 files changed, 32 insertions(+), 48 deletions(-)

lib/std/fmt.zig+32-48
...@@ -435,7 +435,7 @@ pub fn defaultSpec(comptime T: type) [:0]const u8 {...@@ -435,7 +435,7 @@ pub fn defaultSpec(comptime T: type) [:0]const u8 {
435 .Array => |_| return ANY,435 .Array => |_| return ANY,
436 .Pointer => |ptr_info| switch (ptr_info.size) {436 .Pointer => |ptr_info| switch (ptr_info.size) {
437 .One => switch (@typeInfo(ptr_info.child)) {437 .One => switch (@typeInfo(ptr_info.child)) {
438 .Array => |_| return "*",438 .Array => |_| return ANY,
439 else => {},439 else => {},
440 },440 },
441 .Many, .C => return "*",441 .Many, .C => return "*",
...@@ -599,26 +599,7 @@ pub fn formatType(...@@ -599,26 +599,7 @@ pub fn formatType(
599 },599 },
600 .Pointer => |ptr_info| switch (ptr_info.size) {600 .Pointer => |ptr_info| switch (ptr_info.size) {
601 .One => switch (@typeInfo(ptr_info.child)) {601 .One => switch (@typeInfo(ptr_info.child)) {
602 .Array => |info| {602 .Array, .Enum, .Union, .Struct => {
603 if (actual_fmt.len == 0)
604 @compileError("cannot format array ref without a specifier (i.e. {s} or {*})");
605 if (info.child == u8) {
606 switch (actual_fmt[0]) {
607 's', 'x', 'X', 'e', 'E' => {
608 comptime checkTextFmt(actual_fmt);
609 return formatBuf(value, options, writer);
610 },
611 else => {},
612 }
613 }
614 for (value, 0..) |item, i| {
615 comptime checkTextFmt(actual_fmt);
616 if (i != 0) try formatBuf(", ", options, writer);
617 try formatBuf(item, options, writer);
618 }
619 return;
620 },
621 .Enum, .Union, .Struct => {
622 return formatType(value.*, actual_fmt, options, writer, max_depth);603 return formatType(value.*, actual_fmt, options, writer, max_depth);
623 },604 },
624 else => return format(writer, "{s}@{x}", .{ @typeName(ptr_info.child), @intFromPtr(value) }),605 else => return format(writer, "{s}@{x}", .{ @typeName(ptr_info.child), @intFromPtr(value) }),
...@@ -629,14 +610,8 @@ pub fn formatType(...@@ -629,14 +610,8 @@ pub fn formatType(
629 if (ptr_info.sentinel) |_| {610 if (ptr_info.sentinel) |_| {
630 return formatType(mem.span(value), actual_fmt, options, writer, max_depth);611 return formatType(mem.span(value), actual_fmt, options, writer, max_depth);
631 }612 }
632 if (ptr_info.child == u8) {613 if (actual_fmt[0] == 's' and ptr_info.child == u8) {
633 switch (actual_fmt[0]) {614 return formatBuf(mem.span(value), options, writer);
634 's', 'x', 'X', 'e', 'E' => {
635 comptime checkTextFmt(actual_fmt);
636 return formatBuf(mem.span(value), options, writer);
637 },
638 else => {},
639 }
640 }615 }
641 invalidFmtError(fmt, value);616 invalidFmtError(fmt, value);
642 },617 },
...@@ -646,14 +621,8 @@ pub fn formatType(...@@ -646,14 +621,8 @@ pub fn formatType(
646 if (max_depth == 0) {621 if (max_depth == 0) {
647 return writer.writeAll("{ ... }");622 return writer.writeAll("{ ... }");
648 }623 }
649 if (ptr_info.child == u8) {624 if (actual_fmt[0] == 's' and ptr_info.child == u8) {
650 switch (actual_fmt[0]) {625 return formatBuf(value, options, writer);
651 's', 'x', 'X', 'e', 'E' => {
652 comptime checkTextFmt(actual_fmt);
653 return formatBuf(value, options, writer);
654 },
655 else => {},
656 }
657 }626 }
658 try writer.writeAll("{ ");627 try writer.writeAll("{ ");
659 for (value, 0..) |elem, i| {628 for (value, 0..) |elem, i| {
...@@ -671,14 +640,8 @@ pub fn formatType(...@@ -671,14 +640,8 @@ pub fn formatType(
671 if (max_depth == 0) {640 if (max_depth == 0) {
672 return writer.writeAll("{ ... }");641 return writer.writeAll("{ ... }");
673 }642 }
674 if (info.child == u8) {643 if (actual_fmt[0] == 's' and info.child == u8) {
675 switch (actual_fmt[0]) {644 return formatBuf(&value, options, writer);
676 's', 'x', 'X', 'e', 'E' => {
677 comptime checkTextFmt(actual_fmt);
678 return formatBuf(&value, options, writer);
679 },
680 else => {},
681 }
682 }645 }
683 try writer.writeAll("{ ");646 try writer.writeAll("{ ");
684 for (value, 0..) |elem, i| {647 for (value, 0..) |elem, i| {
...@@ -2205,12 +2168,22 @@ test "buffer" {...@@ -2205,12 +2168,22 @@ test "buffer" {
2205 }2168 }
2206}2169}
22072170
2171// Test formatting of arrays by value, by single-item pointer, and as a slice
2172fn expectArrayFmt(expected: []const u8, comptime template: []const u8, comptime array_value: anytype) !void {
2173 try expectFmt(expected, template, .{array_value});
2174 try expectFmt(expected, template, .{&array_value});
2175 var runtime_zero: usize = 0;
2176 _ = &runtime_zero;
2177 try expectFmt(expected, template, .{array_value[runtime_zero..]});
2178}
2179
2208test "array" {2180test "array" {
2209 {2181 {
2210 const value: [3]u8 = "abc".*;2182 const value: [3]u8 = "abc".*;
2211 try expectFmt("array: abc\n", "array: {s}\n", .{value});2183 try expectArrayFmt("array: abc\n", "array: {s}\n", value);
2212 try expectFmt("array: abc\n", "array: {s}\n", .{&value});2184 try expectArrayFmt("array: { 97, 98, 99 }\n", "array: {d}\n", value);
2213 try expectFmt("array: { 97, 98, 99 }\n", "array: {d}\n", .{value});2185 try expectArrayFmt("array: { 61, 62, 63 }\n", "array: {x}\n", value);
2186 try expectArrayFmt("array: { 97, 98, 99 }\n", "array: {any}\n", value);
22142187
2215 var buf: [100]u8 = undefined;2188 var buf: [100]u8 = undefined;
2216 try expectFmt(2189 try expectFmt(
...@@ -2219,12 +2192,23 @@ test "array" {...@@ -2219,12 +2192,23 @@ test "array" {
2219 .{&value},2192 .{&value},
2220 );2193 );
2221 }2194 }
2195
2196 {
2197 const value = [2][3]u8{ "abc".*, "def".* };
2198
2199 try expectArrayFmt("array: { abc, def }\n", "array: {s}\n", value);
2200 try expectArrayFmt("array: { { 97, 98, 99 }, { 100, 101, 102 } }\n", "array: {d}\n", value);
2201 try expectArrayFmt("array: { { 61, 62, 63 }, { 64, 65, 66 } }\n", "array: {x}\n", value);
2202 }
2222}2203}
22232204
2224test "slice" {2205test "slice" {
2225 {2206 {
2226 const value: []const u8 = "abc";2207 const value: []const u8 = "abc";
2227 try expectFmt("slice: abc\n", "slice: {s}\n", .{value});2208 try expectFmt("slice: abc\n", "slice: {s}\n", .{value});
2209 try expectFmt("slice: { 97, 98, 99 }\n", "slice: {d}\n", .{value});
2210 try expectFmt("slice: { 61, 62, 63 }\n", "slice: {x}\n", .{value});
2211 try expectFmt("slice: { 97, 98, 99 }\n", "slice: {any}\n", .{value});
2228 }2212 }
2229 {2213 {
2230 var runtime_zero: usize = 0;2214 var runtime_zero: usize = 0;