authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-09-17 16:17:15-04:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2020-09-17 16:17:15-04:00
log3672a187999c3db6eba35d9a9184e7cc066ed629
treedc8ebe30dee31989d36f2fb00eb3aeca257b26e9
parent2962be81359a6806f66d220474abcb0b1cf7edf0
parentb7f9f779afa6de38f7599d8ffd9937fb48b9284c
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #6360 from LemonBoy/some-fmt-fixes

Two std.fmt fixes

2 files changed, 57 insertions(+), 84 deletions(-)

lib/std/fmt.zig+56-83
...@@ -22,7 +22,7 @@ pub const Alignment = enum {...@@ -22,7 +22,7 @@ pub const Alignment = enum {
22pub const FormatOptions = struct {22pub const FormatOptions = struct {
23 precision: ?usize = null,23 precision: ?usize = null,
24 width: ?usize = null,24 width: ?usize = null,
25 alignment: Alignment = .Left,25 alignment: Alignment = .Right,
26 fill: u8 = ' ',26 fill: u8 = ' ',
27};27};
2828
...@@ -327,7 +327,7 @@ pub fn formatType(...@@ -327,7 +327,7 @@ pub fn formatType(
327 max_depth: usize,327 max_depth: usize,
328) @TypeOf(writer).Error!void {328) @TypeOf(writer).Error!void {
329 if (comptime std.mem.eql(u8, fmt, "*")) {329 if (comptime std.mem.eql(u8, fmt, "*")) {
330 try writer.writeAll(@typeName(@typeInfo(@TypeOf(value)).Pointer.child));330 try writer.writeAll(@typeName(std.meta.Child(@TypeOf(value))));
331 try writer.writeAll("@");331 try writer.writeAll("@");
332 try formatInt(@ptrToInt(value), 16, false, FormatOptions{}, writer);332 try formatInt(@ptrToInt(value), 16, false, FormatOptions{}, writer);
333 return;333 return;
...@@ -631,26 +631,22 @@ pub fn formatBuf(...@@ -631,26 +631,22 @@ pub fn formatBuf(
631 writer: anytype,631 writer: anytype,
632) !void {632) !void {
633 const width = options.width orelse buf.len;633 const width = options.width orelse buf.len;
634 var padding = if (width > buf.len) (width - buf.len) else 0;634 const padding = if (width > buf.len) (width - buf.len) else 0;
635 const pad_byte = [1]u8{options.fill};635
636 switch (options.alignment) {636 switch (options.alignment) {
637 .Left => {637 .Left => {
638 try writer.writeAll(buf);638 try writer.writeAll(buf);
639 while (padding > 0) : (padding -= 1) {639 try writer.writeByteNTimes(options.fill, padding);
640 try writer.writeAll(&pad_byte);
641 }
642 },640 },
643 .Center => {641 .Center => {
644 const padl = padding / 2;642 const left_padding = padding / 2;
645 var i: usize = 0;643 const right_padding = (padding + 1) / 2;
646 while (i < padl) : (i += 1) try writer.writeAll(&pad_byte);644 try writer.writeByteNTimes(options.fill, left_padding);
647 try writer.writeAll(buf);645 try writer.writeAll(buf);
648 while (i < padding) : (i += 1) try writer.writeAll(&pad_byte);646 try writer.writeByteNTimes(options.fill, right_padding);
649 },647 },
650 .Right => {648 .Right => {
651 while (padding > 0) : (padding -= 1) {649 try writer.writeByteNTimes(options.fill, padding);
652 try writer.writeAll(&pad_byte);
653 }
654 try writer.writeAll(buf);650 try writer.writeAll(buf);
655 },651 },
656 }652 }
...@@ -941,61 +937,27 @@ pub fn formatInt(...@@ -941,61 +937,27 @@ pub fn formatInt(
941 options: FormatOptions,937 options: FormatOptions,
942 writer: anytype,938 writer: anytype,
943) !void {939) !void {
940 assert(base >= 2);
941
944 const int_value = if (@TypeOf(value) == comptime_int) blk: {942 const int_value = if (@TypeOf(value) == comptime_int) blk: {
945 const Int = math.IntFittingRange(value, value);943 const Int = math.IntFittingRange(value, value);
946 break :blk @as(Int, value);944 break :blk @as(Int, value);
947 } else945 } else
948 value;946 value;
949947
950 if (@typeInfo(@TypeOf(int_value)).Int.is_signed) {948 const value_info = @typeInfo(@TypeOf(int_value)).Int;
951 return formatIntSigned(int_value, base, uppercase, options, writer);
952 } else {
953 return formatIntUnsigned(int_value, base, uppercase, options, writer);
954 }
955}
956949
957fn formatIntSigned(950 // The type must have the same size as `base` or be wider in order for the
958 value: anytype,951 // division to work
959 base: u8,952 const min_int_bits = comptime math.max(value_info.bits, 8);
960 uppercase: bool,953 const MinInt = std.meta.Int(false, min_int_bits);
961 options: FormatOptions,
962 writer: anytype,
963) !void {
964 const new_options = FormatOptions{
965 .width = if (options.width) |w| (if (w == 0) 0 else w - 1) else null,
966 .precision = options.precision,
967 .fill = options.fill,
968 };
969 const bit_count = @typeInfo(@TypeOf(value)).Int.bits;
970 const Uint = std.meta.Int(false, bit_count);
971 if (value < 0) {
972 try writer.writeAll("-");
973 const new_value = math.absCast(value);
974 return formatIntUnsigned(new_value, base, uppercase, new_options, writer);
975 } else if (options.width == null or options.width.? == 0) {
976 return formatIntUnsigned(@intCast(Uint, value), base, uppercase, options, writer);
977 } else {
978 try writer.writeAll("+");
979 const new_value = @intCast(Uint, value);
980 return formatIntUnsigned(new_value, base, uppercase, new_options, writer);
981 }
982}
983954
984fn formatIntUnsigned(955 const abs_value = math.absCast(int_value);
985 value: anytype,956 // The worst case in terms of space needed is base 2, plus 1 for the sign
986 base: u8,957 var buf: [1 + math.max(value_info.bits, 1)]u8 = undefined;
987 uppercase: bool,
988 options: FormatOptions,
989 writer: anytype,
990) !void {
991 assert(base >= 2);
992 const value_info = @typeInfo(@TypeOf(value)).Int;
993 var buf: [math.max(value_info.bits, 1)]u8 = undefined;
994 const min_int_bits = comptime math.max(value_info.bits, @typeInfo(@TypeOf(base)).Int.bits);
995 const MinInt = std.meta.Int(value_info.is_signed, min_int_bits);
996 var a: MinInt = value;
997 var index: usize = buf.len;
998958
959 var a: MinInt = abs_value;
960 var index: usize = buf.len;
999 while (true) {961 while (true) {
1000 const digit = a % base;962 const digit = a % base;
1001 index -= 1;963 index -= 1;
...@@ -1004,25 +966,21 @@ fn formatIntUnsigned(...@@ -1004,25 +966,21 @@ fn formatIntUnsigned(
1004 if (a == 0) break;966 if (a == 0) break;
1005 }967 }
1006968
1007 const digits_buf = buf[index..];969 if (value_info.is_signed) {
1008 const width = options.width orelse 0;970 if (value < 0) {
1009 const padding = if (width > digits_buf.len) (width - digits_buf.len) else 0;971 // Negative integer
1010972 index -= 1;
1011 if (padding > index) {973 buf[index] = '-';
1012 const zero_byte: u8 = options.fill;974 } else if (options.width == null or options.width.? == 0) {
1013 var leftover_padding = padding - index;975 // Positive integer, omit the plus sign
1014 while (true) {976 } else {
1015 try writer.writeAll(@as(*const [1]u8, &zero_byte)[0..]);977 // Positive integer
1016 leftover_padding -= 1;978 index -= 1;
1017 if (leftover_padding == 0) break;979 buf[index] = '+';
1018 }980 }
1019 mem.set(u8, buf[0..index], options.fill);
1020 return writer.writeAll(&buf);
1021 } else {
1022 const padded_buf = buf[index - padding ..];
1023 mem.set(u8, padded_buf[0..padding], options.fill);
1024 return writer.writeAll(padded_buf);
1025 }981 }
982
983 return formatBuf(buf[index..], options, writer);
1026}984}
1027985
1028pub fn formatIntBuf(out_buf: []u8, value: anytype, base: u8, uppercase: bool, options: FormatOptions) usize {986pub fn formatIntBuf(out_buf: []u8, value: anytype, base: u8, uppercase: bool, options: FormatOptions) usize {
...@@ -1246,6 +1204,10 @@ test "optional" {...@@ -1246,6 +1204,10 @@ test "optional" {
1246 const value: ?i32 = null;1204 const value: ?i32 = null;
1247 try testFmt("optional: null\n", "optional: {}\n", .{value});1205 try testFmt("optional: null\n", "optional: {}\n", .{value});
1248 }1206 }
1207 {
1208 const value = @intToPtr(?*i32, 0xf000d000);
1209 try testFmt("optional: *i32@f000d000\n", "optional: {*}\n", .{value});
1210 }
1249}1211}
12501212
1251test "error" {1213test "error" {
...@@ -1283,7 +1245,17 @@ test "int.specifier" {...@@ -1283,7 +1245,17 @@ test "int.specifier" {
12831245
1284test "int.padded" {1246test "int.padded" {
1285 try testFmt("u8: ' 1'", "u8: '{:4}'", .{@as(u8, 1)});1247 try testFmt("u8: ' 1'", "u8: '{:4}'", .{@as(u8, 1)});
1286 try testFmt("u8: 'xxx1'", "u8: '{:x<4}'", .{@as(u8, 1)});1248 try testFmt("u8: '1000'", "u8: '{:0<4}'", .{@as(u8, 1)});
1249 try testFmt("u8: '0001'", "u8: '{:0>4}'", .{@as(u8, 1)});
1250 try testFmt("u8: '0100'", "u8: '{:0^4}'", .{@as(u8, 1)});
1251 try testFmt("i8: '-1 '", "i8: '{:<4}'", .{@as(i8, -1)});
1252 try testFmt("i8: ' -1'", "i8: '{:>4}'", .{@as(i8, -1)});
1253 try testFmt("i8: ' -1 '", "i8: '{:^4}'", .{@as(i8, -1)});
1254 try testFmt("i16: '-1234'", "i16: '{:4}'", .{@as(i16, -1234)});
1255 try testFmt("i16: '+1234'", "i16: '{:4}'", .{@as(i16, 1234)});
1256 try testFmt("i16: '-12345'", "i16: '{:4}'", .{@as(i16, -12345)});
1257 try testFmt("i16: '+12345'", "i16: '{:4}'", .{@as(i16, 12345)});
1258 try testFmt("u16: '12345'", "u16: '{:4}'", .{@as(u16, 12345)});
1287}1259}
12881260
1289test "buffer" {1261test "buffer" {
...@@ -1329,7 +1301,7 @@ test "slice" {...@@ -1329,7 +1301,7 @@ test "slice" {
1329 try testFmt("slice: []const u8@deadbeef\n", "slice: {}\n", .{value});1301 try testFmt("slice: []const u8@deadbeef\n", "slice: {}\n", .{value});
1330 }1302 }
13311303
1332 try testFmt("buf: Test \n", "buf: {s:5}\n", .{"Test"});1304 try testFmt("buf: Test\n", "buf: {s:5}\n", .{"Test"});
1333 try testFmt("buf: Test\n Other text", "buf: {s}\n Other text", .{"Test"});1305 try testFmt("buf: Test\n Other text", "buf: {s}\n Other text", .{"Test"});
1334}1306}
13351307
...@@ -1362,7 +1334,7 @@ test "cstr" {...@@ -1362,7 +1334,7 @@ test "cstr" {
1362 .{@ptrCast([*c]const u8, "Test C")},1334 .{@ptrCast([*c]const u8, "Test C")},
1363 );1335 );
1364 try testFmt(1336 try testFmt(
1365 "cstr: Test C \n",1337 "cstr: Test C\n",
1366 "cstr: {s:10}\n",1338 "cstr: {s:10}\n",
1367 .{@ptrCast([*c]const u8, "Test C")},1339 .{@ptrCast([*c]const u8, "Test C")},
1368 );1340 );
...@@ -1805,7 +1777,7 @@ test "vector" {...@@ -1805,7 +1777,7 @@ test "vector" {
18051777
1806 try testFmt("{ true, false, true, false }", "{}", .{vbool});1778 try testFmt("{ true, false, true, false }", "{}", .{vbool});
1807 try testFmt("{ -2, -1, 0, 1 }", "{}", .{vi64});1779 try testFmt("{ -2, -1, 0, 1 }", "{}", .{vi64});
1808 try testFmt("{ - 2, - 1, + 0, + 1 }", "{d:5}", .{vi64});1780 try testFmt("{ -2, -1, +0, +1 }", "{d:5}", .{vi64});
1809 try testFmt("{ 1000, 2000, 3000, 4000 }", "{}", .{vu64});1781 try testFmt("{ 1000, 2000, 3000, 4000 }", "{}", .{vu64});
1810 try testFmt("{ 3e8, 7d0, bb8, fa0 }", "{x}", .{vu64});1782 try testFmt("{ 3e8, 7d0, bb8, fa0 }", "{x}", .{vu64});
1811 try testFmt("{ 1kB, 2kB, 3kB, 4kB }", "{B}", .{vu64});1783 try testFmt("{ 1kB, 2kB, 3kB, 4kB }", "{B}", .{vu64});
...@@ -1818,15 +1790,16 @@ test "enum-literal" {...@@ -1818,15 +1790,16 @@ test "enum-literal" {
18181790
1819test "padding" {1791test "padding" {
1820 try testFmt("Simple", "{}", .{"Simple"});1792 try testFmt("Simple", "{}", .{"Simple"});
1821 try testFmt("true ", "{:10}", .{true});1793 try testFmt(" true", "{:10}", .{true});
1822 try testFmt(" true", "{:>10}", .{true});1794 try testFmt(" true", "{:>10}", .{true});
1823 try testFmt("======true", "{:=>10}", .{true});1795 try testFmt("======true", "{:=>10}", .{true});
1824 try testFmt("true======", "{:=<10}", .{true});1796 try testFmt("true======", "{:=<10}", .{true});
1825 try testFmt(" true ", "{:^10}", .{true});1797 try testFmt(" true ", "{:^10}", .{true});
1826 try testFmt("===true===", "{:=^10}", .{true});1798 try testFmt("===true===", "{:=^10}", .{true});
1827 try testFmt("Minimum width", "{:18} width", .{"Minimum"});1799 try testFmt(" Minimum width", "{:18} width", .{"Minimum"});
1828 try testFmt("==================Filled", "{:=>24}", .{"Filled"});1800 try testFmt("==================Filled", "{:=>24}", .{"Filled"});
1829 try testFmt(" Centered ", "{:^24}", .{"Centered"});1801 try testFmt(" Centered ", "{:^24}", .{"Centered"});
1802 try testFmt("-", "{:-^1}", .{""});
1830}1803}
18311804
1832test "decimal float padding" {1805test "decimal float padding" {
src-self-hosted/translate_c.zig+1-1
...@@ -2032,7 +2032,7 @@ fn escapeChar(c: u8, char_buf: *[4]u8) []const u8 {...@@ -2032,7 +2032,7 @@ fn escapeChar(c: u8, char_buf: *[4]u8) []const u8 {
2032 // Handle the remaining escapes Zig doesn't support by turning them2032 // Handle the remaining escapes Zig doesn't support by turning them
2033 // into their respective hex representation2033 // into their respective hex representation
2034 else => if (std.ascii.isCntrl(c))2034 else => if (std.ascii.isCntrl(c))
2035 std.fmt.bufPrint(char_buf, "\\x{x:0<2}", .{c}) catch unreachable2035 std.fmt.bufPrint(char_buf, "\\x{x:0>2}", .{c}) catch unreachable
2036 else2036 else
2037 std.fmt.bufPrint(char_buf, "{c}", .{c}) catch unreachable,2037 std.fmt.bufPrint(char_buf, "{c}", .{c}) catch unreachable,
2038 };2038 };