mirror of
https://codeberg.org/ziglang/zig.git
synced 2025-12-06 13:54:21 +00:00
std: Deprecate the B and Bi format specifiers
Following #8007 and #8137 let's get rid of the last weird format.
This commit is contained in:
parent
e47b754b28
commit
72664df491
4 changed files with 97 additions and 70 deletions
|
|
@ -73,7 +73,8 @@ fn render(
|
|||
if (vars.get(var_name)) |value| {
|
||||
const trimmed = mem.trim(u8, value, " \r\n");
|
||||
if (fmt == .html and mem.endsWith(u8, var_name, "BYTESIZE")) {
|
||||
try writer.print("{Bi:.1}", .{try std.fmt.parseInt(u64, trimmed, 10)});
|
||||
const size = try std.fmt.parseInt(u64, trimmed, 10);
|
||||
try writer.print("{:.1}", .{std.fmt.fmtIntSizeDec(size)});
|
||||
} else {
|
||||
try writer.writeAll(trimmed);
|
||||
}
|
||||
|
|
|
|||
128
lib/std/fmt.zig
128
lib/std/fmt.zig
|
|
@ -35,11 +35,11 @@ pub const FormatOptions = struct {
|
|||
///
|
||||
/// The format string must be comptime known and may contain placeholders following
|
||||
/// this format:
|
||||
/// `{[position][specifier]:[fill][alignment][width].[precision]}`
|
||||
/// `{[argument][specifier]:[fill][alignment][width].[precision]}`
|
||||
///
|
||||
/// Each word between `[` and `]` is a parameter you have to replace with something:
|
||||
///
|
||||
/// - *position* is the index of the argument that should be inserted
|
||||
/// - *argument* is either the index or the name of the argument that should be inserted
|
||||
/// - *specifier* is a type-dependent formatting option that determines how a type should formatted (see below)
|
||||
/// - *fill* is a single character which is used to pad the formatted text
|
||||
/// - *alignment* is one of the three characters `<`, `^` or `>`. they define if the text is *left*, *center*, or *right* aligned
|
||||
|
|
@ -52,16 +52,10 @@ pub const FormatOptions = struct {
|
|||
/// the digits after `:` is interpreted as *width*, not *fill*.
|
||||
///
|
||||
/// The *specifier* has several options for types:
|
||||
/// - `x` and `X`:
|
||||
/// - format the non-numeric value as a string of bytes in hexadecimal notation ("binary dump") in either lower case or upper case
|
||||
/// - output numeric value in hexadecimal notation
|
||||
/// - `x` and `X`: output numeric value in hexadecimal notation
|
||||
/// - `s`:
|
||||
/// - for pointer-to-many and C pointers of u8, print as a C-string using zero-termination
|
||||
/// - for slices of u8, print the entire slice as a string without zero-termination
|
||||
/// - `z`: escape the string with @"" syntax if it is not a valid Zig identifier.
|
||||
/// - `Z`: print the string escaping non-printable characters using Zig escape sequences.
|
||||
/// - `B` and `Bi`: output a memory size in either metric (1000) or power-of-two (1024) based notation. works for both float and integer values.
|
||||
/// - `e` and `E`: if printing a string, escape non-printable characters
|
||||
/// - `e`: output floating point value in scientific notation
|
||||
/// - `d`: output numeric value in decimal notation
|
||||
/// - `b`: output integer value in binary notation
|
||||
|
|
@ -620,9 +614,9 @@ fn formatValue(
|
|||
writer: anytype,
|
||||
) !void {
|
||||
if (comptime std.mem.eql(u8, fmt, "B")) {
|
||||
return formatBytes(value, options, 1000, writer);
|
||||
@compileError("specifier 'B' has been deprecated, wrap your argument in std.fmt.fmtIntSizeDec instead");
|
||||
} else if (comptime std.mem.eql(u8, fmt, "Bi")) {
|
||||
return formatBytes(value, options, 1024, writer);
|
||||
@compileError("specifier 'Bi' has been deprecated, wrap your argument in std.fmt.fmtIntSizeBin instead");
|
||||
}
|
||||
|
||||
const T = @TypeOf(value);
|
||||
|
|
@ -790,6 +784,67 @@ pub fn fmtSliceEscapeUpper(bytes: []const u8) std.fmt.Formatter(formatSliceEscap
|
|||
return .{ .data = bytes };
|
||||
}
|
||||
|
||||
fn formatSizeImpl(comptime radix: comptime_int) type {
|
||||
return struct {
|
||||
fn f(
|
||||
value: u64,
|
||||
comptime fmt: []const u8,
|
||||
options: FormatOptions,
|
||||
writer: anytype,
|
||||
) !void {
|
||||
if (value == 0) {
|
||||
return writer.writeAll("0B");
|
||||
}
|
||||
|
||||
const mags_si = " kMGTPEZY";
|
||||
const mags_iec = " KMGTPEZY";
|
||||
|
||||
const log2 = math.log2(value);
|
||||
const magnitude = switch (radix) {
|
||||
1000 => math.min(log2 / comptime math.log2(1000), mags_si.len - 1),
|
||||
1024 => math.min(log2 / 10, mags_iec.len - 1),
|
||||
else => unreachable,
|
||||
};
|
||||
const new_value = lossyCast(f64, value) / math.pow(f64, lossyCast(f64, radix), lossyCast(f64, magnitude));
|
||||
const suffix = switch (radix) {
|
||||
1000 => mags_si[magnitude],
|
||||
1024 => mags_iec[magnitude],
|
||||
else => unreachable,
|
||||
};
|
||||
|
||||
try formatFloatDecimal(new_value, options, writer);
|
||||
|
||||
if (suffix == ' ') {
|
||||
return writer.writeAll("B");
|
||||
}
|
||||
|
||||
const buf = switch (radix) {
|
||||
1000 => &[_]u8{ suffix, 'B' },
|
||||
1024 => &[_]u8{ suffix, 'i', 'B' },
|
||||
else => unreachable,
|
||||
};
|
||||
return writer.writeAll(buf);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
const formatSizeDec = formatSizeImpl(1000).f;
|
||||
const formatSizeBin = formatSizeImpl(1024).f;
|
||||
|
||||
/// Return a Formatter for a u64 value representing a file size.
|
||||
/// This formatter represents the number as multiple of 1000 and uses the SI
|
||||
/// measurement units (kB, MB, GB, ...).
|
||||
pub fn fmtIntSizeDec(value: u64) std.fmt.Formatter(formatSizeDec) {
|
||||
return .{ .data = value };
|
||||
}
|
||||
|
||||
/// Return a Formatter for a u64 value representing a file size.
|
||||
/// This formatter represents the number as multiple of 1024 and uses the IEC
|
||||
/// measurement units (KiB, MiB, GiB, ...).
|
||||
pub fn fmtIntSizeBin(value: u64) std.fmt.Formatter(formatSizeBin) {
|
||||
return .{ .data = value };
|
||||
}
|
||||
|
||||
pub fn formatText(
|
||||
bytes: []const u8,
|
||||
comptime fmt: []const u8,
|
||||
|
|
@ -1111,47 +1166,6 @@ pub fn formatFloatDecimal(
|
|||
}
|
||||
}
|
||||
|
||||
pub fn formatBytes(
|
||||
value: anytype,
|
||||
options: FormatOptions,
|
||||
comptime radix: usize,
|
||||
writer: anytype,
|
||||
) !void {
|
||||
if (value == 0) {
|
||||
return writer.writeAll("0B");
|
||||
}
|
||||
|
||||
const is_float = comptime std.meta.trait.is(.Float)(@TypeOf(value));
|
||||
const mags_si = " kMGTPEZY";
|
||||
const mags_iec = " KMGTPEZY";
|
||||
|
||||
const log2 = if (is_float) @floatToInt(usize, math.log2(value)) else math.log2(value);
|
||||
const magnitude = switch (radix) {
|
||||
1000 => math.min(log2 / comptime math.log2(1000), mags_si.len - 1),
|
||||
1024 => math.min(log2 / 10, mags_iec.len - 1),
|
||||
else => unreachable,
|
||||
};
|
||||
const new_value = lossyCast(f64, value) / math.pow(f64, lossyCast(f64, radix), lossyCast(f64, magnitude));
|
||||
const suffix = switch (radix) {
|
||||
1000 => mags_si[magnitude],
|
||||
1024 => mags_iec[magnitude],
|
||||
else => unreachable,
|
||||
};
|
||||
|
||||
try formatFloatDecimal(new_value, options, writer);
|
||||
|
||||
if (suffix == ' ') {
|
||||
return writer.writeAll("B");
|
||||
}
|
||||
|
||||
const buf = switch (radix) {
|
||||
1000 => &[_]u8{ suffix, 'B' },
|
||||
1024 => &[_]u8{ suffix, 'i', 'B' },
|
||||
else => unreachable,
|
||||
};
|
||||
return writer.writeAll(buf);
|
||||
}
|
||||
|
||||
pub fn formatInt(
|
||||
value: anytype,
|
||||
base: u8,
|
||||
|
|
@ -1806,8 +1820,12 @@ test "cstr" {
|
|||
}
|
||||
|
||||
test "filesize" {
|
||||
try expectFmt("file size: 63MiB\n", "file size: {Bi}\n", .{@as(usize, 63 * 1024 * 1024)});
|
||||
try expectFmt("file size: 66.06MB\n", "file size: {B:.2}\n", .{@as(usize, 63 * 1024 * 1024)});
|
||||
try expectFmt("file size: 42B\n", "file size: {}\n", .{fmtIntSizeDec(42)});
|
||||
try expectFmt("file size: 42B\n", "file size: {}\n", .{fmtIntSizeBin(42)});
|
||||
try expectFmt("file size: 63MB\n", "file size: {}\n", .{fmtIntSizeDec(63 * 1000 * 1000)});
|
||||
try expectFmt("file size: 63MiB\n", "file size: {}\n", .{fmtIntSizeBin(63 * 1024 * 1024)});
|
||||
try expectFmt("file size: 66.06MB\n", "file size: {:.2}\n", .{fmtIntSizeDec(63 * 1024 * 1024)});
|
||||
try expectFmt("file size: 60.08MiB\n", "file size: {:.2}\n", .{fmtIntSizeBin(63 * 1000 * 1000)});
|
||||
}
|
||||
|
||||
test "struct" {
|
||||
|
|
@ -2213,8 +2231,6 @@ test "vector" {
|
|||
try expectFmt("{ -2, -1, +0, +1 }", "{d:5}", .{vi64});
|
||||
try expectFmt("{ 1000, 2000, 3000, 4000 }", "{}", .{vu64});
|
||||
try expectFmt("{ 3e8, 7d0, bb8, fa0 }", "{x}", .{vu64});
|
||||
try expectFmt("{ 1kB, 2kB, 3kB, 4kB }", "{B}", .{vu64});
|
||||
try expectFmt("{ 1000B, 1.953125KiB, 2.9296875KiB, 3.90625KiB }", "{Bi}", .{vu64});
|
||||
}
|
||||
|
||||
test "enum-literal" {
|
||||
|
|
|
|||
|
|
@ -701,7 +701,11 @@ pub fn updateDecl(self: *Coff, module: *Module, decl: *Module.Decl) !void {
|
|||
}
|
||||
} else {
|
||||
const vaddr = try self.allocateTextBlock(&decl.link.coff, code.len, required_alignment);
|
||||
log.debug("allocated text block for {s} at 0x{x} (size: {Bi})\n", .{ mem.spanZ(decl.name), vaddr, code.len });
|
||||
log.debug("allocated text block for {s} at 0x{x} (size: {Bi})\n", .{
|
||||
mem.spanZ(decl.name),
|
||||
vaddr,
|
||||
std.fmt.fmtIntSizeDec(code.len),
|
||||
});
|
||||
errdefer self.freeTextBlock(&decl.link.coff);
|
||||
self.offset_table.items[decl.link.coff.offset_table_index] = vaddr;
|
||||
try self.writeOffsetTableEntry(decl.link.coff.offset_table_index);
|
||||
|
|
|
|||
|
|
@ -270,7 +270,7 @@ pub fn main() !void {
|
|||
if (std.mem.eql(u8, args[arg_i], "--help"))
|
||||
usageAndExit(args[0]);
|
||||
if (arg_i + 1 >= args.len) {
|
||||
std.debug.warn("expected argument after '{}'\n", .{args[arg_i]});
|
||||
std.debug.warn("expected argument after '{s}'\n", .{args[arg_i]});
|
||||
usageAndExit(args[0]);
|
||||
}
|
||||
|
||||
|
|
@ -283,7 +283,7 @@ pub fn main() !void {
|
|||
assert(opt_abi == null);
|
||||
opt_abi = args[arg_i + 1];
|
||||
} else {
|
||||
std.debug.warn("unrecognized argument: {}\n", .{args[arg_i]});
|
||||
std.debug.warn("unrecognized argument: {s}\n", .{args[arg_i]});
|
||||
usageAndExit(args[0]);
|
||||
}
|
||||
|
||||
|
|
@ -297,10 +297,10 @@ pub fn main() !void {
|
|||
else if (std.mem.eql(u8, abi_name, "glibc"))
|
||||
LibCVendor.glibc
|
||||
else {
|
||||
std.debug.warn("unrecognized C ABI: {}\n", .{abi_name});
|
||||
std.debug.warn("unrecognized C ABI: {s}\n", .{abi_name});
|
||||
usageAndExit(args[0]);
|
||||
};
|
||||
const generic_name = try std.fmt.allocPrint(allocator, "generic-{}", .{abi_name});
|
||||
const generic_name = try std.fmt.allocPrint(allocator, "generic-{s}", .{abi_name});
|
||||
|
||||
// TODO compiler crashed when I wrote this the canonical way
|
||||
var libc_targets: []const LibCTarget = undefined;
|
||||
|
|
@ -368,10 +368,10 @@ pub fn main() !void {
|
|||
if (gop.found_existing) {
|
||||
max_bytes_saved += raw_bytes.len;
|
||||
gop.entry.value.hit_count += 1;
|
||||
std.debug.warn("duplicate: {} {} ({Bi:2})\n", .{
|
||||
std.debug.warn("duplicate: {s} {s} ({:2})\n", .{
|
||||
libc_target.name,
|
||||
rel_path,
|
||||
raw_bytes.len,
|
||||
std.fmt.fmtIntSizeDec(raw_bytes.len),
|
||||
});
|
||||
} else {
|
||||
gop.entry.value = Contents{
|
||||
|
|
@ -390,16 +390,19 @@ pub fn main() !void {
|
|||
};
|
||||
try target_to_hash.putNoClobber(dest_target, hash);
|
||||
},
|
||||
else => std.debug.warn("warning: weird file: {}\n", .{full_path}),
|
||||
else => std.debug.warn("warning: weird file: {s}\n", .{full_path}),
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
} else {
|
||||
std.debug.warn("warning: libc target not found: {}\n", .{libc_target.name});
|
||||
std.debug.warn("warning: libc target not found: {s}\n", .{libc_target.name});
|
||||
}
|
||||
}
|
||||
std.debug.warn("summary: {Bi:2} could be reduced to {Bi:2}\n", .{ total_bytes, total_bytes - max_bytes_saved });
|
||||
std.debug.warn("summary: {:2} could be reduced to {:2}\n", .{
|
||||
std.fmt.fmtIntSizeDec(total_bytes),
|
||||
std.fmt.fmtIntSizeDec(total_bytes - max_bytes_saved),
|
||||
});
|
||||
try std.fs.cwd().makePath(out_dir);
|
||||
|
||||
var missed_opportunity_bytes: usize = 0;
|
||||
|
|
@ -428,7 +431,10 @@ pub fn main() !void {
|
|||
if (contender.hit_count > 1) {
|
||||
const this_missed_bytes = contender.hit_count * contender.bytes.len;
|
||||
missed_opportunity_bytes += this_missed_bytes;
|
||||
std.debug.warn("Missed opportunity ({Bi:2}): {}\n", .{ this_missed_bytes, path_kv.key });
|
||||
std.debug.warn("Missed opportunity ({:2}): {s}\n", .{
|
||||
std.fmt.fmtIntSizeDec(this_missed_bytes),
|
||||
path_kv.key,
|
||||
});
|
||||
} else break;
|
||||
}
|
||||
}
|
||||
|
|
@ -442,7 +448,7 @@ pub fn main() !void {
|
|||
.specific => |a| @tagName(a),
|
||||
else => @tagName(dest_target.arch),
|
||||
};
|
||||
const out_subpath = try std.fmt.allocPrint(allocator, "{}-{}-{}", .{
|
||||
const out_subpath = try std.fmt.allocPrint(allocator, "{s}-{s}-{s}", .{
|
||||
arch_name,
|
||||
@tagName(dest_target.os),
|
||||
@tagName(dest_target.abi),
|
||||
|
|
@ -455,7 +461,7 @@ pub fn main() !void {
|
|||
}
|
||||
|
||||
fn usageAndExit(arg0: []const u8) noreturn {
|
||||
std.debug.warn("Usage: {} [--search-path <dir>] --out <dir> --abi <name>\n", .{arg0});
|
||||
std.debug.warn("Usage: {s} [--search-path <dir>] --out <dir> --abi <name>\n", .{arg0});
|
||||
std.debug.warn("--search-path can be used any number of times.\n", .{});
|
||||
std.debug.warn(" subdirectories of search paths look like, e.g. x86_64-linux-gnu\n", .{});
|
||||
std.debug.warn("--out is a dir that will be created, and populated with the results\n", .{});
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue