authorgravatar for john.schmidt.h@gmail.comJohn Schmidt <john.schmidt.h@gmail.com> 2021-12-18 23:10:02+01:00
committergravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2022-01-24 20:30:36+02:00
log40b3c9a5926f70db2dcf41971342a7e191d036af
treed2d4715f8520498addb274a5ea3746cbbc039354
parenta0732117d07f9dc9b8afb457d935ca84411ec233

Handle FormatOptions in fmtDuration/fmtDurationSigned


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

lib/std/fmt.zig+58-20
...@@ -1417,10 +1417,23 @@ pub fn formatIntBuf(out_buf: []u8, value: anytype, base: u8, case: Case, options...@@ -1417,10 +1417,23 @@ pub fn formatIntBuf(out_buf: []u8, value: anytype, base: u8, case: Case, options
1417 return fbs.pos;1417 return fbs.pos;
1418}1418}
14191419
1420fn formatDuration(ns: u64, comptime fmt: []const u8, options: std.fmt.FormatOptions, writer: anytype) !void {1420const FormatDurationData = struct {
1421 ns: u64,
1422 negative: bool = false,
1423};
1424
1425fn formatDuration(data: FormatDurationData, comptime fmt: []const u8, options: std.fmt.FormatOptions, writer: anytype) !void {
1421 _ = fmt;1426 _ = fmt;
1422 _ = options;1427
1423 var ns_remaining = ns;1428 // worst case: "-XXXyXXwXXdXXhXXmXX.XXXs".len = 24
1429 var buf: [24]u8 = undefined;
1430 var fbs = std.io.fixedBufferStream(&buf);
1431 var buf_writer = fbs.writer();
1432 if (data.negative) {
1433 try buf_writer.writeByte('-');
1434 }
1435
1436 var ns_remaining = data.ns;
1424 inline for (.{1437 inline for (.{
1425 .{ .ns = 365 * std.time.ns_per_day, .sep = 'y' },1438 .{ .ns = 365 * std.time.ns_per_day, .sep = 'y' },
1426 .{ .ns = std.time.ns_per_week, .sep = 'w' },1439 .{ .ns = std.time.ns_per_week, .sep = 'w' },
...@@ -1430,10 +1443,11 @@ fn formatDuration(ns: u64, comptime fmt: []const u8, options: std.fmt.FormatOpti...@@ -1430,10 +1443,11 @@ fn formatDuration(ns: u64, comptime fmt: []const u8, options: std.fmt.FormatOpti
1430 }) |unit| {1443 }) |unit| {
1431 if (ns_remaining >= unit.ns) {1444 if (ns_remaining >= unit.ns) {
1432 const units = ns_remaining / unit.ns;1445 const units = ns_remaining / unit.ns;
1433 try formatInt(units, 10, .lower, .{}, writer);1446 try formatInt(units, 10, .lower, .{}, buf_writer);
1434 try writer.writeByte(unit.sep);1447 try buf_writer.writeByte(unit.sep);
1435 ns_remaining -= units * unit.ns;1448 ns_remaining -= units * unit.ns;
1436 if (ns_remaining == 0) return;1449 if (ns_remaining == 0)
1450 return formatBuf(fbs.getWritten(), options, writer);
1437 }1451 }
1438 }1452 }
14391453
...@@ -1444,32 +1458,33 @@ fn formatDuration(ns: u64, comptime fmt: []const u8, options: std.fmt.FormatOpti...@@ -1444,32 +1458,33 @@ fn formatDuration(ns: u64, comptime fmt: []const u8, options: std.fmt.FormatOpti
1444 }) |unit| {1458 }) |unit| {
1445 const kunits = ns_remaining * 1000 / unit.ns;1459 const kunits = ns_remaining * 1000 / unit.ns;
1446 if (kunits >= 1000) {1460 if (kunits >= 1000) {
1447 try formatInt(kunits / 1000, 10, .lower, .{}, writer);1461 try formatInt(kunits / 1000, 10, .lower, .{}, buf_writer);
1448 const frac = kunits % 1000;1462 const frac = kunits % 1000;
1449 if (frac > 0) {1463 if (frac > 0) {
1450 // Write up to 3 decimal places1464 // Write up to 3 decimal places
1451 var buf = [_]u8{ '.', 0, 0, 0 };1465 var decimal_buf = [_]u8{ '.', 0, 0, 0 };
1452 _ = formatIntBuf(buf[1..], frac, 10, .lower, .{ .fill = '0', .width = 3 });1466 _ = formatIntBuf(decimal_buf[1..], frac, 10, .lower, .{ .fill = '0', .width = 3 });
1453 var end: usize = 4;1467 var end: usize = 4;
1454 while (end > 1) : (end -= 1) {1468 while (end > 1) : (end -= 1) {
1455 if (buf[end - 1] != '0') break;1469 if (decimal_buf[end - 1] != '0') break;
1456 }1470 }
1457 try writer.writeAll(buf[0..end]);1471 try buf_writer.writeAll(decimal_buf[0..end]);
1458 }1472 }
1459 try writer.writeAll(unit.sep);1473 try buf_writer.writeAll(unit.sep);
1460 return;1474 return formatBuf(fbs.getWritten(), options, writer);
1461 }1475 }
1462 }1476 }
14631477
1464 try formatInt(ns_remaining, 10, .lower, .{}, writer);1478 try formatInt(ns_remaining, 10, .lower, .{}, buf_writer);
1465 try writer.writeAll("ns");1479 try buf_writer.writeAll("ns");
1466 return;1480 return formatBuf(fbs.getWritten(), options, writer);
1467}1481}
14681482
1469/// Return a Formatter for number of nanoseconds according to its magnitude:1483/// Return a Formatter for number of nanoseconds according to its magnitude:
1470/// [#y][#w][#d][#h][#m]#[.###][n|u|m]s1484/// [#y][#w][#d][#h][#m]#[.###][n|u|m]s
1471pub fn fmtDuration(ns: u64) Formatter(formatDuration) {1485pub fn fmtDuration(ns: u64) Formatter(formatDuration) {
1472 return .{ .data = ns };1486 const data = FormatDurationData{ .ns = ns };
1487 return .{ .data = data };
1473}1488}
14741489
1475test "fmtDuration" {1490test "fmtDuration" {
...@@ -1504,18 +1519,29 @@ test "fmtDuration" {...@@ -1504,18 +1519,29 @@ test "fmtDuration" {
1504 .{ .s = "1y1h1ms", .d = 365 * std.time.ns_per_day + std.time.ns_per_hour + std.time.ns_per_ms },1519 .{ .s = "1y1h1ms", .d = 365 * std.time.ns_per_day + std.time.ns_per_hour + std.time.ns_per_ms },
1505 .{ .s = "1y1h1ms", .d = 365 * std.time.ns_per_day + std.time.ns_per_hour + std.time.ns_per_ms + 1 },1520 .{ .s = "1y1h1ms", .d = 365 * std.time.ns_per_day + std.time.ns_per_hour + std.time.ns_per_ms + 1 },
1506 .{ .s = "1y1m999ns", .d = 365 * std.time.ns_per_day + std.time.ns_per_min + 999 },1521 .{ .s = "1y1m999ns", .d = 365 * std.time.ns_per_day + std.time.ns_per_min + 999 },
1522 .{ .s = "584y49w23h34m33.709s", .d = math.maxInt(u64) },
1507 }) |tc| {1523 }) |tc| {
1508 const slice = try bufPrint(&buf, "{}", .{fmtDuration(tc.d)});1524 const slice = try bufPrint(&buf, "{}", .{fmtDuration(tc.d)});
1509 try std.testing.expectEqualStrings(tc.s, slice);1525 try std.testing.expectEqualStrings(tc.s, slice);
1510 }1526 }
1527
1528 inline for (.{
1529 .{ .s = "=======0ns", .f = "{s:=>10}", .d = 0 },
1530 .{ .s = "1ns=======", .f = "{s:=<10}", .d = 1 },
1531 .{ .s = " 999ns ", .f = "{s:^10}", .d = std.time.ns_per_us - 1 },
1532 }) |tc| {
1533 const slice = try bufPrint(&buf, tc.f, .{fmtDuration(tc.d)});
1534 try std.testing.expectEqualStrings(tc.s, slice);
1535 }
1511}1536}
15121537
1513fn formatDurationSigned(ns: i64, comptime fmt: []const u8, options: std.fmt.FormatOptions, writer: anytype) !void {1538fn formatDurationSigned(ns: i64, comptime fmt: []const u8, options: std.fmt.FormatOptions, writer: anytype) !void {
1514 if (ns < 0) {1539 if (ns < 0) {
1515 try writer.writeByte('-');1540 const data = FormatDurationData{ .ns = @intCast(u64, -ns), .negative = true };
1516 try formatDuration(@intCast(u64, -ns), fmt, options, writer);1541 try formatDuration(data, fmt, options, writer);
1517 } else {1542 } else {
1518 try formatDuration(@intCast(u64, ns), fmt, options, writer);1543 const data = FormatDurationData{ .ns = @intCast(u64, ns) };
1544 try formatDuration(data, fmt, options, writer);
1519 }1545 }
1520}1546}
15211547
...@@ -1585,10 +1611,22 @@ test "fmtDurationSigned" {...@@ -1585,10 +1611,22 @@ test "fmtDurationSigned" {
1585 .{ .s = "-1y1h1ms", .d = -(365 * std.time.ns_per_day + std.time.ns_per_hour + std.time.ns_per_ms + 1) },1611 .{ .s = "-1y1h1ms", .d = -(365 * std.time.ns_per_day + std.time.ns_per_hour + std.time.ns_per_ms + 1) },
1586 .{ .s = "1y1m999ns", .d = 365 * std.time.ns_per_day + std.time.ns_per_min + 999 },1612 .{ .s = "1y1m999ns", .d = 365 * std.time.ns_per_day + std.time.ns_per_min + 999 },
1587 .{ .s = "-1y1m999ns", .d = -(365 * std.time.ns_per_day + std.time.ns_per_min + 999) },1613 .{ .s = "-1y1m999ns", .d = -(365 * std.time.ns_per_day + std.time.ns_per_min + 999) },
1614 .{ .s = "292y24w3d23h47m16.854s", .d = math.maxInt(i64) },
1615 .{ .s = "-292y24w3d23h47m16.854s", .d = math.minInt(i64) + 1 },
1588 }) |tc| {1616 }) |tc| {
1589 const slice = try bufPrint(&buf, "{}", .{fmtDurationSigned(tc.d)});1617 const slice = try bufPrint(&buf, "{}", .{fmtDurationSigned(tc.d)});
1590 try std.testing.expectEqualStrings(tc.s, slice);1618 try std.testing.expectEqualStrings(tc.s, slice);
1591 }1619 }
1620
1621 inline for (.{
1622 .{ .s = "=======0ns", .f = "{s:=>10}", .d = 0 },
1623 .{ .s = "1ns=======", .f = "{s:=<10}", .d = 1 },
1624 .{ .s = "-1ns======", .f = "{s:=<10}", .d = -(1) },
1625 .{ .s = " -999ns ", .f = "{s:^10}", .d = -(std.time.ns_per_us - 1) },
1626 }) |tc| {
1627 const slice = try bufPrint(&buf, tc.f, .{fmtDurationSigned(tc.d)});
1628 try std.testing.expectEqualStrings(tc.s, slice);
1629 }
1592}1630}
15931631
1594pub const ParseIntError = error{1632pub const ParseIntError = error{