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 {
2222pub const FormatOptions = struct {
2323 precision: ?usize = null,
2424 width: ?usize = null,
25 alignment: Alignment = .Left,
25 alignment: Alignment = .Right,
2626 fill: u8 = ' ',
2727};
2828
......@@ -327,7 +327,7 @@ pub fn formatType(
327327 max_depth: usize,
328328) @TypeOf(writer).Error!void {
329329 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))));
331331 try writer.writeAll("@");
332332 try formatInt(@ptrToInt(value), 16, false, FormatOptions{}, writer);
333333 return;
......@@ -631,26 +631,22 @@ pub fn formatBuf(
631631 writer: anytype,
632632) !void {
633633 const width = options.width orelse buf.len;
634 var padding = if (width > buf.len) (width - buf.len) else 0;
635 const pad_byte = [1]u8{options.fill};
634 const padding = if (width > buf.len) (width - buf.len) else 0;
635
636636 switch (options.alignment) {
637637 .Left => {
638638 try writer.writeAll(buf);
639 while (padding > 0) : (padding -= 1) {
640 try writer.writeAll(&pad_byte);
641 }
639 try writer.writeByteNTimes(options.fill, padding);
642640 },
643641 .Center => {
644 const padl = padding / 2;
645 var i: usize = 0;
646 while (i < padl) : (i += 1) try writer.writeAll(&pad_byte);
642 const left_padding = padding / 2;
643 const right_padding = (padding + 1) / 2;
644 try writer.writeByteNTimes(options.fill, left_padding);
647645 try writer.writeAll(buf);
648 while (i < padding) : (i += 1) try writer.writeAll(&pad_byte);
646 try writer.writeByteNTimes(options.fill, right_padding);
649647 },
650648 .Right => {
651 while (padding > 0) : (padding -= 1) {
652 try writer.writeAll(&pad_byte);
653 }
649 try writer.writeByteNTimes(options.fill, padding);
654650 try writer.writeAll(buf);
655651 },
656652 }
......@@ -941,61 +937,27 @@ pub fn formatInt(
941937 options: FormatOptions,
942938 writer: anytype,
943939) !void {
940 assert(base >= 2);
941
944942 const int_value = if (@TypeOf(value) == comptime_int) blk: {
945943 const Int = math.IntFittingRange(value, value);
946944 break :blk @as(Int, value);
947945 } else
948946 value;
949947
950 if (@typeInfo(@TypeOf(int_value)).Int.is_signed) {
951 return formatIntSigned(int_value, base, uppercase, options, writer);
952 } else {
953 return formatIntUnsigned(int_value, base, uppercase, options, writer);
954 }
955}
948 const value_info = @typeInfo(@TypeOf(int_value)).Int;
956949
957fn formatIntSigned(
958 value: anytype,
959 base: u8,
960 uppercase: bool,
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}
950 // The type must have the same size as `base` or be wider in order for the
951 // division to work
952 const min_int_bits = comptime math.max(value_info.bits, 8);
953 const MinInt = std.meta.Int(false, min_int_bits);
983954
984fn formatIntUnsigned(
985 value: anytype,
986 base: u8,
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;
955 const abs_value = math.absCast(int_value);
956 // The worst case in terms of space needed is base 2, plus 1 for the sign
957 var buf: [1 + math.max(value_info.bits, 1)]u8 = undefined;
998958
959 var a: MinInt = abs_value;
960 var index: usize = buf.len;
999961 while (true) {
1000962 const digit = a % base;
1001963 index -= 1;
......@@ -1004,25 +966,21 @@ fn formatIntUnsigned(
1004966 if (a == 0) break;
1005967 }
1006968
1007 const digits_buf = buf[index..];
1008 const width = options.width orelse 0;
1009 const padding = if (width > digits_buf.len) (width - digits_buf.len) else 0;
1010
1011 if (padding > index) {
1012 const zero_byte: u8 = options.fill;
1013 var leftover_padding = padding - index;
1014 while (true) {
1015 try writer.writeAll(@as(*const [1]u8, &zero_byte)[0..]);
1016 leftover_padding -= 1;
1017 if (leftover_padding == 0) break;
969 if (value_info.is_signed) {
970 if (value < 0) {
971 // Negative integer
972 index -= 1;
973 buf[index] = '-';
974 } else if (options.width == null or options.width.? == 0) {
975 // Positive integer, omit the plus sign
976 } else {
977 // Positive integer
978 index -= 1;
979 buf[index] = '+';
1018980 }
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);
1025981 }
982
983 return formatBuf(buf[index..], options, writer);
1026984}
1027985
1028986pub fn formatIntBuf(out_buf: []u8, value: anytype, base: u8, uppercase: bool, options: FormatOptions) usize {
......@@ -1246,6 +1204,10 @@ test "optional" {
12461204 const value: ?i32 = null;
12471205 try testFmt("optional: null\n", "optional: {}\n", .{value});
12481206 }
1207 {
1208 const value = @intToPtr(?*i32, 0xf000d000);
1209 try testFmt("optional: *i32@f000d000\n", "optional: {*}\n", .{value});
1210 }
12491211}
12501212
12511213test "error" {
......@@ -1283,7 +1245,17 @@ test "int.specifier" {
12831245
12841246test "int.padded" {
12851247 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)});
12871259}
12881260
12891261test "buffer" {
......@@ -1329,7 +1301,7 @@ test "slice" {
13291301 try testFmt("slice: []const u8@deadbeef\n", "slice: {}\n", .{value});
13301302 }
13311303
1332 try testFmt("buf: Test \n", "buf: {s:5}\n", .{"Test"});
1304 try testFmt("buf: Test\n", "buf: {s:5}\n", .{"Test"});
13331305 try testFmt("buf: Test\n Other text", "buf: {s}\n Other text", .{"Test"});
13341306}
13351307
......@@ -1362,7 +1334,7 @@ test "cstr" {
13621334 .{@ptrCast([*c]const u8, "Test C")},
13631335 );
13641336 try testFmt(
1365 "cstr: Test C \n",
1337 "cstr: Test C\n",
13661338 "cstr: {s:10}\n",
13671339 .{@ptrCast([*c]const u8, "Test C")},
13681340 );
......@@ -1805,7 +1777,7 @@ test "vector" {
18051777
18061778 try testFmt("{ true, false, true, false }", "{}", .{vbool});
18071779 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});
18091781 try testFmt("{ 1000, 2000, 3000, 4000 }", "{}", .{vu64});
18101782 try testFmt("{ 3e8, 7d0, bb8, fa0 }", "{x}", .{vu64});
18111783 try testFmt("{ 1kB, 2kB, 3kB, 4kB }", "{B}", .{vu64});
......@@ -1818,15 +1790,16 @@ test "enum-literal" {
18181790
18191791test "padding" {
18201792 try testFmt("Simple", "{}", .{"Simple"});
1821 try testFmt("true ", "{:10}", .{true});
1793 try testFmt(" true", "{:10}", .{true});
18221794 try testFmt(" true", "{:>10}", .{true});
18231795 try testFmt("======true", "{:=>10}", .{true});
18241796 try testFmt("true======", "{:=<10}", .{true});
18251797 try testFmt(" true ", "{:^10}", .{true});
18261798 try testFmt("===true===", "{:=^10}", .{true});
1827 try testFmt("Minimum width", "{:18} width", .{"Minimum"});
1799 try testFmt(" Minimum width", "{:18} width", .{"Minimum"});
18281800 try testFmt("==================Filled", "{:=>24}", .{"Filled"});
18291801 try testFmt(" Centered ", "{:^24}", .{"Centered"});
1802 try testFmt("-", "{:-^1}", .{""});
18301803}
18311804
18321805test "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 {
20322032 // Handle the remaining escapes Zig doesn't support by turning them
20332033 // into their respective hex representation
20342034 else => if (std.ascii.isCntrl(c))
2035 std.fmt.bufPrint(char_buf, "\\x{x:0<2}", .{c}) catch unreachable
2035 std.fmt.bufPrint(char_buf, "\\x{x:0>2}", .{c}) catch unreachable
20362036 else
20372037 std.fmt.bufPrint(char_buf, "{c}", .{c}) catch unreachable,
20382038 };