mirror of
https://github.com/ziglang/zig.git
synced 2025-02-13 16:10:19 +00:00
Merge pull request #6360 from LemonBoy/some-fmt-fixes
Two std.fmt fixes
This commit is contained in:
commit
3672a18799
139
lib/std/fmt.zig
139
lib/std/fmt.zig
@ -22,7 +22,7 @@ pub const Alignment = enum {
|
||||
pub const FormatOptions = struct {
|
||||
precision: ?usize = null,
|
||||
width: ?usize = null,
|
||||
alignment: Alignment = .Left,
|
||||
alignment: Alignment = .Right,
|
||||
fill: u8 = ' ',
|
||||
};
|
||||
|
||||
@ -327,7 +327,7 @@ pub fn formatType(
|
||||
max_depth: usize,
|
||||
) @TypeOf(writer).Error!void {
|
||||
if (comptime std.mem.eql(u8, fmt, "*")) {
|
||||
try writer.writeAll(@typeName(@typeInfo(@TypeOf(value)).Pointer.child));
|
||||
try writer.writeAll(@typeName(std.meta.Child(@TypeOf(value))));
|
||||
try writer.writeAll("@");
|
||||
try formatInt(@ptrToInt(value), 16, false, FormatOptions{}, writer);
|
||||
return;
|
||||
@ -631,26 +631,22 @@ pub fn formatBuf(
|
||||
writer: anytype,
|
||||
) !void {
|
||||
const width = options.width orelse buf.len;
|
||||
var padding = if (width > buf.len) (width - buf.len) else 0;
|
||||
const pad_byte = [1]u8{options.fill};
|
||||
const padding = if (width > buf.len) (width - buf.len) else 0;
|
||||
|
||||
switch (options.alignment) {
|
||||
.Left => {
|
||||
try writer.writeAll(buf);
|
||||
while (padding > 0) : (padding -= 1) {
|
||||
try writer.writeAll(&pad_byte);
|
||||
}
|
||||
try writer.writeByteNTimes(options.fill, padding);
|
||||
},
|
||||
.Center => {
|
||||
const padl = padding / 2;
|
||||
var i: usize = 0;
|
||||
while (i < padl) : (i += 1) try writer.writeAll(&pad_byte);
|
||||
const left_padding = padding / 2;
|
||||
const right_padding = (padding + 1) / 2;
|
||||
try writer.writeByteNTimes(options.fill, left_padding);
|
||||
try writer.writeAll(buf);
|
||||
while (i < padding) : (i += 1) try writer.writeAll(&pad_byte);
|
||||
try writer.writeByteNTimes(options.fill, right_padding);
|
||||
},
|
||||
.Right => {
|
||||
while (padding > 0) : (padding -= 1) {
|
||||
try writer.writeAll(&pad_byte);
|
||||
}
|
||||
try writer.writeByteNTimes(options.fill, padding);
|
||||
try writer.writeAll(buf);
|
||||
},
|
||||
}
|
||||
@ -941,61 +937,27 @@ pub fn formatInt(
|
||||
options: FormatOptions,
|
||||
writer: anytype,
|
||||
) !void {
|
||||
assert(base >= 2);
|
||||
|
||||
const int_value = if (@TypeOf(value) == comptime_int) blk: {
|
||||
const Int = math.IntFittingRange(value, value);
|
||||
break :blk @as(Int, value);
|
||||
} else
|
||||
value;
|
||||
|
||||
if (@typeInfo(@TypeOf(int_value)).Int.is_signed) {
|
||||
return formatIntSigned(int_value, base, uppercase, options, writer);
|
||||
} else {
|
||||
return formatIntUnsigned(int_value, base, uppercase, options, writer);
|
||||
}
|
||||
}
|
||||
const value_info = @typeInfo(@TypeOf(int_value)).Int;
|
||||
|
||||
fn formatIntSigned(
|
||||
value: anytype,
|
||||
base: u8,
|
||||
uppercase: bool,
|
||||
options: FormatOptions,
|
||||
writer: anytype,
|
||||
) !void {
|
||||
const new_options = FormatOptions{
|
||||
.width = if (options.width) |w| (if (w == 0) 0 else w - 1) else null,
|
||||
.precision = options.precision,
|
||||
.fill = options.fill,
|
||||
};
|
||||
const bit_count = @typeInfo(@TypeOf(value)).Int.bits;
|
||||
const Uint = std.meta.Int(false, bit_count);
|
||||
if (value < 0) {
|
||||
try writer.writeAll("-");
|
||||
const new_value = math.absCast(value);
|
||||
return formatIntUnsigned(new_value, base, uppercase, new_options, writer);
|
||||
} else if (options.width == null or options.width.? == 0) {
|
||||
return formatIntUnsigned(@intCast(Uint, value), base, uppercase, options, writer);
|
||||
} else {
|
||||
try writer.writeAll("+");
|
||||
const new_value = @intCast(Uint, value);
|
||||
return formatIntUnsigned(new_value, base, uppercase, new_options, writer);
|
||||
}
|
||||
}
|
||||
// The type must have the same size as `base` or be wider in order for the
|
||||
// division to work
|
||||
const min_int_bits = comptime math.max(value_info.bits, 8);
|
||||
const MinInt = std.meta.Int(false, min_int_bits);
|
||||
|
||||
fn formatIntUnsigned(
|
||||
value: anytype,
|
||||
base: u8,
|
||||
uppercase: bool,
|
||||
options: FormatOptions,
|
||||
writer: anytype,
|
||||
) !void {
|
||||
assert(base >= 2);
|
||||
const value_info = @typeInfo(@TypeOf(value)).Int;
|
||||
var buf: [math.max(value_info.bits, 1)]u8 = undefined;
|
||||
const min_int_bits = comptime math.max(value_info.bits, @typeInfo(@TypeOf(base)).Int.bits);
|
||||
const MinInt = std.meta.Int(value_info.is_signed, min_int_bits);
|
||||
var a: MinInt = value;
|
||||
const abs_value = math.absCast(int_value);
|
||||
// The worst case in terms of space needed is base 2, plus 1 for the sign
|
||||
var buf: [1 + math.max(value_info.bits, 1)]u8 = undefined;
|
||||
|
||||
var a: MinInt = abs_value;
|
||||
var index: usize = buf.len;
|
||||
|
||||
while (true) {
|
||||
const digit = a % base;
|
||||
index -= 1;
|
||||
@ -1004,25 +966,21 @@ fn formatIntUnsigned(
|
||||
if (a == 0) break;
|
||||
}
|
||||
|
||||
const digits_buf = buf[index..];
|
||||
const width = options.width orelse 0;
|
||||
const padding = if (width > digits_buf.len) (width - digits_buf.len) else 0;
|
||||
|
||||
if (padding > index) {
|
||||
const zero_byte: u8 = options.fill;
|
||||
var leftover_padding = padding - index;
|
||||
while (true) {
|
||||
try writer.writeAll(@as(*const [1]u8, &zero_byte)[0..]);
|
||||
leftover_padding -= 1;
|
||||
if (leftover_padding == 0) break;
|
||||
if (value_info.is_signed) {
|
||||
if (value < 0) {
|
||||
// Negative integer
|
||||
index -= 1;
|
||||
buf[index] = '-';
|
||||
} else if (options.width == null or options.width.? == 0) {
|
||||
// Positive integer, omit the plus sign
|
||||
} else {
|
||||
// Positive integer
|
||||
index -= 1;
|
||||
buf[index] = '+';
|
||||
}
|
||||
mem.set(u8, buf[0..index], options.fill);
|
||||
return writer.writeAll(&buf);
|
||||
} else {
|
||||
const padded_buf = buf[index - padding ..];
|
||||
mem.set(u8, padded_buf[0..padding], options.fill);
|
||||
return writer.writeAll(padded_buf);
|
||||
}
|
||||
|
||||
return formatBuf(buf[index..], options, writer);
|
||||
}
|
||||
|
||||
pub fn formatIntBuf(out_buf: []u8, value: anytype, base: u8, uppercase: bool, options: FormatOptions) usize {
|
||||
@ -1246,6 +1204,10 @@ test "optional" {
|
||||
const value: ?i32 = null;
|
||||
try testFmt("optional: null\n", "optional: {}\n", .{value});
|
||||
}
|
||||
{
|
||||
const value = @intToPtr(?*i32, 0xf000d000);
|
||||
try testFmt("optional: *i32@f000d000\n", "optional: {*}\n", .{value});
|
||||
}
|
||||
}
|
||||
|
||||
test "error" {
|
||||
@ -1283,7 +1245,17 @@ test "int.specifier" {
|
||||
|
||||
test "int.padded" {
|
||||
try testFmt("u8: ' 1'", "u8: '{:4}'", .{@as(u8, 1)});
|
||||
try testFmt("u8: 'xxx1'", "u8: '{:x<4}'", .{@as(u8, 1)});
|
||||
try testFmt("u8: '1000'", "u8: '{:0<4}'", .{@as(u8, 1)});
|
||||
try testFmt("u8: '0001'", "u8: '{:0>4}'", .{@as(u8, 1)});
|
||||
try testFmt("u8: '0100'", "u8: '{:0^4}'", .{@as(u8, 1)});
|
||||
try testFmt("i8: '-1 '", "i8: '{:<4}'", .{@as(i8, -1)});
|
||||
try testFmt("i8: ' -1'", "i8: '{:>4}'", .{@as(i8, -1)});
|
||||
try testFmt("i8: ' -1 '", "i8: '{:^4}'", .{@as(i8, -1)});
|
||||
try testFmt("i16: '-1234'", "i16: '{:4}'", .{@as(i16, -1234)});
|
||||
try testFmt("i16: '+1234'", "i16: '{:4}'", .{@as(i16, 1234)});
|
||||
try testFmt("i16: '-12345'", "i16: '{:4}'", .{@as(i16, -12345)});
|
||||
try testFmt("i16: '+12345'", "i16: '{:4}'", .{@as(i16, 12345)});
|
||||
try testFmt("u16: '12345'", "u16: '{:4}'", .{@as(u16, 12345)});
|
||||
}
|
||||
|
||||
test "buffer" {
|
||||
@ -1329,7 +1301,7 @@ test "slice" {
|
||||
try testFmt("slice: []const u8@deadbeef\n", "slice: {}\n", .{value});
|
||||
}
|
||||
|
||||
try testFmt("buf: Test \n", "buf: {s:5}\n", .{"Test"});
|
||||
try testFmt("buf: Test\n", "buf: {s:5}\n", .{"Test"});
|
||||
try testFmt("buf: Test\n Other text", "buf: {s}\n Other text", .{"Test"});
|
||||
}
|
||||
|
||||
@ -1362,7 +1334,7 @@ test "cstr" {
|
||||
.{@ptrCast([*c]const u8, "Test C")},
|
||||
);
|
||||
try testFmt(
|
||||
"cstr: Test C \n",
|
||||
"cstr: Test C\n",
|
||||
"cstr: {s:10}\n",
|
||||
.{@ptrCast([*c]const u8, "Test C")},
|
||||
);
|
||||
@ -1805,7 +1777,7 @@ test "vector" {
|
||||
|
||||
try testFmt("{ true, false, true, false }", "{}", .{vbool});
|
||||
try testFmt("{ -2, -1, 0, 1 }", "{}", .{vi64});
|
||||
try testFmt("{ - 2, - 1, + 0, + 1 }", "{d:5}", .{vi64});
|
||||
try testFmt("{ -2, -1, +0, +1 }", "{d:5}", .{vi64});
|
||||
try testFmt("{ 1000, 2000, 3000, 4000 }", "{}", .{vu64});
|
||||
try testFmt("{ 3e8, 7d0, bb8, fa0 }", "{x}", .{vu64});
|
||||
try testFmt("{ 1kB, 2kB, 3kB, 4kB }", "{B}", .{vu64});
|
||||
@ -1818,15 +1790,16 @@ test "enum-literal" {
|
||||
|
||||
test "padding" {
|
||||
try testFmt("Simple", "{}", .{"Simple"});
|
||||
try testFmt("true ", "{:10}", .{true});
|
||||
try testFmt(" true", "{:10}", .{true});
|
||||
try testFmt(" true", "{:>10}", .{true});
|
||||
try testFmt("======true", "{:=>10}", .{true});
|
||||
try testFmt("true======", "{:=<10}", .{true});
|
||||
try testFmt(" true ", "{:^10}", .{true});
|
||||
try testFmt("===true===", "{:=^10}", .{true});
|
||||
try testFmt("Minimum width", "{:18} width", .{"Minimum"});
|
||||
try testFmt(" Minimum width", "{:18} width", .{"Minimum"});
|
||||
try testFmt("==================Filled", "{:=>24}", .{"Filled"});
|
||||
try testFmt(" Centered ", "{:^24}", .{"Centered"});
|
||||
try testFmt("-", "{:-^1}", .{""});
|
||||
}
|
||||
|
||||
test "decimal float padding" {
|
||||
|
@ -2032,7 +2032,7 @@ fn escapeChar(c: u8, char_buf: *[4]u8) []const u8 {
|
||||
// Handle the remaining escapes Zig doesn't support by turning them
|
||||
// into their respective hex representation
|
||||
else => if (std.ascii.isCntrl(c))
|
||||
std.fmt.bufPrint(char_buf, "\\x{x:0<2}", .{c}) catch unreachable
|
||||
std.fmt.bufPrint(char_buf, "\\x{x:0>2}", .{c}) catch unreachable
|
||||
else
|
||||
std.fmt.bufPrint(char_buf, "{c}", .{c}) catch unreachable,
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user