Commit 51a9a6aab6
Changed files (3)
lib
std
lib/std/io/Writer.zig
@@ -744,11 +744,8 @@ pub fn printAddress(w: *Writer, value: anytype) Error!void {
switch (@typeInfo(T)) {
.pointer => |info| {
try w.writeAll(@typeName(info.child) ++ "@");
- if (info.size == .slice)
- try w.printInt(@intFromPtr(value.ptr), 16, .lower, .{})
- else
- try w.printInt(@intFromPtr(value), 16, .lower, .{});
- return;
+ const int = if (info.size == .slice) @intFromPtr(value.ptr) else @intFromPtr(value);
+ return w.printInt(int, 16, .lower, .{});
},
.optional => |info| {
if (@typeInfo(info.child) == .pointer) {
@@ -777,9 +774,9 @@ pub fn printValue(
'*' => return w.printAddress(value),
'f' => return value.format(w),
'd' => switch (@typeInfo(T)) {
- .float, .comptime_float => return printFloat(w, value, .decimal, options),
+ .float, .comptime_float => return printFloat(w, value, options.toNumber(.decimal, .lower)),
.int, .comptime_int => return printInt(w, value, 10, .lower, options),
- .@"struct" => return value.formatInteger(w, 10, .lower),
+ .@"struct" => return value.formatNumber(w, options.toNumber(.decimal, .lower)),
.@"enum" => return printInt(w, @intFromEnum(value), 10, .lower, options),
.vector => return printVector(w, fmt, options, value, max_depth),
else => invalidFmtError(fmt, value),
@@ -789,22 +786,22 @@ pub fn printValue(
'b' => switch (@typeInfo(T)) {
.int, .comptime_int => return printInt(w, value, 2, .lower, options),
.@"enum" => return printInt(w, @intFromEnum(value), 2, .lower, options),
- .@"struct" => return value.formatInteger(w, 2, .lower),
+ .@"struct" => return value.formatNumber(w, options.toNumber(.binary, .lower)),
.vector => return printVector(w, fmt, options, value, max_depth),
else => invalidFmtError(fmt, value),
},
'o' => switch (@typeInfo(T)) {
.int, .comptime_int => return printInt(w, value, 8, .lower, options),
.@"enum" => return printInt(w, @intFromEnum(value), 8, .lower, options),
- .@"struct" => return value.formatInteger(w, 8, .lower),
+ .@"struct" => return value.formatNumber(w, options.toNumber(.octal, .lower)),
.vector => return printVector(w, fmt, options, value, max_depth),
else => invalidFmtError(fmt, value),
},
'x' => switch (@typeInfo(T)) {
- .float, .comptime_float => return printFloatHexOptions(w, value, .lower, options),
+ .float, .comptime_float => return printFloatHexOptions(w, value, options.toNumber(.hex, .lower)),
.int, .comptime_int => return printInt(w, value, 16, .lower, options),
.@"enum" => return printInt(w, @intFromEnum(value), 16, .lower, options),
- .@"struct" => return value.formatInteger(w, 16, .lower),
+ .@"struct" => return value.formatNumber(w, options.toNumber(.hex, .lower)),
.pointer => |info| switch (info.size) {
.one, .slice => {
const slice: []const u8 = value;
@@ -823,10 +820,10 @@ pub fn printValue(
else => invalidFmtError(fmt, value),
},
'X' => switch (@typeInfo(T)) {
- .float, .comptime_float => return printFloatHexOptions(w, value, .lower, options),
+ .float, .comptime_float => return printFloatHexOptions(w, value, options.toNumber(.hex, .lower)),
.int, .comptime_int => return printInt(w, value, 16, .upper, options),
.@"enum" => return printInt(w, @intFromEnum(value), 16, .upper, options),
- .@"struct" => return value.formatInteger(w, 16, .upper),
+ .@"struct" => return value.formatNumber(w, options.toNumber(.hex, .upper)),
.pointer => |info| switch (info.size) {
.one, .slice => {
const slice: []const u8 = value;
@@ -872,8 +869,13 @@ pub fn printValue(
else => invalidFmtError(fmt, value),
},
'e' => switch (@typeInfo(T)) {
- .float, .comptime_float => return printFloat(w, value, .scientific, options),
- .@"struct" => return value.formatFloat(w, .scientific),
+ .float, .comptime_float => return printFloat(w, value, options.toNumber(.scientific, .lower)),
+ .@"struct" => return value.formatNumber(w, options.toNumber(.scientific, .lower)),
+ else => invalidFmtError(fmt, value),
+ },
+ 'E' => switch (@typeInfo(T)) {
+ .float, .comptime_float => return printFloat(w, value, options.toNumber(.scientific, .upper)),
+ .@"struct" => return value.formatNumber(w, options.toNumber(.scientific, .upper)),
else => invalidFmtError(fmt, value),
},
't' => switch (@typeInfo(T)) {
@@ -923,7 +925,7 @@ pub fn printValue(
switch (@typeInfo(T)) {
.float, .comptime_float => {
if (!is_any and fmt.len != 0) invalidFmtError(fmt, value);
- return printFloat(w, value, .decimal, options);
+ return printFloat(w, value, options.toNumber(.decimal, .lower));
},
.int, .comptime_int => {
if (!is_any and fmt.len != 0) invalidFmtError(fmt, value);
@@ -1262,12 +1264,13 @@ pub fn printUnicodeCodepoint(w: *Writer, c: u21) Error!void {
return w.writeAll(buf[0..len]);
}
-pub fn printFloat(
- w: *Writer,
- value: anytype,
- mode: std.fmt.float.Mode,
- options: std.fmt.Options,
-) Error!void {
+/// Uses a larger stack buffer; asserts mode is decimal or scientific.
+pub fn printFloat(w: *Writer, value: anytype, options: std.fmt.Number) Error!void {
+ const mode: std.fmt.float.Mode = switch (options.mode) {
+ .decimal => .decimal,
+ .scientific => .scientific,
+ .binary, .octal, .hex => unreachable,
+ };
var buf: [std.fmt.float.bufferSize(.decimal, f64)]u8 = undefined;
const s = std.fmt.float.render(&buf, value, .{
.mode = mode,
@@ -1275,20 +1278,36 @@ pub fn printFloat(
}) catch |err| switch (err) {
error.BufferTooSmall => "(float)",
};
- return w.alignBufferOptions(s, options);
+ return w.alignBuffer(s, options.width orelse s.len, options.alignment, options.fill);
}
-pub fn printFloatHexOptions(w: *Writer, value: anytype, case: std.fmt.Case, options: std.fmt.Options) Error!void {
+/// Uses a smaller stack buffer; asserts mode is not decimal or scientific.
+pub fn printFloatHexOptions(w: *Writer, value: anytype, options: std.fmt.Number) Error!void {
var buf: [50]u8 = undefined; // for aligning
var sub_writer: Writer = .fixed(&buf);
- printFloatHex(&sub_writer, value, case, options.precision) catch unreachable; // buf is large enough
- return w.alignBufferOptions(sub_writer.buffered(), options);
+ switch (options.mode) {
+ .decimal => unreachable,
+ .scientific => unreachable,
+ .binary => @panic("TODO"),
+ .octal => @panic("TODO"),
+ .hex => {},
+ }
+ printFloatHex(&sub_writer, value, options.case, options.precision) catch unreachable; // buf is large enough
+
+ const printed = sub_writer.buffered();
+ return w.alignBuffer(printed, options.width orelse printed.len, options.alignment, options.fill);
}
pub fn printFloatHex(w: *Writer, value: anytype, case: std.fmt.Case, opt_precision: ?usize) Error!void {
if (std.math.signbit(value)) try w.writeByte('-');
- if (std.math.isNan(value)) return w.writeAll("nan");
- if (std.math.isInf(value)) return w.writeAll("inf");
+ if (std.math.isNan(value)) return w.writeAll(switch (case) {
+ .lower => "nan",
+ .upper => "NAN",
+ });
+ if (std.math.isInf(value)) return w.writeAll(switch (case) {
+ .lower => "inf",
+ .upper => "INF",
+ });
const T = @TypeOf(value);
const TU = std.meta.Int(.unsigned, @bitSizeOf(T));
@@ -1822,7 +1841,7 @@ test printInt {
test "printFloat with comptime_float" {
var buf: [20]u8 = undefined;
var w: Writer = .fixed(&buf);
- try w.printFloat(@as(comptime_float, 1.0), .scientific, .{});
+ try w.printFloat(@as(comptime_float, 1.0), std.fmt.Options.toNumber(.{}, .scientific, .lower));
try std.testing.expectEqualStrings(w.buffered(), "1e0");
try std.testing.expectFmt("1", "{}", .{1.0});
}
lib/std/math/big/int.zig
@@ -2030,11 +2030,11 @@ pub const Mutable = struct {
}
pub fn format(self: Mutable, w: *std.io.Writer) std.io.Writer.Error!void {
- return formatInteger(self, w, 10, .lower);
+ return formatNumber(self, w, .{});
}
- pub fn formatInteger(self: Const, w: *std.io.Writer, base: u8, case: std.fmt.Case) std.io.Writer.Error!void {
- return self.toConst().formatInteger(w, base, case);
+ pub fn formatNumber(self: Const, w: *std.io.Writer, n: std.fmt.Number) std.io.Writer.Error!void {
+ return self.toConst().formatNumber(w, n);
}
};
@@ -2329,7 +2329,7 @@ pub const Const = struct {
/// this function will fail to print the string, printing "(BigInt)" instead of a number.
/// This is because the rendering algorithm requires reversing a string, which requires O(N) memory.
/// See `toString` and `toStringAlloc` for a way to print big integers without failure.
- pub fn formatInteger(self: Const, w: *std.io.Writer, base: u8, case: std.fmt.Case) std.io.Writer.Error!void {
+ pub fn formatNumber(self: Const, w: *std.io.Writer, number: std.fmt.Number) std.io.Writer.Error!void {
const available_len = 64;
if (self.limbs.len > available_len)
return w.writeAll("(BigInt)");
@@ -2341,7 +2341,8 @@ pub const Const = struct {
.positive = false,
};
var buf: [biggest.sizeInBaseUpperBound(2)]u8 = undefined;
- const len = self.toString(&buf, base, case, &limbs);
+ const base: u8 = number.mode.base() orelse @panic("TODO print big int in scientific form");
+ const len = self.toString(&buf, base, number.case, &limbs);
return w.writeAll(buf[0..len]);
}
@@ -2913,15 +2914,15 @@ pub const Managed = struct {
/// To allow `std.fmt.format` to work with `Managed`.
pub fn format(self: Managed, w: *std.io.Writer) std.io.Writer.Error!void {
- return formatInteger(self, w, 10, .lower);
+ return formatNumber(self, w, .{});
}
/// If the absolute value of integer is greater than or equal to `pow(2, 64 * @sizeOf(usize) * 8)`,
/// this function will fail to print the string, printing "(BigInt)" instead of a number.
/// This is because the rendering algorithm requires reversing a string, which requires O(N) memory.
/// See `toString` and `toStringAlloc` for a way to print big integers without failure.
- pub fn formatInteger(self: Managed, w: *std.io.Writer, base: u8, case: std.fmt.Case) std.io.Writer.Error!void {
- return self.toConst().formatInteger(w, base, case);
+ pub fn formatNumber(self: Managed, w: *std.io.Writer, n: std.fmt.Number) std.io.Writer.Error!void {
+ return self.toConst().formatNumber(w, n);
}
/// Returns math.Order.lt, math.Order.eq, math.Order.gt if |a| < |b|, |a| ==
lib/std/fmt.zig
@@ -37,6 +37,45 @@ pub const Options = struct {
width: ?usize = null,
alignment: Alignment = default_alignment,
fill: u8 = default_fill_char,
+
+ pub fn toNumber(o: Options, mode: Number.Mode, case: Case) Number {
+ return .{
+ .mode = mode,
+ .case = case,
+ .precision = o.precision,
+ .width = o.width,
+ .alignment = o.alignment,
+ .fill = o.fill,
+ };
+ }
+};
+
+pub const Number = struct {
+ mode: Mode = .decimal,
+ /// Affects hex digits as well as floating point "inf"/"INF".
+ case: Case = .lower,
+ precision: ?usize = null,
+ width: ?usize = null,
+ alignment: Alignment = default_alignment,
+ fill: u8 = default_fill_char,
+
+ pub const Mode = enum {
+ decimal,
+ binary,
+ octal,
+ hex,
+ scientific,
+
+ pub fn base(mode: Mode) ?u8 {
+ return switch (mode) {
+ .decimal => 10,
+ .binary => 2,
+ .octal => 8,
+ .hex => 16,
+ .scientific => null,
+ };
+ }
+ };
};
/// Renders fmt string with args, calling `writer` with slices of bytes.