authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-07-09 14:54:54-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-07-09 14:54:54-07:00
log51a9a6aab696b9fbd69dadb5a569cfe184fabecc
tree737829297856590eda0d1f93141d7fb4e971f2ae
parent5bc95a6fa2af86689c37a87a5899e7e34d6084ee

std: replace formatInteger with formatNumber


3 files changed, 96 insertions(+), 37 deletions(-)

lib/std/fmt.zig+39
......@@ -37,6 +37,45 @@ pub const Options = struct {
3737 width: ?usize = null,
3838 alignment: Alignment = default_alignment,
3939 fill: u8 = default_fill_char,
40
41 pub fn toNumber(o: Options, mode: Number.Mode, case: Case) Number {
42 return .{
43 .mode = mode,
44 .case = case,
45 .precision = o.precision,
46 .width = o.width,
47 .alignment = o.alignment,
48 .fill = o.fill,
49 };
50 }
51};
52
53pub const Number = struct {
54 mode: Mode = .decimal,
55 /// Affects hex digits as well as floating point "inf"/"INF".
56 case: Case = .lower,
57 precision: ?usize = null,
58 width: ?usize = null,
59 alignment: Alignment = default_alignment,
60 fill: u8 = default_fill_char,
61
62 pub const Mode = enum {
63 decimal,
64 binary,
65 octal,
66 hex,
67 scientific,
68
69 pub fn base(mode: Mode) ?u8 {
70 return switch (mode) {
71 .decimal => 10,
72 .binary => 2,
73 .octal => 8,
74 .hex => 16,
75 .scientific => null,
76 };
77 }
78 };
4079};
4180
4281/// Renders fmt string with args, calling `writer` with slices of bytes.
lib/std/io/Writer.zig+48-29
......@@ -744,11 +744,8 @@ pub fn printAddress(w: *Writer, value: anytype) Error!void {
744744 switch (@typeInfo(T)) {
745745 .pointer => |info| {
746746 try w.writeAll(@typeName(info.child) ++ "@");
747 if (info.size == .slice)
748 try w.printInt(@intFromPtr(value.ptr), 16, .lower, .{})
749 else
750 try w.printInt(@intFromPtr(value), 16, .lower, .{});
751 return;
747 const int = if (info.size == .slice) @intFromPtr(value.ptr) else @intFromPtr(value);
748 return w.printInt(int, 16, .lower, .{});
752749 },
753750 .optional => |info| {
754751 if (@typeInfo(info.child) == .pointer) {
......@@ -777,9 +774,9 @@ pub fn printValue(
777774 '*' => return w.printAddress(value),
778775 'f' => return value.format(w),
779776 'd' => switch (@typeInfo(T)) {
780 .float, .comptime_float => return printFloat(w, value, .decimal, options),
777 .float, .comptime_float => return printFloat(w, value, options.toNumber(.decimal, .lower)),
781778 .int, .comptime_int => return printInt(w, value, 10, .lower, options),
782 .@"struct" => return value.formatInteger(w, 10, .lower),
779 .@"struct" => return value.formatNumber(w, options.toNumber(.decimal, .lower)),
783780 .@"enum" => return printInt(w, @intFromEnum(value), 10, .lower, options),
784781 .vector => return printVector(w, fmt, options, value, max_depth),
785782 else => invalidFmtError(fmt, value),
......@@ -789,22 +786,22 @@ pub fn printValue(
789786 'b' => switch (@typeInfo(T)) {
790787 .int, .comptime_int => return printInt(w, value, 2, .lower, options),
791788 .@"enum" => return printInt(w, @intFromEnum(value), 2, .lower, options),
792 .@"struct" => return value.formatInteger(w, 2, .lower),
789 .@"struct" => return value.formatNumber(w, options.toNumber(.binary, .lower)),
793790 .vector => return printVector(w, fmt, options, value, max_depth),
794791 else => invalidFmtError(fmt, value),
795792 },
796793 'o' => switch (@typeInfo(T)) {
797794 .int, .comptime_int => return printInt(w, value, 8, .lower, options),
798795 .@"enum" => return printInt(w, @intFromEnum(value), 8, .lower, options),
799 .@"struct" => return value.formatInteger(w, 8, .lower),
796 .@"struct" => return value.formatNumber(w, options.toNumber(.octal, .lower)),
800797 .vector => return printVector(w, fmt, options, value, max_depth),
801798 else => invalidFmtError(fmt, value),
802799 },
803800 'x' => switch (@typeInfo(T)) {
804 .float, .comptime_float => return printFloatHexOptions(w, value, .lower, options),
801 .float, .comptime_float => return printFloatHexOptions(w, value, options.toNumber(.hex, .lower)),
805802 .int, .comptime_int => return printInt(w, value, 16, .lower, options),
806803 .@"enum" => return printInt(w, @intFromEnum(value), 16, .lower, options),
807 .@"struct" => return value.formatInteger(w, 16, .lower),
804 .@"struct" => return value.formatNumber(w, options.toNumber(.hex, .lower)),
808805 .pointer => |info| switch (info.size) {
809806 .one, .slice => {
810807 const slice: []const u8 = value;
......@@ -823,10 +820,10 @@ pub fn printValue(
823820 else => invalidFmtError(fmt, value),
824821 },
825822 'X' => switch (@typeInfo(T)) {
826 .float, .comptime_float => return printFloatHexOptions(w, value, .lower, options),
823 .float, .comptime_float => return printFloatHexOptions(w, value, options.toNumber(.hex, .lower)),
827824 .int, .comptime_int => return printInt(w, value, 16, .upper, options),
828825 .@"enum" => return printInt(w, @intFromEnum(value), 16, .upper, options),
829 .@"struct" => return value.formatInteger(w, 16, .upper),
826 .@"struct" => return value.formatNumber(w, options.toNumber(.hex, .upper)),
830827 .pointer => |info| switch (info.size) {
831828 .one, .slice => {
832829 const slice: []const u8 = value;
......@@ -872,8 +869,13 @@ pub fn printValue(
872869 else => invalidFmtError(fmt, value),
873870 },
874871 'e' => switch (@typeInfo(T)) {
875 .float, .comptime_float => return printFloat(w, value, .scientific, options),
876 .@"struct" => return value.formatFloat(w, .scientific),
872 .float, .comptime_float => return printFloat(w, value, options.toNumber(.scientific, .lower)),
873 .@"struct" => return value.formatNumber(w, options.toNumber(.scientific, .lower)),
874 else => invalidFmtError(fmt, value),
875 },
876 'E' => switch (@typeInfo(T)) {
877 .float, .comptime_float => return printFloat(w, value, options.toNumber(.scientific, .upper)),
878 .@"struct" => return value.formatNumber(w, options.toNumber(.scientific, .upper)),
877879 else => invalidFmtError(fmt, value),
878880 },
879881 't' => switch (@typeInfo(T)) {
......@@ -923,7 +925,7 @@ pub fn printValue(
923925 switch (@typeInfo(T)) {
924926 .float, .comptime_float => {
925927 if (!is_any and fmt.len != 0) invalidFmtError(fmt, value);
926 return printFloat(w, value, .decimal, options);
928 return printFloat(w, value, options.toNumber(.decimal, .lower));
927929 },
928930 .int, .comptime_int => {
929931 if (!is_any and fmt.len != 0) invalidFmtError(fmt, value);
......@@ -1262,12 +1264,13 @@ pub fn printUnicodeCodepoint(w: *Writer, c: u21) Error!void {
12621264 return w.writeAll(buf[0..len]);
12631265}
12641266
1265pub fn printFloat(
1266 w: *Writer,
1267 value: anytype,
1268 mode: std.fmt.float.Mode,
1269 options: std.fmt.Options,
1270) Error!void {
1267/// Uses a larger stack buffer; asserts mode is decimal or scientific.
1268pub fn printFloat(w: *Writer, value: anytype, options: std.fmt.Number) Error!void {
1269 const mode: std.fmt.float.Mode = switch (options.mode) {
1270 .decimal => .decimal,
1271 .scientific => .scientific,
1272 .binary, .octal, .hex => unreachable,
1273 };
12711274 var buf: [std.fmt.float.bufferSize(.decimal, f64)]u8 = undefined;
12721275 const s = std.fmt.float.render(&buf, value, .{
12731276 .mode = mode,
......@@ -1275,20 +1278,36 @@ pub fn printFloat(
12751278 }) catch |err| switch (err) {
12761279 error.BufferTooSmall => "(float)",
12771280 };
1278 return w.alignBufferOptions(s, options);
1281 return w.alignBuffer(s, options.width orelse s.len, options.alignment, options.fill);
12791282}
12801283
1281pub fn printFloatHexOptions(w: *Writer, value: anytype, case: std.fmt.Case, options: std.fmt.Options) Error!void {
1284/// Uses a smaller stack buffer; asserts mode is not decimal or scientific.
1285pub fn printFloatHexOptions(w: *Writer, value: anytype, options: std.fmt.Number) Error!void {
12821286 var buf: [50]u8 = undefined; // for aligning
12831287 var sub_writer: Writer = .fixed(&buf);
1284 printFloatHex(&sub_writer, value, case, options.precision) catch unreachable; // buf is large enough
1285 return w.alignBufferOptions(sub_writer.buffered(), options);
1288 switch (options.mode) {
1289 .decimal => unreachable,
1290 .scientific => unreachable,
1291 .binary => @panic("TODO"),
1292 .octal => @panic("TODO"),
1293 .hex => {},
1294 }
1295 printFloatHex(&sub_writer, value, options.case, options.precision) catch unreachable; // buf is large enough
1296
1297 const printed = sub_writer.buffered();
1298 return w.alignBuffer(printed, options.width orelse printed.len, options.alignment, options.fill);
12861299}
12871300
12881301pub fn printFloatHex(w: *Writer, value: anytype, case: std.fmt.Case, opt_precision: ?usize) Error!void {
12891302 if (std.math.signbit(value)) try w.writeByte('-');
1290 if (std.math.isNan(value)) return w.writeAll("nan");
1291 if (std.math.isInf(value)) return w.writeAll("inf");
1303 if (std.math.isNan(value)) return w.writeAll(switch (case) {
1304 .lower => "nan",
1305 .upper => "NAN",
1306 });
1307 if (std.math.isInf(value)) return w.writeAll(switch (case) {
1308 .lower => "inf",
1309 .upper => "INF",
1310 });
12921311
12931312 const T = @TypeOf(value);
12941313 const TU = std.meta.Int(.unsigned, @bitSizeOf(T));
......@@ -1822,7 +1841,7 @@ test printInt {
18221841test "printFloat with comptime_float" {
18231842 var buf: [20]u8 = undefined;
18241843 var w: Writer = .fixed(&buf);
1825 try w.printFloat(@as(comptime_float, 1.0), .scientific, .{});
1844 try w.printFloat(@as(comptime_float, 1.0), std.fmt.Options.toNumber(.{}, .scientific, .lower));
18261845 try std.testing.expectEqualStrings(w.buffered(), "1e0");
18271846 try std.testing.expectFmt("1", "{}", .{1.0});
18281847}
lib/std/math/big/int.zig+9-8
......@@ -2030,11 +2030,11 @@ pub const Mutable = struct {
20302030 }
20312031
20322032 pub fn format(self: Mutable, w: *std.io.Writer) std.io.Writer.Error!void {
2033 return formatInteger(self, w, 10, .lower);
2033 return formatNumber(self, w, .{});
20342034 }
20352035
2036 pub fn formatInteger(self: Const, w: *std.io.Writer, base: u8, case: std.fmt.Case) std.io.Writer.Error!void {
2037 return self.toConst().formatInteger(w, base, case);
2036 pub fn formatNumber(self: Const, w: *std.io.Writer, n: std.fmt.Number) std.io.Writer.Error!void {
2037 return self.toConst().formatNumber(w, n);
20382038 }
20392039};
20402040
......@@ -2329,7 +2329,7 @@ pub const Const = struct {
23292329 /// this function will fail to print the string, printing "(BigInt)" instead of a number.
23302330 /// This is because the rendering algorithm requires reversing a string, which requires O(N) memory.
23312331 /// See `toString` and `toStringAlloc` for a way to print big integers without failure.
2332 pub fn formatInteger(self: Const, w: *std.io.Writer, base: u8, case: std.fmt.Case) std.io.Writer.Error!void {
2332 pub fn formatNumber(self: Const, w: *std.io.Writer, number: std.fmt.Number) std.io.Writer.Error!void {
23332333 const available_len = 64;
23342334 if (self.limbs.len > available_len)
23352335 return w.writeAll("(BigInt)");
......@@ -2341,7 +2341,8 @@ pub const Const = struct {
23412341 .positive = false,
23422342 };
23432343 var buf: [biggest.sizeInBaseUpperBound(2)]u8 = undefined;
2344 const len = self.toString(&buf, base, case, &limbs);
2344 const base: u8 = number.mode.base() orelse @panic("TODO print big int in scientific form");
2345 const len = self.toString(&buf, base, number.case, &limbs);
23452346 return w.writeAll(buf[0..len]);
23462347 }
23472348
......@@ -2913,15 +2914,15 @@ pub const Managed = struct {
29132914
29142915 /// To allow `std.fmt.format` to work with `Managed`.
29152916 pub fn format(self: Managed, w: *std.io.Writer) std.io.Writer.Error!void {
2916 return formatInteger(self, w, 10, .lower);
2917 return formatNumber(self, w, .{});
29172918 }
29182919
29192920 /// If the absolute value of integer is greater than or equal to `pow(2, 64 * @sizeOf(usize) * 8)`,
29202921 /// this function will fail to print the string, printing "(BigInt)" instead of a number.
29212922 /// This is because the rendering algorithm requires reversing a string, which requires O(N) memory.
29222923 /// See `toString` and `toStringAlloc` for a way to print big integers without failure.
2923 pub fn formatInteger(self: Managed, w: *std.io.Writer, base: u8, case: std.fmt.Case) std.io.Writer.Error!void {
2924 return self.toConst().formatInteger(w, base, case);
2924 pub fn formatNumber(self: Managed, w: *std.io.Writer, n: std.fmt.Number) std.io.Writer.Error!void {
2925 return self.toConst().formatNumber(w, n);
29252926 }
29262927
29272928 /// Returns math.Order.lt, math.Order.eq, math.Order.gt if |a| < |b|, |a| ==