authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2018-05-16 18:22:39-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2018-05-16 18:22:39-04:00
log4a3d689550286fbf7859321991c8f7b7e6d87207
treeece3cde10dc2f53a51de557156e32c03ed9e392f
parentee5f9ffad02b3cf263c13ca58c4d2e4526e29a84

std.fmt: use SI prefixes for printing bytes

closes #1015

1 files changed, 58 insertions(+), 29 deletions(-)

std/fmt/index.zig+58-29
...@@ -28,6 +28,7 @@ pub fn format(context: var, comptime Errors: type, output: fn(@typeOf(context),...@@ -28,6 +28,7 @@ pub fn format(context: var, comptime Errors: type, output: fn(@typeOf(context),
28 Buf,28 Buf,
29 BufWidth,29 BufWidth,
30 Bytes,30 Bytes,
31 BytesBase,
31 BytesWidth,32 BytesWidth,
32 };33 };
3334
...@@ -99,6 +100,7 @@ pub fn format(context: var, comptime Errors: type, output: fn(@typeOf(context),...@@ -99,6 +100,7 @@ pub fn format(context: var, comptime Errors: type, output: fn(@typeOf(context),
99 },100 },
100 'B' => {101 'B' => {
101 width = 0;102 width = 0;
103 radix = 1000;
102 state = State.Bytes;104 state = State.Bytes;
103 },105 },
104 else => @compileError("Unknown format character: " ++ []u8{c}),106 else => @compileError("Unknown format character: " ++ []u8{c}),
...@@ -214,7 +216,24 @@ pub fn format(context: var, comptime Errors: type, output: fn(@typeOf(context),...@@ -214,7 +216,24 @@ pub fn format(context: var, comptime Errors: type, output: fn(@typeOf(context),
214 },216 },
215 State.Bytes => switch (c) {217 State.Bytes => switch (c) {
216 '}' => {218 '}' => {
217 try formatBytes(args[next_arg], 0, context, Errors, output);219 try formatBytes(args[next_arg], 0, radix, context, Errors, output);
220 next_arg += 1;
221 state = State.Start;
222 start_index = i + 1;
223 },
224 'i' => {
225 radix = 1024;
226 state = State.BytesBase;
227 },
228 '0' ... '9' => {
229 width_start = i;
230 state = State.BytesWidth;
231 },
232 else => @compileError("Unexpected character in format string: " ++ []u8{c}),
233 },
234 State.BytesBase => switch (c) {
235 '}' => {
236 try formatBytes(args[next_arg], 0, radix, context, Errors, output);
218 next_arg += 1;237 next_arg += 1;
219 state = State.Start;238 state = State.Start;
220 start_index = i + 1;239 start_index = i + 1;
...@@ -228,7 +247,7 @@ pub fn format(context: var, comptime Errors: type, output: fn(@typeOf(context),...@@ -228,7 +247,7 @@ pub fn format(context: var, comptime Errors: type, output: fn(@typeOf(context),
228 State.BytesWidth => switch (c) {247 State.BytesWidth => switch (c) {
229 '}' => {248 '}' => {
230 width = comptime (parseUnsigned(usize, fmt[width_start..i], 10) catch unreachable);249 width = comptime (parseUnsigned(usize, fmt[width_start..i], 10) catch unreachable);
231 try formatBytes(args[next_arg], width, context, Errors, output);250 try formatBytes(args[next_arg], width, radix, context, Errors, output);
232 next_arg += 1;251 next_arg += 1;
233 state = State.Start;252 state = State.Start;
234 start_index = i + 1;253 start_index = i + 1;
...@@ -550,7 +569,7 @@ pub fn formatFloatDecimal(value: var, maybe_precision: ?usize, context: var, com...@@ -550,7 +569,7 @@ pub fn formatFloatDecimal(value: var, maybe_precision: ?usize, context: var, com
550 }569 }
551}570}
552571
553pub fn formatBytes(value: var, width: ?usize,572pub fn formatBytes(value: var, width: ?usize, comptime radix: usize,
554 context: var, comptime Errors: type, output: fn(@typeOf(context), []const u8)Errors!void) Errors!void573 context: var, comptime Errors: type, output: fn(@typeOf(context), []const u8)Errors!void) Errors!void
555{574{
556 if (value == 0) {575 if (value == 0) {
...@@ -558,16 +577,26 @@ pub fn formatBytes(value: var, width: ?usize,...@@ -558,16 +577,26 @@ pub fn formatBytes(value: var, width: ?usize,
558 }577 }
559578
560 const mags = " KMGTPEZY";579 const mags = " KMGTPEZY";
561 const magnitude = math.min(math.log2(value) / 10, mags.len - 1);580 const magnitude = switch (radix) {
562 const new_value = f64(value) / math.pow(f64, 1024, f64(magnitude));581 1000 => math.min(math.log2(value) / comptime math.log2(1000), mags.len - 1),
582 1024 => math.min(math.log2(value) / 10, mags.len - 1),
583 else => unreachable,
584 };
585 const new_value = f64(value) / math.pow(f64, f64(radix), f64(magnitude));
563 const suffix = mags[magnitude];586 const suffix = mags[magnitude];
564587
565 try formatFloatDecimal(new_value, width, context, Errors, output);588 try formatFloatDecimal(new_value, width, context, Errors, output);
566589
567 if (suffix != ' ') {590 if (suffix == ' ') {
568 try output(context, (&suffix)[0..1]);591 return output(context, "B");
569 }592 }
570 return output(context, "B");593
594 const buf = switch (radix) {
595 1000 => []u8 { suffix, 'B' },
596 1024 => []u8 { suffix, 'i', 'B' },
597 else => unreachable,
598 };
599 return output(context, buf);
571}600}
572601
573pub fn formatInt(value: var, base: u8, uppercase: bool, width: usize,602pub fn formatInt(value: var, base: u8, uppercase: bool, width: usize,
...@@ -787,41 +816,27 @@ test "parse unsigned comptime" {...@@ -787,41 +816,27 @@ test "parse unsigned comptime" {
787816
788test "fmt.format" {817test "fmt.format" {
789 {818 {
790 var buf1: [32]u8 = undefined;
791 const value: ?i32 = 1234;819 const value: ?i32 = 1234;
792 const result = try bufPrint(buf1[0..], "nullable: {}\n", value);820 try testFmt("nullable: 1234\n", "nullable: {}\n", value);
793 assert(mem.eql(u8, result, "nullable: 1234\n"));
794 }821 }
795 {822 {
796 var buf1: [32]u8 = undefined;
797 const value: ?i32 = null;823 const value: ?i32 = null;
798 const result = try bufPrint(buf1[0..], "nullable: {}\n", value);824 try testFmt("nullable: null\n", "nullable: {}\n", value);
799 assert(mem.eql(u8, result, "nullable: null\n"));
800 }825 }
801 {826 {
802 var buf1: [32]u8 = undefined;
803 const value: error!i32 = 1234;827 const value: error!i32 = 1234;
804 const result = try bufPrint(buf1[0..], "error union: {}\n", value);828 try testFmt("error union: 1234\n", "error union: {}\n", value);
805 assert(mem.eql(u8, result, "error union: 1234\n"));
806 }829 }
807 {830 {
808 var buf1: [32]u8 = undefined;
809 const value: error!i32 = error.InvalidChar;831 const value: error!i32 = error.InvalidChar;
810 const result = try bufPrint(buf1[0..], "error union: {}\n", value);832 try testFmt("error union: error.InvalidChar\n", "error union: {}\n", value);
811 assert(mem.eql(u8, result, "error union: error.InvalidChar\n"));
812 }833 }
813 {834 {
814 var buf1: [32]u8 = undefined;
815 const value: u3 = 0b101;835 const value: u3 = 0b101;
816 const result = try bufPrint(buf1[0..], "u3: {}\n", value);836 try testFmt("u3: 5\n", "u3: {}\n", value);
817 assert(mem.eql(u8, result, "u3: 5\n"));
818 }
819 {
820 var buf1: [32]u8 = undefined;
821 const value: usize = 63 * 1024 * 1024;
822 const result = try bufPrint(buf1[0..], "file size: {B}\n", value);
823 assert(mem.eql(u8, result, "file size: 63MB\n"));
824 }837 }
838 try testFmt("file size: 63MiB\n", "file size: {Bi}\n", usize(63 * 1024 * 1024));
839 try testFmt("file size: 66.06MB\n", "file size: {B2}\n", usize(63 * 1024 * 1024));
825 {840 {
826 // Dummy field because of https://github.com/zig-lang/zig/issues/557.841 // Dummy field because of https://github.com/zig-lang/zig/issues/557.
827 const Struct = struct {842 const Struct = struct {
...@@ -1041,6 +1056,20 @@ test "fmt.format" {...@@ -1041,6 +1056,20 @@ test "fmt.format" {
1041 }1056 }
1042}1057}
10431058
1059fn testFmt(expected: []const u8, comptime template: []const u8, args: ...) !void {
1060 var buf: [100]u8 = undefined;
1061 const result = try bufPrint(buf[0..], template, args);
1062 if (mem.eql(u8, result, expected))
1063 return;
1064
1065 std.debug.warn("\n====== expected this output: =========\n");
1066 std.debug.warn("{}", expected);
1067 std.debug.warn("\n======== instead found this: =========\n");
1068 std.debug.warn("{}", result);
1069 std.debug.warn("\n======================================\n");
1070 return error.TestFailed;
1071}
1072
1044pub fn trim(buf: []const u8) []const u8 {1073pub fn trim(buf: []const u8) []const u8 {
1045 var start: usize = 0;1074 var start: usize = 0;
1046 while (start < buf.len and isWhiteSpace(buf[start])) : (start += 1) { }1075 while (start < buf.len and isWhiteSpace(buf[start])) : (start += 1) { }