authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-02-12 19:55:09-08:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-07-01 16:35:25-07:00
log00c6c836a66db0bc08309534a49d4c5941a416aa
treecccb3d0fe18fc72e48bb4e369348d504ce00f873
parentee6d19480da53b3a351749e2a7b18c45ad072018

std: start reworking std.io

hello world is compiling

32 files changed, 3894 insertions(+), 3413 deletions(-)

CMakeLists.txt-4
......@@ -436,7 +436,6 @@ set(ZIG_STAGE2_SOURCES
436436 lib/std/elf.zig
437437 lib/std/fifo.zig
438438 lib/std/fmt.zig
439 lib/std/fmt/format_float.zig
440439 lib/std/fmt/parse_float.zig
441440 lib/std/fs.zig
442441 lib/std/fs/AtomicFile.zig
......@@ -454,12 +453,9 @@ set(ZIG_STAGE2_SOURCES
454453 lib/std/io/Reader.zig
455454 lib/std/io/Writer.zig
456455 lib/std/io/buffered_atomic_file.zig
457 lib/std/io/buffered_writer.zig
458456 lib/std/io/change_detection_stream.zig
459457 lib/std/io/counting_reader.zig
460 lib/std/io/counting_writer.zig
461458 lib/std/io/find_byte_writer.zig
462 lib/std/io/fixed_buffer_stream.zig
463459 lib/std/io/limited_reader.zig
464460 lib/std/io/seekable_stream.zig
465461 lib/std/json.zig
lib/std/Build/Cache.zig+5-7
......@@ -286,11 +286,9 @@ pub const HashHelper = struct {
286286
287287pub fn binToHex(bin_digest: BinDigest) HexDigest {
288288 var out_digest: HexDigest = undefined;
289 _ = fmt.bufPrint(
290 &out_digest,
291 "{s}",
292 .{fmt.fmtSliceHexLower(&bin_digest)},
293 ) catch unreachable;
289 var bw: std.io.BufferedWriter = undefined;
290 bw.initFixed(&out_digest);
291 bw.printHex(&bin_digest, .lower) catch unreachable;
294292 return out_digest;
295293}
296294
......@@ -1133,11 +1131,11 @@ pub const Manifest = struct {
11331131 const writer = contents.writer();
11341132 try writer.writeAll(manifest_header ++ "\n");
11351133 for (self.files.keys()) |file| {
1136 try writer.print("{d} {d} {d} {} {d} {s}\n", .{
1134 try writer.print("{d} {d} {d} {x} {d} {s}\n", .{
11371135 file.stat.size,
11381136 file.stat.inode,
11391137 file.stat.mtime,
1140 fmt.fmtSliceHexLower(&file.bin_digest),
1138 &file.bin_digest,
11411139 file.prefixed_path.prefix,
11421140 file.prefixed_path.sub_path,
11431141 });
lib/std/Build/Step/CheckObject.zig+1-1
......@@ -963,7 +963,7 @@ const MachODumper = struct {
963963 .UUID => {
964964 const uuid = lc.cast(macho.uuid_command).?;
965965 try writer.writeByte('\n');
966 try writer.print("uuid {x}", .{std.fmt.fmtSliceHexLower(&uuid.uuid)});
966 try writer.print("uuid {x}", .{&uuid.uuid});
967967 },
968968
969969 .DATA_IN_CODE,
lib/std/Build/Step/Compile.zig+2-8
......@@ -1696,9 +1696,7 @@ fn getZigArgs(compile: *Compile, fuzz: bool) ![][]const u8 {
16961696
16971697 if (compile.build_id orelse b.build_id) |build_id| {
16981698 try zig_args.append(switch (build_id) {
1699 .hexstring => |hs| b.fmt("--build-id=0x{s}", .{
1700 std.fmt.fmtSliceHexLower(hs.toSlice()),
1701 }),
1699 .hexstring => |hs| b.fmt("--build-id=0x{x}", .{hs.toSlice()}),
17021700 .none, .fast, .uuid, .sha1, .md5 => b.fmt("--build-id={s}", .{@tagName(build_id)}),
17031701 });
17041702 }
......@@ -1793,11 +1791,7 @@ fn getZigArgs(compile: *Compile, fuzz: bool) ![][]const u8 {
17931791 var args_hash: [Sha256.digest_length]u8 = undefined;
17941792 Sha256.hash(args, &args_hash, .{});
17951793 var args_hex_hash: [Sha256.digest_length * 2]u8 = undefined;
1796 _ = try std.fmt.bufPrint(
1797 &args_hex_hash,
1798 "{s}",
1799 .{std.fmt.fmtSliceHexLower(&args_hash)},
1800 );
1794 _ = try std.fmt.bufPrint(&args_hex_hash, "{x}", .{&args_hash});
18011795
18021796 const args_file = "args" ++ fs.path.sep_str ++ args_hex_hash;
18031797 try b.cache_root.handle.writeFile(.{ .sub_path = args_file, .data = args });
lib/std/array_list.zig+58-15
......@@ -338,23 +338,66 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?mem.Alignment) ty
338338 @memcpy(self.items[old_len..][0..items.len], items);
339339 }
340340
341 pub const Writer = if (T != u8)
342 @compileError("The Writer interface is only defined for ArrayList(u8) " ++
343 "but the given type is ArrayList(" ++ @typeName(T) ++ ")")
344 else
345 std.io.Writer(*Self, Allocator.Error, appendWrite);
346
347 /// Initializes a Writer which will append to the list.
348 pub fn writer(self: *Self) Writer {
349 return .{ .context = self };
341 /// Initializes a `std.io.Writer` which will append to the list.
342 pub fn writer(self: *Self) std.io.Writer {
343 comptime assert(T == u8);
344 return .{
345 .context = self,
346 .vtable = &.{
347 .writev = expanding_writev,
348 .writeFile = expanding_writeFile,
349 },
350 };
350351 }
351352
352 /// Same as `append` except it returns the number of bytes written, which is always the same
353 /// as `m.len`. The purpose of this function existing is to match `std.io.Writer` API.
354 /// Invalidates element pointers if additional memory is needed.
355 fn appendWrite(self: *Self, m: []const u8) Allocator.Error!usize {
356 try self.appendSlice(m);
357 return m.len;
353 fn expanding_writev(context: *anyopaque, data: []const []const u8) anyerror!usize {
354 const self: *Self = @alignCast(@ptrCast(context));
355 const original_len = self.items.len;
356 var new_capacity: usize = self.capacity;
357 for (data) |bytes| new_capacity += bytes.len;
358 try self.ensureTotalCapacity(new_capacity);
359 for (data) |bytes| self.appendSliceAssumeCapacity(bytes);
360 return self.items.len - original_len;
361 }
362
363 fn expanding_writeFile(
364 context: *anyopaque,
365 file: std.fs.File,
366 offset: u64,
367 len: std.io.Writer.VTable.FileLen,
368 headers_and_trailers: []const []const u8,
369 headers_len: usize,
370 ) anyerror!usize {
371 const self: *Self = @alignCast(@ptrCast(context));
372 const trailers = headers_and_trailers[headers_len..];
373 const original_len = self.items.len;
374 if (len == .entire_file) {
375 var new_capacity: usize = self.capacity + std.atomic.cache_line;
376 for (headers_and_trailers) |bytes| new_capacity += bytes.len;
377 try self.ensureTotalCapacity(new_capacity);
378 for (headers_and_trailers[0..headers_len]) |bytes| self.appendSliceAssumeCapacity(bytes);
379 const dest = self.items.ptr[self.items.len..self.capacity];
380 const n = try file.pread(dest, offset);
381 if (n == 0) {
382 new_capacity = self.capacity;
383 for (trailers) |bytes| new_capacity += bytes.len;
384 try self.ensureTotalCapacity(new_capacity);
385 for (trailers) |bytes| self.appendSliceAssumeCapacity(bytes);
386 return self.items.len - original_len;
387 }
388 self.items.len += n;
389 return self.items.len - original_len;
390 }
391 var new_capacity: usize = self.capacity + len.int();
392 for (headers_and_trailers) |bytes| new_capacity += bytes.len;
393 try self.ensureTotalCapacity(new_capacity);
394 for (headers_and_trailers[0..headers_len]) |bytes| self.appendSliceAssumeCapacity(bytes);
395 const dest = self.items.ptr[self.items.len..][0..len.int()];
396 const n = try file.pread(dest, offset);
397 self.items.len += n;
398 if (n < dest.len) return self.items.len - original_len;
399 for (trailers) |bytes| self.appendSliceAssumeCapacity(bytes);
400 return self.items.len - original_len;
358401 }
359402
360403 pub const FixedWriter = std.io.Writer(*Self, Allocator.Error, appendWriteFixed);
lib/std/crypto/25519/curve25519.zig+2-2
......@@ -124,9 +124,9 @@ test "curve25519" {
124124 const p = try Curve25519.basePoint.clampedMul(s);
125125 try p.rejectIdentity();
126126 var buf: [128]u8 = undefined;
127 try std.testing.expectEqualStrings(try std.fmt.bufPrint(&buf, "{s}", .{std.fmt.fmtSliceHexUpper(&p.toBytes())}), "E6F2A4D1C28EE5C7AD0329268255A468AD407D2672824C0C0EB30EA6EF450145");
127 try std.testing.expectEqualStrings(try std.fmt.bufPrint(&buf, "{X}", .{&p.toBytes()}), "E6F2A4D1C28EE5C7AD0329268255A468AD407D2672824C0C0EB30EA6EF450145");
128128 const q = try p.clampedMul(s);
129 try std.testing.expectEqualStrings(try std.fmt.bufPrint(&buf, "{s}", .{std.fmt.fmtSliceHexUpper(&q.toBytes())}), "3614E119FFE55EC55B87D6B19971A9F4CBC78EFE80BEC55B96392BABCC712537");
129 try std.testing.expectEqualStrings(try std.fmt.bufPrint(&buf, "{X}", .{&q.toBytes()}), "3614E119FFE55EC55B87D6B19971A9F4CBC78EFE80BEC55B96392BABCC712537");
130130
131131 try Curve25519.rejectNonCanonical(s);
132132 s[31] |= 0x80;
lib/std/crypto/25519/ed25519.zig+3-3
......@@ -509,8 +509,8 @@ test "key pair creation" {
509509 _ = try fmt.hexToBytes(seed[0..], "8052030376d47112be7f73ed7a019293dd12ad910b654455798b4667d73de166");
510510 const key_pair = try Ed25519.KeyPair.generateDeterministic(seed);
511511 var buf: [256]u8 = undefined;
512 try std.testing.expectEqualStrings(try std.fmt.bufPrint(&buf, "{s}", .{std.fmt.fmtSliceHexUpper(&key_pair.secret_key.toBytes())}), "8052030376D47112BE7F73ED7A019293DD12AD910B654455798B4667D73DE1662D6F7455D97B4A3A10D7293909D1A4F2058CB9A370E43FA8154BB280DB839083");
513 try std.testing.expectEqualStrings(try std.fmt.bufPrint(&buf, "{s}", .{std.fmt.fmtSliceHexUpper(&key_pair.public_key.toBytes())}), "2D6F7455D97B4A3A10D7293909D1A4F2058CB9A370E43FA8154BB280DB839083");
512 try std.testing.expectEqualStrings(try std.fmt.bufPrint(&buf, "{X}", .{&key_pair.secret_key.toBytes()}), "8052030376D47112BE7F73ED7A019293DD12AD910B654455798B4667D73DE1662D6F7455D97B4A3A10D7293909D1A4F2058CB9A370E43FA8154BB280DB839083");
513 try std.testing.expectEqualStrings(try std.fmt.bufPrint(&buf, "{X}", .{&key_pair.public_key.toBytes()}), "2D6F7455D97B4A3A10D7293909D1A4F2058CB9A370E43FA8154BB280DB839083");
514514}
515515
516516test "signature" {
......@@ -520,7 +520,7 @@ test "signature" {
520520
521521 const sig = try key_pair.sign("test", null);
522522 var buf: [128]u8 = undefined;
523 try std.testing.expectEqualStrings(try std.fmt.bufPrint(&buf, "{s}", .{std.fmt.fmtSliceHexUpper(&sig.toBytes())}), "10A442B4A80CC4225B154F43BEF28D2472CA80221951262EB8E0DF9091575E2687CC486E77263C3418C757522D54F84B0359236ABBBD4ACD20DC297FDCA66808");
523 try std.testing.expectEqualStrings(try std.fmt.bufPrint(&buf, "{X}", .{&sig.toBytes()}), "10A442B4A80CC4225B154F43BEF28D2472CA80221951262EB8E0DF9091575E2687CC486E77263C3418C757522D54F84B0359236ABBBD4ACD20DC297FDCA66808");
524524 try sig.verify("test", key_pair.public_key);
525525 try std.testing.expectError(error.SignatureVerificationFailed, sig.verify("TEST", key_pair.public_key));
526526}
lib/std/crypto/25519/edwards25519.zig+1-1
......@@ -546,7 +546,7 @@ test "packing/unpacking" {
546546 var b = Edwards25519.basePoint;
547547 const pk = try b.mul(s);
548548 var buf: [128]u8 = undefined;
549 try std.testing.expectEqualStrings(try std.fmt.bufPrint(&buf, "{s}", .{std.fmt.fmtSliceHexUpper(&pk.toBytes())}), "074BC7E0FCBD587FDBC0969444245FADC562809C8F6E97E949AF62484B5B81A6");
549 try std.testing.expectEqualStrings(try std.fmt.bufPrint(&buf, "{X}", .{&pk.toBytes()}), "074BC7E0FCBD587FDBC0969444245FADC562809C8F6E97E949AF62484B5B81A6");
550550
551551 const small_order_ss: [7][32]u8 = .{
552552 .{
lib/std/crypto/25519/ristretto255.zig+4-4
......@@ -175,21 +175,21 @@ pub const Ristretto255 = struct {
175175test "ristretto255" {
176176 const p = Ristretto255.basePoint;
177177 var buf: [256]u8 = undefined;
178 try std.testing.expectEqualStrings(try std.fmt.bufPrint(&buf, "{s}", .{std.fmt.fmtSliceHexUpper(&p.toBytes())}), "E2F2AE0A6ABC4E71A884A961C500515F58E30B6AA582DD8DB6A65945E08D2D76");
178 try std.testing.expectEqualStrings(try std.fmt.bufPrint(&buf, "{X}", .{&p.toBytes()}), "E2F2AE0A6ABC4E71A884A961C500515F58E30B6AA582DD8DB6A65945E08D2D76");
179179
180180 var r: [Ristretto255.encoded_length]u8 = undefined;
181181 _ = try fmt.hexToBytes(r[0..], "6a493210f7499cd17fecb510ae0cea23a110e8d5b901f8acadd3095c73a3b919");
182182 var q = try Ristretto255.fromBytes(r);
183183 q = q.dbl().add(p);
184 try std.testing.expectEqualStrings(try std.fmt.bufPrint(&buf, "{s}", .{std.fmt.fmtSliceHexUpper(&q.toBytes())}), "E882B131016B52C1D3337080187CF768423EFCCBB517BB495AB812C4160FF44E");
184 try std.testing.expectEqualStrings(try std.fmt.bufPrint(&buf, "{X}", .{&q.toBytes()}), "E882B131016B52C1D3337080187CF768423EFCCBB517BB495AB812C4160FF44E");
185185
186186 const s = [_]u8{15} ++ [_]u8{0} ** 31;
187187 const w = try p.mul(s);
188 try std.testing.expectEqualStrings(try std.fmt.bufPrint(&buf, "{s}", .{std.fmt.fmtSliceHexUpper(&w.toBytes())}), "E0C418F7C8D9C4CDD7395B93EA124F3AD99021BB681DFC3302A9D99A2E53E64E");
188 try std.testing.expectEqualStrings(try std.fmt.bufPrint(&buf, "{X}", .{&w.toBytes()}), "E0C418F7C8D9C4CDD7395B93EA124F3AD99021BB681DFC3302A9D99A2E53E64E");
189189
190190 try std.testing.expect(p.dbl().dbl().dbl().dbl().equivalent(w.add(p)));
191191
192192 const h = [_]u8{69} ** 32 ++ [_]u8{42} ** 32;
193193 const ph = Ristretto255.fromUniform(h);
194 try std.testing.expectEqualStrings(try std.fmt.bufPrint(&buf, "{s}", .{std.fmt.fmtSliceHexUpper(&ph.toBytes())}), "DCCA54E037A4311EFBEEF413ACD21D35276518970B7A61DC88F8587B493D5E19");
194 try std.testing.expectEqualStrings(try std.fmt.bufPrint(&buf, "{X}", .{&ph.toBytes()}), "DCCA54E037A4311EFBEEF413ACD21D35276518970B7A61DC88F8587B493D5E19");
195195}
lib/std/crypto/25519/scalar.zig+3-3
......@@ -850,10 +850,10 @@ test "scalar25519" {
850850 var y = x.toBytes();
851851 try rejectNonCanonical(y);
852852 var buf: [128]u8 = undefined;
853 try std.testing.expectEqualStrings(try std.fmt.bufPrint(&buf, "{s}", .{std.fmt.fmtSliceHexUpper(&y)}), "1E979B917937F3DE71D18077F961F6CEFF01030405060708010203040506070F");
853 try std.testing.expectEqualStrings(try std.fmt.bufPrint(&buf, "{X}", .{&y}), "1E979B917937F3DE71D18077F961F6CEFF01030405060708010203040506070F");
854854
855855 const reduced = reduce(field_order_s);
856 try std.testing.expectEqualStrings(try std.fmt.bufPrint(&buf, "{s}", .{std.fmt.fmtSliceHexUpper(&reduced)}), "0000000000000000000000000000000000000000000000000000000000000000");
856 try std.testing.expectEqualStrings(try std.fmt.bufPrint(&buf, "{X}", .{&reduced}), "0000000000000000000000000000000000000000000000000000000000000000");
857857}
858858
859859test "non-canonical scalar25519" {
......@@ -867,7 +867,7 @@ test "mulAdd overflow check" {
867867 const c: [32]u8 = [_]u8{0xff} ** 32;
868868 const x = mulAdd(a, b, c);
869869 var buf: [128]u8 = undefined;
870 try std.testing.expectEqualStrings(try std.fmt.bufPrint(&buf, "{s}", .{std.fmt.fmtSliceHexUpper(&x)}), "D14DF91389432C25AD60FF9791B9FD1D67BEF517D273ECCE3D9A307C1B419903");
870 try std.testing.expectEqualStrings(try std.fmt.bufPrint(&buf, "{X}", .{&x}), "D14DF91389432C25AD60FF9791B9FD1D67BEF517D273ECCE3D9A307C1B419903");
871871}
872872
873873test "scalar field inversion" {
lib/std/crypto/chacha20.zig+2-2
......@@ -1145,7 +1145,7 @@ test "xchacha20" {
11451145 var c: [m.len]u8 = undefined;
11461146 XChaCha20IETF.xor(c[0..], m[0..], 0, key, nonce);
11471147 var buf: [2 * c.len]u8 = undefined;
1148 try testing.expectEqualStrings(try std.fmt.bufPrint(&buf, "{s}", .{std.fmt.fmtSliceHexUpper(&c)}), "E0A1BCF939654AFDBDC1746EC49832647C19D891F0D1A81FC0C1703B4514BDEA584B512F6908C2C5E9DD18D5CBC1805DE5803FE3B9CA5F193FB8359E91FAB0C3BB40309A292EB1CF49685C65C4A3ADF4F11DB0CD2B6B67FBC174BC2E860E8F769FD3565BBFAD1C845E05A0FED9BE167C240D");
1148 try testing.expectEqualStrings(try std.fmt.bufPrint(&buf, "{X}", .{&c}), "E0A1BCF939654AFDBDC1746EC49832647C19D891F0D1A81FC0C1703B4514BDEA584B512F6908C2C5E9DD18D5CBC1805DE5803FE3B9CA5F193FB8359E91FAB0C3BB40309A292EB1CF49685C65C4A3ADF4F11DB0CD2B6B67FBC174BC2E860E8F769FD3565BBFAD1C845E05A0FED9BE167C240D");
11491149 }
11501150 {
11511151 const ad = "Additional data";
......@@ -1154,7 +1154,7 @@ test "xchacha20" {
11541154 var out: [m.len]u8 = undefined;
11551155 try XChaCha20Poly1305.decrypt(out[0..], c[0..m.len], c[m.len..].*, ad, nonce, key);
11561156 var buf: [2 * c.len]u8 = undefined;
1157 try testing.expectEqualStrings(try std.fmt.bufPrint(&buf, "{s}", .{std.fmt.fmtSliceHexUpper(&c)}), "994D2DD32333F48E53650C02C7A2ABB8E018B0836D7175AEC779F52E961780768F815C58F1AA52D211498DB89B9216763F569C9433A6BBFCEFB4D4A49387A4C5207FBB3B5A92B5941294DF30588C6740D39DC16FA1F0E634F7246CF7CDCB978E44347D89381B7A74EB7084F754B90BDE9AAF5A94B8F2A85EFD0B50692AE2D425E234");
1157 try testing.expectEqualStrings(try std.fmt.bufPrint(&buf, "{X}", .{&c}), "994D2DD32333F48E53650C02C7A2ABB8E018B0836D7175AEC779F52E961780768F815C58F1AA52D211498DB89B9216763F569C9433A6BBFCEFB4D4A49387A4C5207FBB3B5A92B5941294DF30588C6740D39DC16FA1F0E634F7246CF7CDCB978E44347D89381B7A74EB7084F754B90BDE9AAF5A94B8F2A85EFD0B50692AE2D425E234");
11581158 try testing.expectEqualSlices(u8, out[0..], m);
11591159 c[0] +%= 1;
11601160 try testing.expectError(error.AuthenticationFailed, XChaCha20Poly1305.decrypt(out[0..], c[0..m.len], c[m.len..].*, ad, nonce, key));
lib/std/crypto/ml_kem.zig+6-6
......@@ -1741,7 +1741,7 @@ test "NIST KAT test" {
17411741 for (0..100) |i| {
17421742 g.fill(&seed);
17431743 try std.fmt.format(fw, "count = {}\n", .{i});
1744 try std.fmt.format(fw, "seed = {s}\n", .{std.fmt.fmtSliceHexUpper(&seed)});
1744 try std.fmt.format(fw, "seed = {X}\n", .{&seed});
17451745 var g2 = NistDRBG.init(seed);
17461746
17471747 // This is not equivalent to g2.fill(kseed[:]). As the reference
......@@ -1756,16 +1756,16 @@ test "NIST KAT test" {
17561756 const e = kp.public_key.encaps(eseed);
17571757 const ss2 = try kp.secret_key.decaps(&e.ciphertext);
17581758 try testing.expectEqual(ss2, e.shared_secret);
1759 try std.fmt.format(fw, "pk = {s}\n", .{std.fmt.fmtSliceHexUpper(&kp.public_key.toBytes())});
1760 try std.fmt.format(fw, "sk = {s}\n", .{std.fmt.fmtSliceHexUpper(&kp.secret_key.toBytes())});
1761 try std.fmt.format(fw, "ct = {s}\n", .{std.fmt.fmtSliceHexUpper(&e.ciphertext)});
1762 try std.fmt.format(fw, "ss = {s}\n\n", .{std.fmt.fmtSliceHexUpper(&e.shared_secret)});
1759 try std.fmt.format(fw, "pk = {X}\n", .{&kp.public_key.toBytes()});
1760 try std.fmt.format(fw, "sk = {X}\n", .{&kp.secret_key.toBytes()});
1761 try std.fmt.format(fw, "ct = {X}\n", .{&e.ciphertext});
1762 try std.fmt.format(fw, "ss = {X}\n\n", .{&e.shared_secret});
17631763 }
17641764
17651765 var out: [32]u8 = undefined;
17661766 f.final(&out);
17671767 var outHex: [64]u8 = undefined;
1768 _ = try std.fmt.bufPrint(&outHex, "{s}", .{std.fmt.fmtSliceHexLower(&out)});
1768 _ = try std.fmt.bufPrint(&outHex, "{x}", .{&out});
17691769 try testing.expectEqual(outHex, modeHash[1].*);
17701770 }
17711771}
lib/std/crypto/tls/Client.zig+3-3
......@@ -1513,10 +1513,10 @@ fn logSecrets(key_log_file: std.fs.File, context: anytype, secrets: anytype) voi
15131513 defer if (locked) key_log_file.unlock();
15141514 key_log_file.seekFromEnd(0) catch {};
15151515 inline for (@typeInfo(@TypeOf(secrets)).@"struct".fields) |field| key_log_file.writer().print("{s}" ++
1516 (if (@hasField(@TypeOf(context), "counter")) "_{d}" else "") ++ " {} {}\n", .{field.name} ++
1516 (if (@hasField(@TypeOf(context), "counter")) "_{d}" else "") ++ " {x} {x}\n", .{field.name} ++
15171517 (if (@hasField(@TypeOf(context), "counter")) .{context.counter} else .{}) ++ .{
1518 std.fmt.fmtSliceHexLower(context.client_random),
1519 std.fmt.fmtSliceHexLower(@field(secrets, field.name)),
1518 context.client_random,
1519 @field(secrets, field.name),
15201520 }) catch {};
15211521}
15221522
lib/std/debug.zig+110-99
......@@ -204,13 +204,23 @@ pub fn unlockStdErr() void {
204204 std.Progress.unlockStdErr();
205205}
206206
207/// Allows the caller to freely write to stderr until `unlockStdErr` is called.
208///
209/// During the lock, any `std.Progress` information is cleared from the terminal.
210///
211/// Returns a `std.io.BufferedWriter` with empty buffer, meaning that it is
212/// in fact unbuffered and does not need to be flushed.
213pub fn lockStdErr2() std.io.BufferedWriter {
214 std.Progress.lockStdErr();
215 return io.getStdErr().unbufferedWriter();
216}
217
207218/// Print to stderr, unbuffered, and silently returning on failure. Intended
208219/// for use in "printf debugging." Use `std.log` functions for proper logging.
209220pub fn print(comptime fmt: []const u8, args: anytype) void {
210 lockStdErr();
221 var bw = lockStdErr2();
211222 defer unlockStdErr();
212 const stderr = io.getStdErr().writer();
213 nosuspend stderr.print(fmt, args) catch return;
223 nosuspend bw.print(fmt, args) catch return;
214224}
215225
216226pub fn getStderrMutex() *std.Thread.Mutex {
......@@ -265,7 +275,7 @@ fn dumpHexInternal(bytes: []const u8, ttyconf: std.io.tty.Config, writer: anytyp
265275 if (window.len < 16) {
266276 var missing_columns = (16 - window.len) * 3;
267277 if (window.len < 8) missing_columns += 1;
268 try writer.writeByteNTimes(' ', missing_columns);
278 try writer.splatByteAll(' ', missing_columns);
269279 }
270280
271281 // 3. Print the characters.
......@@ -313,30 +323,32 @@ test dumpHexInternal {
313323}
314324
315325/// Tries to print the current stack trace to stderr, unbuffered, and ignores any error returned.
316/// TODO multithreaded awareness
317326pub fn dumpCurrentStackTrace(start_addr: ?usize) void {
318 nosuspend {
319 if (builtin.target.cpu.arch.isWasm()) {
320 if (native_os == .wasi) {
321 const stderr = io.getStdErr().writer();
322 stderr.print("Unable to dump stack trace: not implemented for Wasm\n", .{}) catch return;
323 }
324 return;
325 }
326 const stderr = io.getStdErr().writer();
327 if (builtin.strip_debug_info) {
328 stderr.print("Unable to dump stack trace: debug info stripped\n", .{}) catch return;
329 return;
327 var stderr = lockStdErr2();
328 defer unlockStdErr();
329 nosuspend dumpCurrentStackTraceToWriter(start_addr, &stderr) catch return;
330}
331
332/// Prints the current stack trace to the provided writer.
333pub fn dumpCurrentStackTraceToWriter(start_addr: ?usize, writer: *std.io.BufferedWriter) !void {
334 if (builtin.target.cpu.arch.isWasm()) {
335 if (native_os == .wasi) {
336 try writer.writeAll("Unable to dump stack trace: not implemented for Wasm\n");
330337 }
331 const debug_info = getSelfDebugInfo() catch |err| {
332 stderr.print("Unable to dump stack trace: Unable to open debug info: {s}\n", .{@errorName(err)}) catch return;
333 return;
334 };
335 writeCurrentStackTrace(stderr, debug_info, io.tty.detectConfig(io.getStdErr()), start_addr) catch |err| {
336 stderr.print("Unable to dump stack trace: {s}\n", .{@errorName(err)}) catch return;
337 return;
338 };
338 return;
339339 }
340 if (builtin.strip_debug_info) {
341 try writer.writeAll("Unable to dump stack trace: debug info stripped\n");
342 return;
343 }
344 const debug_info = getSelfDebugInfo() catch |err| {
345 try writer.print("Unable to dump stack trace: Unable to open debug info: {s}\n", .{@errorName(err)});
346 return;
347 };
348 writeCurrentStackTrace(writer, debug_info, io.tty.detectConfig(io.getStdErr()), start_addr) catch |err| {
349 try writer.print("Unable to dump stack trace: {s}\n", .{@errorName(err)});
350 return;
351 };
340352}
341353
342354pub const have_ucontext = posix.ucontext_t != void;
......@@ -402,16 +414,14 @@ pub inline fn getContext(context: *ThreadContext) bool {
402414/// Tries to print the stack trace starting from the supplied base pointer to stderr,
403415/// unbuffered, and ignores any error returned.
404416/// TODO multithreaded awareness
405pub fn dumpStackTraceFromBase(context: *ThreadContext) void {
417pub fn dumpStackTraceFromBase(context: *ThreadContext, stderr: *std.io.BufferedWriter) void {
406418 nosuspend {
407419 if (builtin.target.cpu.arch.isWasm()) {
408420 if (native_os == .wasi) {
409 const stderr = io.getStdErr().writer();
410421 stderr.print("Unable to dump stack trace: not implemented for Wasm\n", .{}) catch return;
411422 }
412423 return;
413424 }
414 const stderr = io.getStdErr().writer();
415425 if (builtin.strip_debug_info) {
416426 stderr.print("Unable to dump stack trace: debug info stripped\n", .{}) catch return;
417427 return;
......@@ -510,21 +520,23 @@ pub fn dumpStackTrace(stack_trace: std.builtin.StackTrace) void {
510520 nosuspend {
511521 if (builtin.target.cpu.arch.isWasm()) {
512522 if (native_os == .wasi) {
513 const stderr = io.getStdErr().writer();
514 stderr.print("Unable to dump stack trace: not implemented for Wasm\n", .{}) catch return;
523 var stderr = lockStdErr2();
524 defer unlockStdErr();
525 stderr.writeAll("Unable to dump stack trace: not implemented for Wasm\n") catch return;
515526 }
516527 return;
517528 }
518 const stderr = io.getStdErr().writer();
529 var stderr = lockStdErr2();
530 defer unlockStdErr();
519531 if (builtin.strip_debug_info) {
520 stderr.print("Unable to dump stack trace: debug info stripped\n", .{}) catch return;
532 stderr.writeAll("Unable to dump stack trace: debug info stripped\n") catch return;
521533 return;
522534 }
523535 const debug_info = getSelfDebugInfo() catch |err| {
524536 stderr.print("Unable to dump stack trace: Unable to open debug info: {s}\n", .{@errorName(err)}) catch return;
525537 return;
526538 };
527 writeStackTrace(stack_trace, stderr, debug_info, io.tty.detectConfig(io.getStdErr())) catch |err| {
539 writeStackTrace(stack_trace, &stderr, debug_info, io.tty.detectConfig(io.getStdErr())) catch |err| {
528540 stderr.print("Unable to dump stack trace: {s}\n", .{@errorName(err)}) catch return;
529541 return;
530542 };
......@@ -573,14 +585,14 @@ pub fn panicExtra(
573585 const size = 0x1000;
574586 const trunc_msg = "(msg truncated)";
575587 var buf: [size + trunc_msg.len]u8 = undefined;
588 var bw: std.io.BufferedWriter = undefined;
589 bw.initFixed(buf[0..size]);
576590 // a minor annoyance with this is that it will result in the NoSpaceLeft
577591 // error being part of the @panic stack trace (but that error should
578592 // only happen rarely)
579 const msg = std.fmt.bufPrint(buf[0..size], format, args) catch |err| switch (err) {
580 error.NoSpaceLeft => blk: {
581 @memcpy(buf[size..], trunc_msg);
582 break :blk &buf;
583 },
593 const msg = if (bw.print(format, args)) |_| bw.getWritten() else |_| blk: {
594 @memcpy(buf[size..], trunc_msg);
595 break :blk &buf;
584596 };
585597 std.builtin.panic.call(msg, ret_addr);
586598}
......@@ -675,10 +687,9 @@ pub fn defaultPanic(
675687 _ = panicking.fetchAdd(1, .seq_cst);
676688
677689 {
678 lockStdErr();
690 var stderr = lockStdErr2();
679691 defer unlockStdErr();
680692
681 const stderr = io.getStdErr().writer();
682693 if (builtin.single_threaded) {
683694 stderr.print("panic: ", .{}) catch posix.abort();
684695 } else {
......@@ -688,7 +699,7 @@ pub fn defaultPanic(
688699 stderr.print("{s}\n", .{msg}) catch posix.abort();
689700
690701 if (@errorReturnTrace()) |t| dumpStackTrace(t.*);
691 dumpCurrentStackTrace(first_trace_addr orelse @returnAddress());
702 dumpCurrentStackTraceToWriter(first_trace_addr orelse @returnAddress(), &stderr) catch {};
692703 }
693704
694705 waitForOtherThreadToFinishPanicking();
......@@ -723,7 +734,7 @@ fn waitForOtherThreadToFinishPanicking() void {
723734
724735pub fn writeStackTrace(
725736 stack_trace: std.builtin.StackTrace,
726 out_stream: anytype,
737 writer: *std.io.BufferedWriter,
727738 debug_info: *SelfInfo,
728739 tty_config: io.tty.Config,
729740) !void {
......@@ -736,15 +747,15 @@ pub fn writeStackTrace(
736747 frame_index = (frame_index + 1) % stack_trace.instruction_addresses.len;
737748 }) {
738749 const return_address = stack_trace.instruction_addresses[frame_index];
739 try printSourceAtAddress(debug_info, out_stream, return_address - 1, tty_config);
750 try printSourceAtAddress(debug_info, writer, return_address - 1, tty_config);
740751 }
741752
742753 if (stack_trace.index > stack_trace.instruction_addresses.len) {
743754 const dropped_frames = stack_trace.index - stack_trace.instruction_addresses.len;
744755
745 tty_config.setColor(out_stream, .bold) catch {};
746 try out_stream.print("({d} additional stack frames skipped...)\n", .{dropped_frames});
747 tty_config.setColor(out_stream, .reset) catch {};
756 tty_config.setColor(writer, .bold) catch {};
757 try writer.print("({d} additional stack frames skipped...)\n", .{dropped_frames});
758 tty_config.setColor(writer, .reset) catch {};
748759 }
749760}
750761
......@@ -954,7 +965,7 @@ pub const StackIterator = struct {
954965};
955966
956967pub fn writeCurrentStackTrace(
957 out_stream: anytype,
968 writer: *std.io.BufferedWriter,
958969 debug_info: *SelfInfo,
959970 tty_config: io.tty.Config,
960971 start_addr: ?usize,
......@@ -962,7 +973,7 @@ pub fn writeCurrentStackTrace(
962973 if (native_os == .windows) {
963974 var context: ThreadContext = undefined;
964975 assert(getContext(&context));
965 return writeStackTraceWindows(out_stream, debug_info, tty_config, &context, start_addr);
976 return writeStackTraceWindows(writer, debug_info, tty_config, &context, start_addr);
966977 }
967978 var context: ThreadContext = undefined;
968979 const has_context = getContext(&context);
......@@ -973,7 +984,7 @@ pub fn writeCurrentStackTrace(
973984 defer it.deinit();
974985
975986 while (it.next()) |return_address| {
976 printLastUnwindError(&it, debug_info, out_stream, tty_config);
987 printLastUnwindError(&it, debug_info, writer, tty_config);
977988
978989 // On arm64 macOS, the address of the last frame is 0x0 rather than 0x1 as on x86_64 macOS,
979990 // therefore, we do a check for `return_address == 0` before subtracting 1 from it to avoid
......@@ -981,8 +992,8 @@ pub fn writeCurrentStackTrace(
981992 // condition on the subsequent iteration and return `null` thus terminating the loop.
982993 // same behaviour for x86-windows-msvc
983994 const address = return_address -| 1;
984 try printSourceAtAddress(debug_info, out_stream, address, tty_config);
985 } else printLastUnwindError(&it, debug_info, out_stream, tty_config);
995 try printSourceAtAddress(debug_info, writer, address, tty_config);
996 } else printLastUnwindError(&it, debug_info, writer, tty_config);
986997}
987998
988999pub noinline fn walkStackWindows(addresses: []usize, existing_context: ?*const windows.CONTEXT) usize {
......@@ -1042,7 +1053,7 @@ pub noinline fn walkStackWindows(addresses: []usize, existing_context: ?*const w
10421053}
10431054
10441055pub fn writeStackTraceWindows(
1045 out_stream: anytype,
1056 writer: *std.io.BufferedWriter,
10461057 debug_info: *SelfInfo,
10471058 tty_config: io.tty.Config,
10481059 context: *const windows.CONTEXT,
......@@ -1058,14 +1069,14 @@ pub fn writeStackTraceWindows(
10581069 return;
10591070 } else 0;
10601071 for (addrs[start_i..]) |addr| {
1061 try printSourceAtAddress(debug_info, out_stream, addr - 1, tty_config);
1072 try printSourceAtAddress(debug_info, writer, addr - 1, tty_config);
10621073 }
10631074}
10641075
1065fn printUnknownSource(debug_info: *SelfInfo, out_stream: anytype, address: usize, tty_config: io.tty.Config) !void {
1076fn printUnknownSource(debug_info: *SelfInfo, writer: *std.io.BufferedWriter, address: usize, tty_config: io.tty.Config) !void {
10661077 const module_name = debug_info.getModuleNameForAddress(address);
10671078 return printLineInfo(
1068 out_stream,
1079 writer,
10691080 null,
10701081 address,
10711082 "???",
......@@ -1075,38 +1086,38 @@ fn printUnknownSource(debug_info: *SelfInfo, out_stream: anytype, address: usize
10751086 );
10761087}
10771088
1078fn printLastUnwindError(it: *StackIterator, debug_info: *SelfInfo, out_stream: anytype, tty_config: io.tty.Config) void {
1089fn printLastUnwindError(it: *StackIterator, debug_info: *SelfInfo, writer: *std.io.BufferedWriter, tty_config: io.tty.Config) void {
10791090 if (!have_ucontext) return;
10801091 if (it.getLastError()) |unwind_error| {
1081 printUnwindError(debug_info, out_stream, unwind_error.address, unwind_error.err, tty_config) catch {};
1092 printUnwindError(debug_info, writer, unwind_error.address, unwind_error.err, tty_config) catch {};
10821093 }
10831094}
10841095
1085fn printUnwindError(debug_info: *SelfInfo, out_stream: anytype, address: usize, err: UnwindError, tty_config: io.tty.Config) !void {
1096fn printUnwindError(debug_info: *SelfInfo, writer: *std.io.BufferedWriter, address: usize, err: UnwindError, tty_config: io.tty.Config) !void {
10861097 const module_name = debug_info.getModuleNameForAddress(address) orelse "???";
1087 try tty_config.setColor(out_stream, .dim);
1098 try tty_config.setColor(writer, .dim);
10881099 if (err == error.MissingDebugInfo) {
1089 try out_stream.print("Unwind information for `{s}:0x{x}` was not available, trace may be incomplete\n\n", .{ module_name, address });
1100 try writer.print("Unwind information for `{s}:0x{x}` was not available, trace may be incomplete\n\n", .{ module_name, address });
10901101 } else {
1091 try out_stream.print("Unwind error at address `{s}:0x{x}` ({}), trace may be incomplete\n\n", .{ module_name, address, err });
1102 try writer.print("Unwind error at address `{s}:0x{x}` ({}), trace may be incomplete\n\n", .{ module_name, address, err });
10921103 }
1093 try tty_config.setColor(out_stream, .reset);
1104 try tty_config.setColor(writer, .reset);
10941105}
10951106
1096pub fn printSourceAtAddress(debug_info: *SelfInfo, out_stream: anytype, address: usize, tty_config: io.tty.Config) !void {
1107pub fn printSourceAtAddress(debug_info: *SelfInfo, writer: *std.io.BufferedWriter, address: usize, tty_config: io.tty.Config) !void {
10971108 const module = debug_info.getModuleForAddress(address) catch |err| switch (err) {
1098 error.MissingDebugInfo, error.InvalidDebugInfo => return printUnknownSource(debug_info, out_stream, address, tty_config),
1109 error.MissingDebugInfo, error.InvalidDebugInfo => return printUnknownSource(debug_info, writer, address, tty_config),
10991110 else => return err,
11001111 };
11011112
11021113 const symbol_info = module.getSymbolAtAddress(debug_info.allocator, address) catch |err| switch (err) {
1103 error.MissingDebugInfo, error.InvalidDebugInfo => return printUnknownSource(debug_info, out_stream, address, tty_config),
1114 error.MissingDebugInfo, error.InvalidDebugInfo => return printUnknownSource(debug_info, writer, address, tty_config),
11041115 else => return err,
11051116 };
11061117 defer if (symbol_info.source_location) |sl| debug_info.allocator.free(sl.file_name);
11071118
11081119 return printLineInfo(
1109 out_stream,
1120 writer,
11101121 symbol_info.source_location,
11111122 address,
11121123 symbol_info.name,
......@@ -1117,7 +1128,7 @@ pub fn printSourceAtAddress(debug_info: *SelfInfo, out_stream: anytype, address:
11171128}
11181129
11191130fn printLineInfo(
1120 out_stream: anytype,
1131 writer: *std.io.BufferedWriter,
11211132 source_location: ?SourceLocation,
11221133 address: usize,
11231134 symbol_name: []const u8,
......@@ -1126,34 +1137,34 @@ fn printLineInfo(
11261137 comptime printLineFromFile: anytype,
11271138) !void {
11281139 nosuspend {
1129 try tty_config.setColor(out_stream, .bold);
1140 try tty_config.setColor(writer, .bold);
11301141
11311142 if (source_location) |*sl| {
1132 try out_stream.print("{s}:{d}:{d}", .{ sl.file_name, sl.line, sl.column });
1143 try writer.print("{s}:{d}:{d}", .{ sl.file_name, sl.line, sl.column });
11331144 } else {
1134 try out_stream.writeAll("???:?:?");
1145 try writer.writeAll("???:?:?");
11351146 }
11361147
1137 try tty_config.setColor(out_stream, .reset);
1138 try out_stream.writeAll(": ");
1139 try tty_config.setColor(out_stream, .dim);
1140 try out_stream.print("0x{x} in {s} ({s})", .{ address, symbol_name, compile_unit_name });
1141 try tty_config.setColor(out_stream, .reset);
1142 try out_stream.writeAll("\n");
1148 try tty_config.setColor(writer, .reset);
1149 try writer.writeAll(": ");
1150 try tty_config.setColor(writer, .dim);
1151 try writer.print("0x{x} in {s} ({s})", .{ address, symbol_name, compile_unit_name });
1152 try tty_config.setColor(writer, .reset);
1153 try writer.writeAll("\n");
11431154
11441155 // Show the matching source code line if possible
11451156 if (source_location) |sl| {
1146 if (printLineFromFile(out_stream, sl)) {
1157 if (printLineFromFile(writer, sl)) {
11471158 if (sl.column > 0) {
11481159 // The caret already takes one char
11491160 const space_needed = @as(usize, @intCast(sl.column - 1));
11501161
1151 try out_stream.writeByteNTimes(' ', space_needed);
1152 try tty_config.setColor(out_stream, .green);
1153 try out_stream.writeAll("^");
1154 try tty_config.setColor(out_stream, .reset);
1162 try writer.splatByteAll(' ', space_needed);
1163 try tty_config.setColor(writer, .green);
1164 try writer.writeAll("^");
1165 try tty_config.setColor(writer, .reset);
11551166 }
1156 try out_stream.writeAll("\n");
1167 try writer.writeAll("\n");
11571168 } else |err| switch (err) {
11581169 error.EndOfFile, error.FileNotFound => {},
11591170 error.BadPathName => {},
......@@ -1164,7 +1175,7 @@ fn printLineInfo(
11641175 }
11651176}
11661177
1167fn printLineFromFileAnyOs(out_stream: anytype, source_location: SourceLocation) !void {
1178fn printLineFromFileAnyOs(writer: *std.io.BufferedWriter, source_location: SourceLocation) !void {
11681179 // Need this to always block even in async I/O mode, because this could potentially
11691180 // be called from e.g. the event loop code crashing.
11701181 var f = try fs.cwd().openFile(source_location.file_name, .{});
......@@ -1197,24 +1208,24 @@ fn printLineFromFileAnyOs(out_stream: anytype, source_location: SourceLocation)
11971208 if (mem.indexOfScalar(u8, slice, '\n')) |pos| {
11981209 const line = slice[0 .. pos + 1];
11991210 mem.replaceScalar(u8, line, '\t', ' ');
1200 return out_stream.writeAll(line);
1211 return writer.writeAll(line);
12011212 } else { // Line is the last inside the buffer, and requires another read to find delimiter. Alternatively the file ends.
12021213 mem.replaceScalar(u8, slice, '\t', ' ');
1203 try out_stream.writeAll(slice);
1214 try writer.writeAll(slice);
12041215 while (amt_read == buf.len) {
12051216 amt_read = try f.read(buf[0..]);
12061217 if (mem.indexOfScalar(u8, buf[0..amt_read], '\n')) |pos| {
12071218 const line = buf[0 .. pos + 1];
12081219 mem.replaceScalar(u8, line, '\t', ' ');
1209 return out_stream.writeAll(line);
1220 return writer.writeAll(line);
12101221 } else {
12111222 const line = buf[0..amt_read];
12121223 mem.replaceScalar(u8, line, '\t', ' ');
1213 try out_stream.writeAll(line);
1224 try writer.writeAll(line);
12141225 }
12151226 }
12161227 // Make sure printing last line of file inserts extra newline
1217 try out_stream.writeByte('\n');
1228 try writer.writeByte('\n');
12181229 }
12191230}
12201231
......@@ -1274,9 +1285,9 @@ test printLineFromFileAnyOs {
12741285
12751286 const overlap = 10;
12761287 var writer = file.writer();
1277 try writer.writeByteNTimes('a', std.heap.page_size_min - overlap);
1288 try writer.splatByteAll('a', std.heap.page_size_min - overlap);
12781289 try writer.writeByte('\n');
1279 try writer.writeByteNTimes('a', overlap);
1290 try writer.splatByteAll('a', overlap);
12801291
12811292 try printLineFromFileAnyOs(output_stream, .{ .file_name = path, .line = 2, .column = 0 });
12821293 try expectEqualStrings(("a" ** overlap) ++ "\n", output.items);
......@@ -1289,7 +1300,7 @@ test printLineFromFileAnyOs {
12891300 defer allocator.free(path);
12901301
12911302 var writer = file.writer();
1292 try writer.writeByteNTimes('a', std.heap.page_size_max);
1303 try writer.splatByteAll('a', std.heap.page_size_max);
12931304
12941305 try printLineFromFileAnyOs(output_stream, .{ .file_name = path, .line = 1, .column = 0 });
12951306 try expectEqualStrings(("a" ** std.heap.page_size_max) ++ "\n", output.items);
......@@ -1302,7 +1313,7 @@ test printLineFromFileAnyOs {
13021313 defer allocator.free(path);
13031314
13041315 var writer = file.writer();
1305 try writer.writeByteNTimes('a', 3 * std.heap.page_size_max);
1316 try writer.splatByteAll('a', 3 * std.heap.page_size_max);
13061317
13071318 try expectError(error.EndOfFile, printLineFromFileAnyOs(output_stream, .{ .file_name = path, .line = 2, .column = 0 }));
13081319
......@@ -1328,7 +1339,7 @@ test printLineFromFileAnyOs {
13281339
13291340 var writer = file.writer();
13301341 const real_file_start = 3 * std.heap.page_size_min;
1331 try writer.writeByteNTimes('\n', real_file_start);
1342 try writer.splatByteAll('\n', real_file_start);
13321343 try writer.writeAll("abc\ndef");
13331344
13341345 try printLineFromFileAnyOs(output_stream, .{ .file_name = path, .line = real_file_start + 1, .column = 0 });
......@@ -1461,7 +1472,7 @@ fn handleSegfaultPosix(sig: i32, info: *const posix.siginfo_t, ctx_ptr: ?*anyopa
14611472}
14621473
14631474fn dumpSegfaultInfoPosix(sig: i32, code: i32, addr: usize, ctx_ptr: ?*anyopaque) void {
1464 const stderr = io.getStdErr().writer();
1475 var stderr = io.getStdErr().unbufferedWriter();
14651476 _ = switch (sig) {
14661477 posix.SIG.SEGV => if (native_arch == .x86_64 and native_os == .linux and code == 128) // SI_KERNEL
14671478 // x86_64 doesn't have a full 64-bit virtual address space.
......@@ -1471,7 +1482,7 @@ fn dumpSegfaultInfoPosix(sig: i32, code: i32, addr: usize, ctx_ptr: ?*anyopaque)
14711482 // but can also happen when no addressable memory is involved;
14721483 // for example when reading/writing model-specific registers
14731484 // by executing `rdmsr` or `wrmsr` in user-space (unprivileged mode).
1474 stderr.print("General protection exception (no address available)\n", .{})
1485 stderr.writeAll("General protection exception (no address available)\n")
14751486 else
14761487 stderr.print("Segmentation fault at address 0x{x}\n", .{addr}),
14771488 posix.SIG.ILL => stderr.print("Illegal instruction at address 0x{x}\n", .{addr}),
......@@ -1509,7 +1520,7 @@ fn dumpSegfaultInfoPosix(sig: i32, code: i32, addr: usize, ctx_ptr: ?*anyopaque)
15091520 }, @ptrCast(ctx)).__mcontext_data;
15101521 }
15111522 relocateContext(&new_ctx);
1512 dumpStackTraceFromBase(&new_ctx);
1523 dumpStackTraceFromBase(&new_ctx, &stderr);
15131524 },
15141525 else => {},
15151526 }
......@@ -1557,7 +1568,7 @@ fn handleSegfaultWindowsExtra(info: *windows.EXCEPTION_POINTERS, msg: u8, label:
15571568}
15581569
15591570fn dumpSegfaultInfoWindows(info: *windows.EXCEPTION_POINTERS, msg: u8, label: ?[]const u8) void {
1560 const stderr = io.getStdErr().writer();
1571 var stderr = io.getStdErr().unbufferedWriter();
15611572 _ = switch (msg) {
15621573 0 => stderr.print("{s}\n", .{label.?}),
15631574 1 => stderr.print("Segmentation fault at address 0x{x}\n", .{info.ExceptionRecord.ExceptionInformation[1]}),
......@@ -1565,7 +1576,7 @@ fn dumpSegfaultInfoWindows(info: *windows.EXCEPTION_POINTERS, msg: u8, label: ?[
15651576 else => unreachable,
15661577 } catch posix.abort();
15671578
1568 dumpStackTraceFromBase(info.ContextRecord);
1579 dumpStackTraceFromBase(info.ContextRecord, &stderr);
15691580}
15701581
15711582pub fn dumpStackPointerAddr(prefix: []const u8) void {
......@@ -1688,7 +1699,7 @@ pub fn ConfigurableTrace(comptime size: usize, comptime stack_frame_count: usize
16881699 t: @This(),
16891700 comptime fmt: []const u8,
16901701 options: std.fmt.FormatOptions,
1691 writer: anytype,
1702 writer: *std.io.BufferedWriter,
16921703 ) !void {
16931704 if (fmt.len != 0) std.fmt.invalidFmtError(fmt, t);
16941705 _ = options;
lib/std/debug/Dwarf.zig+4-12
......@@ -2235,7 +2235,7 @@ pub const ElfModule = struct {
22352235
22362236 const section_bytes = try chopSlice(mapped_mem, shdr.sh_offset, shdr.sh_size);
22372237 sections[section_index.?] = if ((shdr.sh_flags & elf.SHF_COMPRESSED) > 0) blk: {
2238 var section_stream = std.io.fixedBufferStream(section_bytes);
2238 var section_stream: std.io.FixedBufferStream = .{ .buffer = section_bytes };
22392239 const section_reader = section_stream.reader();
22402240 const chdr = section_reader.readStruct(elf.Chdr) catch continue;
22412241 if (chdr.ch_type != .ZLIB) continue;
......@@ -2302,11 +2302,7 @@ pub const ElfModule = struct {
23022302 };
23032303 defer debuginfod_dir.close();
23042304
2305 const filename = std.fmt.allocPrint(
2306 gpa,
2307 "{s}/debuginfo",
2308 .{std.fmt.fmtSliceHexLower(id)},
2309 ) catch break :blk;
2305 const filename = std.fmt.allocPrint(gpa, "{x}/debuginfo", .{id}) catch break :blk;
23102306 defer gpa.free(filename);
23112307
23122308 const path: Path = .{
......@@ -2330,12 +2326,8 @@ pub const ElfModule = struct {
23302326 var id_prefix_buf: [2]u8 = undefined;
23312327 var filename_buf: [38 + extension.len]u8 = undefined;
23322328
2333 _ = std.fmt.bufPrint(&id_prefix_buf, "{s}", .{std.fmt.fmtSliceHexLower(id[0..1])}) catch unreachable;
2334 const filename = std.fmt.bufPrint(
2335 &filename_buf,
2336 "{s}" ++ extension,
2337 .{std.fmt.fmtSliceHexLower(id[1..])},
2338 ) catch break :blk;
2329 _ = std.fmt.bufPrint(&id_prefix_buf, "{x}", .{id[0..1]}) catch unreachable;
2330 const filename = std.fmt.bufPrint(&filename_buf, "{x}" ++ extension, .{id[1..]}) catch break :blk;
23392331
23402332 for (global_debug_directories) |global_directory| {
23412333 const path: Path = .{
lib/std/debug/Dwarf/call_frame.zig+2-2
......@@ -51,7 +51,7 @@ const Opcode = enum(u8) {
5151 pub const hi_user = 0x3f;
5252};
5353
54fn readBlock(stream: *std.io.FixedBufferStream([]const u8)) ![]const u8 {
54fn readBlock(stream: *std.io.FixedBufferStream) ![]const u8 {
5555 const reader = stream.reader();
5656 const block_len = try leb.readUleb128(usize, reader);
5757 if (stream.pos + block_len > stream.buffer.len) return error.InvalidOperand;
......@@ -147,7 +147,7 @@ pub const Instruction = union(Opcode) {
147147 },
148148
149149 pub fn read(
150 stream: *std.io.FixedBufferStream([]const u8),
150 stream: *std.io.FixedBufferStream,
151151 addr_size_bytes: u8,
152152 endian: std.builtin.Endian,
153153 ) !Instruction {
lib/std/debug/Dwarf/expression.zig+4-4
......@@ -178,7 +178,7 @@ pub fn StackMachine(comptime options: Options) type {
178178 }
179179 }
180180
181 pub fn readOperand(stream: *std.io.FixedBufferStream([]const u8), opcode: u8, context: Context) !?Operand {
181 pub fn readOperand(stream: *std.io.FixedBufferStream, opcode: u8, context: Context) !?Operand {
182182 const reader = stream.reader();
183183 return switch (opcode) {
184184 OP.addr => generic(try reader.readInt(addr_type, options.endian)),
......@@ -293,7 +293,7 @@ pub fn StackMachine(comptime options: Options) type {
293293 initial_value: ?usize,
294294 ) Error!?Value {
295295 if (initial_value) |i| try self.stack.append(allocator, .{ .generic = i });
296 var stream = std.io.fixedBufferStream(expression);
296 var stream: std.io.FixedBufferStream = .{ .buffer = expression };
297297 while (try self.step(&stream, allocator, context)) {}
298298 if (self.stack.items.len == 0) return null;
299299 return self.stack.items[self.stack.items.len - 1];
......@@ -302,7 +302,7 @@ pub fn StackMachine(comptime options: Options) type {
302302 /// Reads an opcode and its operands from `stream`, then executes it
303303 pub fn step(
304304 self: *Self,
305 stream: *std.io.FixedBufferStream([]const u8),
305 stream: *std.io.FixedBufferStream,
306306 allocator: std.mem.Allocator,
307307 context: Context,
308308 ) Error!bool {
......@@ -756,7 +756,7 @@ pub fn StackMachine(comptime options: Options) type {
756756 if (isOpcodeRegisterLocation(block[0])) {
757757 if (context.thread_context == null) return error.IncompleteExpressionContext;
758758
759 var block_stream = std.io.fixedBufferStream(block);
759 var block_stream: std.io.FixedBufferStream = .{ .buffer = block };
760760 const register = (try readOperand(&block_stream, block[0], context)).?.register;
761761 const value = mem.readInt(usize, (try abi.regBytes(context.thread_context.?, register, context.reg_context))[0..@sizeOf(usize)], native_endian);
762762 try self.stack.append(allocator, .{ .generic = value });
lib/std/debug/SelfInfo.zig+3-6
......@@ -2027,12 +2027,9 @@ pub const VirtualMachine = struct {
20272027
20282028 var prev_row: Row = self.current_row;
20292029
2030 var cie_stream = std.io.fixedBufferStream(cie.initial_instructions);
2031 var fde_stream = std.io.fixedBufferStream(fde.instructions);
2032 var streams = [_]*std.io.FixedBufferStream([]const u8){
2033 &cie_stream,
2034 &fde_stream,
2035 };
2030 var cie_stream: std.io.FixedBufferStream = .{ .buffer = cie.initial_instructions };
2031 var fde_stream: std.io.FixedBufferStream = .{ .buffer = fde.instructions };
2032 const streams: [2]*std.io.FixedBufferStream = .{ &cie_stream, &fde_stream };
20362033
20372034 for (&streams, 0..) |stream, i| {
20382035 while (stream.pos < stream.buffer.len) {
lib/std/fmt.zig+51-1155
......@@ -13,6 +13,8 @@ const lossyCast = math.lossyCast;
1313const expectFmt = std.testing.expectFmt;
1414const testing = std.testing;
1515
16pub const float = @import("fmt/float.zig");
17
1618pub const default_max_depth = 3;
1719
1820pub const Alignment = enum {
......@@ -24,11 +26,14 @@ pub const Alignment = enum {
2426const default_alignment = .right;
2527const default_fill_char = ' ';
2628
27pub const FormatOptions = struct {
29/// Deprecated; to be removed after 0.14.0 is tagged.
30pub const FormatOptions = Options;
31
32pub const Options = struct {
2833 precision: ?usize = null,
2934 width: ?usize = null,
3035 alignment: Alignment = default_alignment,
31 fill: u21 = default_fill_char,
36 fill: u8 = default_fill_char,
3237};
3338
3439/// Renders fmt string with args, calling `writer` with slices of bytes.
......@@ -45,9 +50,10 @@ pub const FormatOptions = struct {
4550/// - when using a field name, you are required to enclose the field name (an identifier) in square
4651/// brackets, e.g. {[score]...} as opposed to the numeric index form which can be written e.g. {2...}
4752/// - *specifier* is a type-dependent formatting option that determines how a type should formatted (see below)
48/// - *fill* is a single unicode codepoint which is used to pad the formatted text
53/// - *fill* is a single byte which is used to pad the formatted text
4954/// - *alignment* is one of the three bytes '<', '^', or '>' to make the text left-, center-, or right-aligned, respectively
50/// - *width* is the total width of the field in unicode codepoints
55/// - *width* is the total width of the field in bytes. This is generally only
56/// useful for ASCII text, such as numbers.
5157/// - *precision* specifies how many decimals a formatted number should have
5258///
5359/// Note that most of the parameters are optional and may be omitted. Also you can leave out separators like `:` and `.` when
......@@ -66,6 +72,9 @@ pub const FormatOptions = struct {
6672/// - `o`: output integer value in octal notation
6773/// - `c`: output integer as an ASCII character. Integer type must have 8 bits at max.
6874/// - `u`: output integer as an UTF-8 sequence. Integer type must have 21 bits at max.
75/// - `D`: output nanoseconds as duration
76/// - `B`: output bytes in SI units (decimal)
77/// - `Bi`: output bytes in IEC units (binary)
6978/// - `?`: output optional value as either the unwrapped value, or `null`; may be followed by a format specifier for the underlying value.
7079/// - `!`: output error union value as either the unwrapped value, or the formatted error value; may be followed by a format specifier for the underlying value.
7180/// - `*`: output the address of the value instead of the value itself.
......@@ -73,7 +82,7 @@ pub const FormatOptions = struct {
7382///
7483/// If a formatted user type contains a function of the type
7584/// ```
76/// pub fn format(value: ?, comptime fmt: []const u8, options: std.fmt.FormatOptions, writer: anytype) !void
85/// pub fn format(value: ?, comptime fmt: []const u8, options: std.fmt.Options, writer: anytype) !void
7786/// ```
7887/// with `?` being the type formatted, this function will be called instead of the default implementation.
7988/// This allows user types to be formatted in a logical manner instead of dumping all fields of the type.
......@@ -81,11 +90,7 @@ pub const FormatOptions = struct {
8190/// A user type may be a `struct`, `vector`, `union` or `enum` type.
8291///
8392/// To print literal curly braces, escape them by writing them twice, e.g. `{{` or `}}`.
84pub fn format(
85 writer: anytype,
86 comptime fmt: []const u8,
87 args: anytype,
88) !void {
93pub fn format(bw: *std.io.BufferedWriter, comptime fmt: []const u8, args: anytype) anyerror!void {
8994 const ArgsType = @TypeOf(args);
9095 const args_type_info = @typeInfo(ArgsType);
9196 if (args_type_info != .@"struct") {
......@@ -130,7 +135,7 @@ pub fn format(
130135
131136 // Write out the literal
132137 if (literal.len != 0) {
133 try writer.writeAll(literal);
138 try bw.writeAll(literal);
134139 literal = "";
135140 }
136141
......@@ -190,16 +195,15 @@ pub fn format(
190195 const arg_to_print = comptime arg_state.nextArg(arg_pos) orelse
191196 @compileError("too few arguments");
192197
193 try formatType(
194 @field(args, fields_info[arg_to_print].name),
198 try bw.printValue(
195199 placeholder.specifier_arg,
196 FormatOptions{
200 .{
197201 .fill = placeholder.fill,
198202 .alignment = placeholder.alignment,
199203 .width = width,
200204 .precision = precision,
201205 },
202 writer,
206 @field(args, fields_info[arg_to_print].name),
203207 std.options.fmt_max_depth,
204208 );
205209 }
......@@ -298,7 +302,7 @@ pub const Placeholder = struct {
298302 @compileError("extraneous trailing character '" ++ unicode.utf8EncodeComptime(ch) ++ "'");
299303 }
300304
301 return Placeholder{
305 return .{
302306 .specifier_arg = cacheString(specifier_arg[0..specifier_arg.len].*),
303307 .fill = fill orelse default_fill_char,
304308 .alignment = alignment orelse default_alignment,
......@@ -434,429 +438,12 @@ pub const ArgState = struct {
434438 }
435439};
436440
437pub fn formatAddress(value: anytype, options: FormatOptions, writer: anytype) @TypeOf(writer).Error!void {
438 _ = options;
439 const T = @TypeOf(value);
440
441 switch (@typeInfo(T)) {
442 .pointer => |info| {
443 try writer.writeAll(@typeName(info.child) ++ "@");
444 if (info.size == .slice)
445 try formatInt(@intFromPtr(value.ptr), 16, .lower, FormatOptions{}, writer)
446 else
447 try formatInt(@intFromPtr(value), 16, .lower, FormatOptions{}, writer);
448 return;
449 },
450 .optional => |info| {
451 if (@typeInfo(info.child) == .pointer) {
452 try writer.writeAll(@typeName(info.child) ++ "@");
453 try formatInt(@intFromPtr(value), 16, .lower, FormatOptions{}, writer);
454 return;
455 }
456 },
457 else => {},
458 }
459
460 @compileError("cannot format non-pointer type " ++ @typeName(T) ++ " with * specifier");
461}
462
463// This ANY const is a workaround for: https://github.com/ziglang/zig/issues/7948
464const ANY = "any";
465
466pub fn defaultSpec(comptime T: type) [:0]const u8 {
467 switch (@typeInfo(T)) {
468 .array, .vector => return ANY,
469 .pointer => |ptr_info| switch (ptr_info.size) {
470 .one => switch (@typeInfo(ptr_info.child)) {
471 .array => return ANY,
472 else => {},
473 },
474 .many, .c => return "*",
475 .slice => return ANY,
476 },
477 .optional => |info| return "?" ++ defaultSpec(info.child),
478 .error_union => |info| return "!" ++ defaultSpec(info.payload),
479 else => {},
480 }
481 return "";
482}
483
484fn stripOptionalOrErrorUnionSpec(comptime fmt: []const u8) []const u8 {
485 return if (std.mem.eql(u8, fmt[1..], ANY))
486 ANY
487 else
488 fmt[1..];
489}
490
491pub fn invalidFmtError(comptime fmt: []const u8, value: anytype) void {
492 @compileError("invalid format string '" ++ fmt ++ "' for type '" ++ @typeName(@TypeOf(value)) ++ "'");
493}
494
495pub fn formatType(
496 value: anytype,
497 comptime fmt: []const u8,
498 options: FormatOptions,
499 writer: anytype,
500 max_depth: usize,
501) @TypeOf(writer).Error!void {
502 const T = @TypeOf(value);
503 const actual_fmt = comptime if (std.mem.eql(u8, fmt, ANY))
504 defaultSpec(T)
505 else if (fmt.len != 0 and (fmt[0] == '?' or fmt[0] == '!')) switch (@typeInfo(T)) {
506 .optional, .error_union => fmt,
507 else => stripOptionalOrErrorUnionSpec(fmt),
508 } else fmt;
509
510 if (comptime std.mem.eql(u8, actual_fmt, "*")) {
511 return formatAddress(value, options, writer);
512 }
513
514 if (std.meta.hasMethod(T, "format")) {
515 return try value.format(actual_fmt, options, writer);
516 }
517
518 switch (@typeInfo(T)) {
519 .comptime_int, .int, .comptime_float, .float => {
520 return formatValue(value, actual_fmt, options, writer);
521 },
522 .void => {
523 if (actual_fmt.len != 0) invalidFmtError(fmt, value);
524 return formatBuf("void", options, writer);
525 },
526 .bool => {
527 if (actual_fmt.len != 0) invalidFmtError(fmt, value);
528 return formatBuf(if (value) "true" else "false", options, writer);
529 },
530 .optional => {
531 if (actual_fmt.len == 0 or actual_fmt[0] != '?')
532 @compileError("cannot format optional without a specifier (i.e. {?} or {any})");
533 const remaining_fmt = comptime stripOptionalOrErrorUnionSpec(actual_fmt);
534 if (value) |payload| {
535 return formatType(payload, remaining_fmt, options, writer, max_depth);
536 } else {
537 return formatBuf("null", options, writer);
538 }
539 },
540 .error_union => {
541 if (actual_fmt.len == 0 or actual_fmt[0] != '!')
542 @compileError("cannot format error union without a specifier (i.e. {!} or {any})");
543 const remaining_fmt = comptime stripOptionalOrErrorUnionSpec(actual_fmt);
544 if (value) |payload| {
545 return formatType(payload, remaining_fmt, options, writer, max_depth);
546 } else |err| {
547 return formatType(err, "", options, writer, max_depth);
548 }
549 },
550 .error_set => {
551 if (actual_fmt.len != 0) invalidFmtError(fmt, value);
552 try writer.writeAll("error.");
553 return writer.writeAll(@errorName(value));
554 },
555 .@"enum" => |enumInfo| {
556 try writer.writeAll(@typeName(T));
557 if (enumInfo.is_exhaustive) {
558 if (actual_fmt.len != 0) invalidFmtError(fmt, value);
559 try writer.writeAll(".");
560 try writer.writeAll(@tagName(value));
561 return;
562 }
563
564 // Use @tagName only if value is one of known fields
565 @setEvalBranchQuota(3 * enumInfo.fields.len);
566 inline for (enumInfo.fields) |enumField| {
567 if (@intFromEnum(value) == enumField.value) {
568 try writer.writeAll(".");
569 try writer.writeAll(@tagName(value));
570 return;
571 }
572 }
573
574 try writer.writeAll("(");
575 try formatType(@intFromEnum(value), actual_fmt, options, writer, max_depth);
576 try writer.writeAll(")");
577 },
578 .@"union" => |info| {
579 if (actual_fmt.len != 0) invalidFmtError(fmt, value);
580 try writer.writeAll(@typeName(T));
581 if (max_depth == 0) {
582 return writer.writeAll("{ ... }");
583 }
584 if (info.tag_type) |UnionTagType| {
585 try writer.writeAll("{ .");
586 try writer.writeAll(@tagName(@as(UnionTagType, value)));
587 try writer.writeAll(" = ");
588 inline for (info.fields) |u_field| {
589 if (value == @field(UnionTagType, u_field.name)) {
590 try formatType(@field(value, u_field.name), ANY, options, writer, max_depth - 1);
591 }
592 }
593 try writer.writeAll(" }");
594 } else {
595 try format(writer, "@{x}", .{@intFromPtr(&value)});
596 }
597 },
598 .@"struct" => |info| {
599 if (actual_fmt.len != 0) invalidFmtError(fmt, value);
600 if (info.is_tuple) {
601 // Skip the type and field names when formatting tuples.
602 if (max_depth == 0) {
603 return writer.writeAll("{ ... }");
604 }
605 try writer.writeAll("{");
606 inline for (info.fields, 0..) |f, i| {
607 if (i == 0) {
608 try writer.writeAll(" ");
609 } else {
610 try writer.writeAll(", ");
611 }
612 try formatType(@field(value, f.name), ANY, options, writer, max_depth - 1);
613 }
614 return writer.writeAll(" }");
615 }
616 try writer.writeAll(@typeName(T));
617 if (max_depth == 0) {
618 return writer.writeAll("{ ... }");
619 }
620 try writer.writeAll("{");
621 inline for (info.fields, 0..) |f, i| {
622 if (i == 0) {
623 try writer.writeAll(" .");
624 } else {
625 try writer.writeAll(", .");
626 }
627 try writer.writeAll(f.name);
628 try writer.writeAll(" = ");
629 try formatType(@field(value, f.name), ANY, options, writer, max_depth - 1);
630 }
631 try writer.writeAll(" }");
632 },
633 .pointer => |ptr_info| switch (ptr_info.size) {
634 .one => switch (@typeInfo(ptr_info.child)) {
635 .array, .@"enum", .@"union", .@"struct" => {
636 return formatType(value.*, actual_fmt, options, writer, max_depth);
637 },
638 else => return format(writer, "{s}@{x}", .{ @typeName(ptr_info.child), @intFromPtr(value) }),
639 },
640 .many, .c => {
641 if (actual_fmt.len == 0)
642 @compileError("cannot format pointer without a specifier (i.e. {s} or {*})");
643 if (ptr_info.sentinel() != null) {
644 return formatType(mem.span(value), actual_fmt, options, writer, max_depth);
645 }
646 if (actual_fmt[0] == 's' and ptr_info.child == u8) {
647 return formatBuf(mem.span(value), options, writer);
648 }
649 invalidFmtError(fmt, value);
650 },
651 .slice => {
652 if (actual_fmt.len == 0)
653 @compileError("cannot format slice without a specifier (i.e. {s} or {any})");
654 if (max_depth == 0) {
655 return writer.writeAll("{ ... }");
656 }
657 if (actual_fmt[0] == 's' and ptr_info.child == u8) {
658 return formatBuf(value, options, writer);
659 }
660 try writer.writeAll("{ ");
661 for (value, 0..) |elem, i| {
662 try formatType(elem, actual_fmt, options, writer, max_depth - 1);
663 if (i != value.len - 1) {
664 try writer.writeAll(", ");
665 }
666 }
667 try writer.writeAll(" }");
668 },
669 },
670 .array => |info| {
671 if (actual_fmt.len == 0)
672 @compileError("cannot format array without a specifier (i.e. {s} or {any})");
673 if (max_depth == 0) {
674 return writer.writeAll("{ ... }");
675 }
676 if (actual_fmt[0] == 's' and info.child == u8) {
677 return formatBuf(&value, options, writer);
678 }
679 try writer.writeAll("{ ");
680 for (value, 0..) |elem, i| {
681 try formatType(elem, actual_fmt, options, writer, max_depth - 1);
682 if (i < value.len - 1) {
683 try writer.writeAll(", ");
684 }
685 }
686 try writer.writeAll(" }");
687 },
688 .vector => |info| {
689 if (max_depth == 0) {
690 return writer.writeAll("{ ... }");
691 }
692 try writer.writeAll("{ ");
693 var i: usize = 0;
694 while (i < info.len) : (i += 1) {
695 try formatType(value[i], actual_fmt, options, writer, max_depth - 1);
696 if (i < info.len - 1) {
697 try writer.writeAll(", ");
698 }
699 }
700 try writer.writeAll(" }");
701 },
702 .@"fn" => @compileError("unable to format function body type, use '*const " ++ @typeName(T) ++ "' for a function pointer type"),
703 .type => {
704 if (actual_fmt.len != 0) invalidFmtError(fmt, value);
705 return formatBuf(@typeName(value), options, writer);
706 },
707 .enum_literal => {
708 if (actual_fmt.len != 0) invalidFmtError(fmt, value);
709 const buffer = [_]u8{'.'} ++ @tagName(value);
710 return formatBuf(buffer, options, writer);
711 },
712 .null => {
713 if (actual_fmt.len != 0) invalidFmtError(fmt, value);
714 return formatBuf("null", options, writer);
715 },
716 else => @compileError("unable to format type '" ++ @typeName(T) ++ "'"),
717 }
718}
719
720fn formatValue(
721 value: anytype,
722 comptime fmt: []const u8,
723 options: FormatOptions,
724 writer: anytype,
725) !void {
726 const T = @TypeOf(value);
727 switch (@typeInfo(T)) {
728 .float, .comptime_float => return formatFloatValue(value, fmt, options, writer),
729 .int, .comptime_int => return formatIntValue(value, fmt, options, writer),
730 .bool => return formatBuf(if (value) "true" else "false", options, writer),
731 else => comptime unreachable,
732 }
733}
734
735pub fn formatIntValue(
736 value: anytype,
737 comptime fmt: []const u8,
738 options: FormatOptions,
739 writer: anytype,
740) !void {
741 comptime var base = 10;
742 comptime var case: Case = .lower;
743
744 const int_value = if (@TypeOf(value) == comptime_int) blk: {
745 const Int = math.IntFittingRange(value, value);
746 break :blk @as(Int, value);
747 } else value;
748
749 if (fmt.len == 0 or comptime std.mem.eql(u8, fmt, "d")) {
750 base = 10;
751 case = .lower;
752 } else if (comptime std.mem.eql(u8, fmt, "c")) {
753 if (@typeInfo(@TypeOf(int_value)).int.bits <= 8) {
754 return formatAsciiChar(@as(u8, int_value), options, writer);
755 } else {
756 @compileError("cannot print integer that is larger than 8 bits as an ASCII character");
757 }
758 } else if (comptime std.mem.eql(u8, fmt, "u")) {
759 if (@typeInfo(@TypeOf(int_value)).int.bits <= 21) {
760 return formatUnicodeCodepoint(@as(u21, int_value), options, writer);
761 } else {
762 @compileError("cannot print integer that is larger than 21 bits as an UTF-8 sequence");
763 }
764 } else if (comptime std.mem.eql(u8, fmt, "b")) {
765 base = 2;
766 case = .lower;
767 } else if (comptime std.mem.eql(u8, fmt, "x")) {
768 base = 16;
769 case = .lower;
770 } else if (comptime std.mem.eql(u8, fmt, "X")) {
771 base = 16;
772 case = .upper;
773 } else if (comptime std.mem.eql(u8, fmt, "o")) {
774 base = 8;
775 case = .lower;
776 } else {
777 invalidFmtError(fmt, value);
778 }
779
780 return formatInt(int_value, base, case, options, writer);
781}
782
783pub const format_float = @import("fmt/format_float.zig");
784pub const formatFloat = format_float.formatFloat;
785pub const FormatFloatError = format_float.FormatError;
786
787fn formatFloatValue(
788 value: anytype,
789 comptime fmt: []const u8,
790 options: FormatOptions,
791 writer: anytype,
792) !void {
793 var buf: [format_float.bufferSize(.decimal, f64)]u8 = undefined;
794
795 if (fmt.len == 0 or comptime std.mem.eql(u8, fmt, "e")) {
796 const s = formatFloat(&buf, value, .{ .mode = .scientific, .precision = options.precision }) catch |err| switch (err) {
797 error.BufferTooSmall => "(float)",
798 };
799 return formatBuf(s, options, writer);
800 } else if (comptime std.mem.eql(u8, fmt, "d")) {
801 const s = formatFloat(&buf, value, .{ .mode = .decimal, .precision = options.precision }) catch |err| switch (err) {
802 error.BufferTooSmall => "(float)",
803 };
804 return formatBuf(s, options, writer);
805 } else if (comptime std.mem.eql(u8, fmt, "x")) {
806 var buf_stream = std.io.fixedBufferStream(&buf);
807 formatFloatHexadecimal(value, options, buf_stream.writer()) catch |err| switch (err) {
808 error.NoSpaceLeft => unreachable,
809 };
810 return formatBuf(buf_stream.getWritten(), options, writer);
811 } else {
812 invalidFmtError(fmt, value);
813 }
814}
815
816441test {
817 _ = &format_float;
442 _ = float;
818443}
819444
820445pub const Case = enum { lower, upper };
821446
822fn SliceHex(comptime case: Case) type {
823 const charset = "0123456789" ++ if (case == .upper) "ABCDEF" else "abcdef";
824
825 return struct {
826 pub fn format(
827 bytes: []const u8,
828 comptime fmt: []const u8,
829 options: std.fmt.FormatOptions,
830 writer: anytype,
831 ) !void {
832 _ = fmt;
833 _ = options;
834 var buf: [2]u8 = undefined;
835
836 for (bytes) |c| {
837 buf[0] = charset[c >> 4];
838 buf[1] = charset[c & 15];
839 try writer.writeAll(&buf);
840 }
841 }
842 };
843}
844
845const formatSliceHexLower = SliceHex(.lower).format;
846const formatSliceHexUpper = SliceHex(.upper).format;
847
848/// Return a Formatter for a []const u8 where every byte is formatted as a pair
849/// of lowercase hexadecimal digits.
850pub fn fmtSliceHexLower(bytes: []const u8) std.fmt.Formatter(formatSliceHexLower) {
851 return .{ .data = bytes };
852}
853
854/// Return a Formatter for a []const u8 where every byte is formatted as pair
855/// of uppercase hexadecimal digits.
856pub fn fmtSliceHexUpper(bytes: []const u8) std.fmt.Formatter(formatSliceHexUpper) {
857 return .{ .data = bytes };
858}
859
860447fn SliceEscape(comptime case: Case) type {
861448 const charset = "0123456789" ++ if (case == .upper) "ABCDEF" else "abcdef";
862449
......@@ -864,7 +451,7 @@ fn SliceEscape(comptime case: Case) type {
864451 pub fn format(
865452 bytes: []const u8,
866453 comptime fmt: []const u8,
867 options: std.fmt.FormatOptions,
454 options: std.fmt.Options,
868455 writer: anytype,
869456 ) !void {
870457 _ = fmt;
......@@ -904,352 +491,13 @@ pub fn fmtSliceEscapeUpper(bytes: []const u8) std.fmt.Formatter(formatSliceEscap
904491 return .{ .data = bytes };
905492}
906493
907fn Size(comptime base: comptime_int) type {
908 return struct {
909 fn format(
910 value: u64,
911 comptime fmt: []const u8,
912 options: FormatOptions,
913 writer: anytype,
914 ) !void {
915 _ = fmt;
916 if (value == 0) {
917 return formatBuf("0B", options, writer);
918 }
919 // The worst case in terms of space needed is 32 bytes + 3 for the suffix.
920 var buf: [format_float.min_buffer_size + 3]u8 = undefined;
921
922 const mags_si = " kMGTPEZY";
923 const mags_iec = " KMGTPEZY";
924
925 const log2 = math.log2(value);
926 const magnitude = switch (base) {
927 1000 => @min(log2 / comptime math.log2(1000), mags_si.len - 1),
928 1024 => @min(log2 / 10, mags_iec.len - 1),
929 else => unreachable,
930 };
931 const new_value = lossyCast(f64, value) / math.pow(f64, lossyCast(f64, base), lossyCast(f64, magnitude));
932 const suffix = switch (base) {
933 1000 => mags_si[magnitude],
934 1024 => mags_iec[magnitude],
935 else => unreachable,
936 };
937
938 const s = switch (magnitude) {
939 0 => buf[0..formatIntBuf(&buf, value, 10, .lower, .{})],
940 else => formatFloat(&buf, new_value, .{ .mode = .decimal, .precision = options.precision }) catch |err| switch (err) {
941 error.BufferTooSmall => unreachable,
942 },
943 };
944
945 var i: usize = s.len;
946 if (suffix == ' ') {
947 buf[i] = 'B';
948 i += 1;
949 } else switch (base) {
950 1000 => {
951 buf[i..][0..2].* = [_]u8{ suffix, 'B' };
952 i += 2;
953 },
954 1024 => {
955 buf[i..][0..3].* = [_]u8{ suffix, 'i', 'B' };
956 i += 3;
957 },
958 else => unreachable,
959 }
960
961 return formatBuf(buf[0..i], options, writer);
962 }
963 };
964}
965const formatSizeDec = Size(1000).format;
966const formatSizeBin = Size(1024).format;
967
968/// Return a Formatter for a u64 value representing a file size.
969/// This formatter represents the number as multiple of 1000 and uses the SI
970/// measurement units (kB, MB, GB, ...).
971/// Format option `precision` is ignored when `value` is less than 1kB
972pub fn fmtIntSizeDec(value: u64) std.fmt.Formatter(formatSizeDec) {
973 return .{ .data = value };
974}
975
976/// Return a Formatter for a u64 value representing a file size.
977/// This formatter represents the number as multiple of 1024 and uses the IEC
978/// measurement units (KiB, MiB, GiB, ...).
979/// Format option `precision` is ignored when `value` is less than 1KiB
980pub fn fmtIntSizeBin(value: u64) std.fmt.Formatter(formatSizeBin) {
981 return .{ .data = value };
982}
983
984fn checkTextFmt(comptime fmt: []const u8) void {
985 if (fmt.len != 1)
986 @compileError("unsupported format string '" ++ fmt ++ "' when formatting text");
987 switch (fmt[0]) {
988 // Example of deprecation:
989 // '[deprecated_specifier]' => @compileError("specifier '[deprecated_specifier]' has been deprecated, wrap your argument in `std.some_function` instead"),
990 'x' => @compileError("specifier 'x' has been deprecated, wrap your argument in std.fmt.fmtSliceHexLower instead"),
991 'X' => @compileError("specifier 'X' has been deprecated, wrap your argument in std.fmt.fmtSliceHexUpper instead"),
992 else => {},
993 }
994}
995
996pub fn formatText(
997 bytes: []const u8,
998 comptime fmt: []const u8,
999 options: FormatOptions,
1000 writer: anytype,
1001) !void {
1002 comptime checkTextFmt(fmt);
1003 return formatBuf(bytes, options, writer);
1004}
1005
1006pub fn formatAsciiChar(
1007 c: u8,
1008 options: FormatOptions,
1009 writer: anytype,
1010) !void {
1011 return formatBuf(@as(*const [1]u8, &c), options, writer);
1012}
1013
1014pub fn formatUnicodeCodepoint(
1015 c: u21,
1016 options: FormatOptions,
1017 writer: anytype,
1018) !void {
1019 var buf: [4]u8 = undefined;
1020 const len = unicode.utf8Encode(c, &buf) catch |err| switch (err) {
1021 error.Utf8CannotEncodeSurrogateHalf, error.CodepointTooLarge => {
1022 return formatBuf(&unicode.utf8EncodeComptime(unicode.replacement_character), options, writer);
1023 },
1024 };
1025 return formatBuf(buf[0..len], options, writer);
1026}
1027
1028pub fn formatBuf(
1029 buf: []const u8,
1030 options: FormatOptions,
1031 writer: anytype,
1032) !void {
1033 if (options.width) |min_width| {
1034 // In case of error assume the buffer content is ASCII-encoded
1035 const width = unicode.utf8CountCodepoints(buf) catch buf.len;
1036 const padding = if (width < min_width) min_width - width else 0;
1037
1038 if (padding == 0)
1039 return writer.writeAll(buf);
1040
1041 var fill_buffer: [4]u8 = undefined;
1042 const fill_utf8 = if (unicode.utf8Encode(options.fill, &fill_buffer)) |len|
1043 fill_buffer[0..len]
1044 else |err| switch (err) {
1045 error.Utf8CannotEncodeSurrogateHalf,
1046 error.CodepointTooLarge,
1047 => &unicode.utf8EncodeComptime(unicode.replacement_character),
1048 };
1049 switch (options.alignment) {
1050 .left => {
1051 try writer.writeAll(buf);
1052 try writer.writeBytesNTimes(fill_utf8, padding);
1053 },
1054 .center => {
1055 const left_padding = padding / 2;
1056 const right_padding = (padding + 1) / 2;
1057 try writer.writeBytesNTimes(fill_utf8, left_padding);
1058 try writer.writeAll(buf);
1059 try writer.writeBytesNTimes(fill_utf8, right_padding);
1060 },
1061 .right => {
1062 try writer.writeBytesNTimes(fill_utf8, padding);
1063 try writer.writeAll(buf);
1064 },
1065 }
1066 } else {
1067 // Fast path, avoid counting the number of codepoints
1068 try writer.writeAll(buf);
1069 }
1070}
1071
1072pub fn formatFloatHexadecimal(
1073 value: anytype,
1074 options: FormatOptions,
1075 writer: anytype,
1076) !void {
1077 if (math.signbit(value)) {
1078 try writer.writeByte('-');
1079 }
1080 if (math.isNan(value)) {
1081 return writer.writeAll("nan");
1082 }
1083 if (math.isInf(value)) {
1084 return writer.writeAll("inf");
1085 }
1086
1087 const T = @TypeOf(value);
1088 const TU = std.meta.Int(.unsigned, @bitSizeOf(T));
1089
1090 const mantissa_bits = math.floatMantissaBits(T);
1091 const fractional_bits = math.floatFractionalBits(T);
1092 const exponent_bits = math.floatExponentBits(T);
1093 const mantissa_mask = (1 << mantissa_bits) - 1;
1094 const exponent_mask = (1 << exponent_bits) - 1;
1095 const exponent_bias = (1 << (exponent_bits - 1)) - 1;
1096
1097 const as_bits = @as(TU, @bitCast(value));
1098 var mantissa = as_bits & mantissa_mask;
1099 var exponent: i32 = @as(u16, @truncate((as_bits >> mantissa_bits) & exponent_mask));
1100
1101 const is_denormal = exponent == 0 and mantissa != 0;
1102 const is_zero = exponent == 0 and mantissa == 0;
1103
1104 if (is_zero) {
1105 // Handle this case here to simplify the logic below.
1106 try writer.writeAll("0x0");
1107 if (options.precision) |precision| {
1108 if (precision > 0) {
1109 try writer.writeAll(".");
1110 try writer.writeByteNTimes('0', precision);
1111 }
1112 } else {
1113 try writer.writeAll(".0");
1114 }
1115 try writer.writeAll("p0");
1116 return;
1117 }
1118
1119 if (is_denormal) {
1120 // Adjust the exponent for printing.
1121 exponent += 1;
1122 } else {
1123 if (fractional_bits == mantissa_bits)
1124 mantissa |= 1 << fractional_bits; // Add the implicit integer bit.
1125 }
1126
1127 const mantissa_digits = (fractional_bits + 3) / 4;
1128 // Fill in zeroes to round the fraction width to a multiple of 4.
1129 mantissa <<= mantissa_digits * 4 - fractional_bits;
1130
1131 if (options.precision) |precision| {
1132 // Round if needed.
1133 if (precision < mantissa_digits) {
1134 // We always have at least 4 extra bits.
1135 var extra_bits = (mantissa_digits - precision) * 4;
1136 // The result LSB is the Guard bit, we need two more (Round and
1137 // Sticky) to round the value.
1138 while (extra_bits > 2) {
1139 mantissa = (mantissa >> 1) | (mantissa & 1);
1140 extra_bits -= 1;
1141 }
1142 // Round to nearest, tie to even.
1143 mantissa |= @intFromBool(mantissa & 0b100 != 0);
1144 mantissa += 1;
1145 // Drop the excess bits.
1146 mantissa >>= 2;
1147 // Restore the alignment.
1148 mantissa <<= @as(math.Log2Int(TU), @intCast((mantissa_digits - precision) * 4));
1149
1150 const overflow = mantissa & (1 << 1 + mantissa_digits * 4) != 0;
1151 // Prefer a normalized result in case of overflow.
1152 if (overflow) {
1153 mantissa >>= 1;
1154 exponent += 1;
1155 }
1156 }
1157 }
1158
1159 // +1 for the decimal part.
1160 var buf: [1 + mantissa_digits]u8 = undefined;
1161 _ = formatIntBuf(&buf, mantissa, 16, .lower, .{ .fill = '0', .width = 1 + mantissa_digits });
1162
1163 try writer.writeAll("0x");
1164 try writer.writeByte(buf[0]);
1165 const trimmed = mem.trimEnd(u8, buf[1..], "0");
1166 if (options.precision) |precision| {
1167 if (precision > 0) try writer.writeAll(".");
1168 } else if (trimmed.len > 0) {
1169 try writer.writeAll(".");
1170 }
1171 try writer.writeAll(trimmed);
1172 // Add trailing zeros if explicitly requested.
1173 if (options.precision) |precision| if (precision > 0) {
1174 if (precision > trimmed.len)
1175 try writer.writeByteNTimes('0', precision - trimmed.len);
1176 };
1177 try writer.writeAll("p");
1178 try formatInt(exponent - exponent_bias, 10, .lower, .{}, writer);
1179}
1180
1181pub fn formatInt(
1182 value: anytype,
1183 base: u8,
1184 case: Case,
1185 options: FormatOptions,
1186 writer: anytype,
1187) !void {
1188 assert(base >= 2);
1189
1190 const int_value = if (@TypeOf(value) == comptime_int) blk: {
1191 const Int = math.IntFittingRange(value, value);
1192 break :blk @as(Int, value);
1193 } else value;
1194
1195 const value_info = @typeInfo(@TypeOf(int_value)).int;
1196
1197 // The type must have the same size as `base` or be wider in order for the
1198 // division to work
1199 const min_int_bits = comptime @max(value_info.bits, 8);
1200 const MinInt = std.meta.Int(.unsigned, min_int_bits);
1201
1202 const abs_value = @abs(int_value);
1203 // The worst case in terms of space needed is base 2, plus 1 for the sign
1204 var buf: [1 + @max(@as(comptime_int, value_info.bits), 1)]u8 = undefined;
1205
1206 var a: MinInt = abs_value;
1207 var index: usize = buf.len;
1208
1209 if (base == 10) {
1210 while (a >= 100) : (a = @divTrunc(a, 100)) {
1211 index -= 2;
1212 buf[index..][0..2].* = digits2(@intCast(a % 100));
1213 }
1214
1215 if (a < 10) {
1216 index -= 1;
1217 buf[index] = '0' + @as(u8, @intCast(a));
1218 } else {
1219 index -= 2;
1220 buf[index..][0..2].* = digits2(@intCast(a));
1221 }
1222 } else {
1223 while (true) {
1224 const digit = a % base;
1225 index -= 1;
1226 buf[index] = digitToChar(@intCast(digit), case);
1227 a /= base;
1228 if (a == 0) break;
1229 }
1230 }
1231
1232 if (value_info.signedness == .signed) {
1233 if (value < 0) {
1234 // Negative integer
1235 index -= 1;
1236 buf[index] = '-';
1237 } else if (options.width == null or options.width.? == 0) {
1238 // Positive integer, omit the plus sign
1239 } else {
1240 // Positive integer
1241 index -= 1;
1242 buf[index] = '+';
1243 }
1244 }
1245
1246 return formatBuf(buf[index..], options, writer);
1247}
1248
1249pub fn formatIntBuf(out_buf: []u8, value: anytype, base: u8, case: Case, options: FormatOptions) usize {
1250 var fbs = std.io.fixedBufferStream(out_buf);
1251 formatInt(value, base, case, options, fbs.writer()) catch unreachable;
1252 return fbs.pos;
494/// Asserts the rendered integer value fits in `buffer`.
495/// Returns the end index within `buffer`.
496pub fn printInt(buffer: []u8, value: anytype, base: u8, case: Case, options: Options) usize {
497 var bw: std.io.BufferedWriter = undefined;
498 bw.initFixed(buffer);
499 bw.printIntOptions(value, base, case, options) catch unreachable;
500 return bw.end;
1253501}
1254502
1255503/// Converts values in the range [0, 100) to a base 10 string.
......@@ -1261,214 +509,6 @@ pub fn digits2(value: u8) [2]u8 {
1261509 }
1262510}
1263511
1264const FormatDurationData = struct {
1265 ns: u64,
1266 negative: bool = false,
1267};
1268
1269fn formatDuration(data: FormatDurationData, comptime fmt: []const u8, options: std.fmt.FormatOptions, writer: anytype) !void {
1270 _ = fmt;
1271
1272 // worst case: "-XXXyXXwXXdXXhXXmXX.XXXs".len = 24
1273 var buf: [24]u8 = undefined;
1274 var fbs = std.io.fixedBufferStream(&buf);
1275 var buf_writer = fbs.writer();
1276 if (data.negative) {
1277 buf_writer.writeByte('-') catch unreachable;
1278 }
1279
1280 var ns_remaining = data.ns;
1281 inline for (.{
1282 .{ .ns = 365 * std.time.ns_per_day, .sep = 'y' },
1283 .{ .ns = std.time.ns_per_week, .sep = 'w' },
1284 .{ .ns = std.time.ns_per_day, .sep = 'd' },
1285 .{ .ns = std.time.ns_per_hour, .sep = 'h' },
1286 .{ .ns = std.time.ns_per_min, .sep = 'm' },
1287 }) |unit| {
1288 if (ns_remaining >= unit.ns) {
1289 const units = ns_remaining / unit.ns;
1290 formatInt(units, 10, .lower, .{}, buf_writer) catch unreachable;
1291 buf_writer.writeByte(unit.sep) catch unreachable;
1292 ns_remaining -= units * unit.ns;
1293 if (ns_remaining == 0)
1294 return formatBuf(fbs.getWritten(), options, writer);
1295 }
1296 }
1297
1298 inline for (.{
1299 .{ .ns = std.time.ns_per_s, .sep = "s" },
1300 .{ .ns = std.time.ns_per_ms, .sep = "ms" },
1301 .{ .ns = std.time.ns_per_us, .sep = "us" },
1302 }) |unit| {
1303 const kunits = ns_remaining * 1000 / unit.ns;
1304 if (kunits >= 1000) {
1305 formatInt(kunits / 1000, 10, .lower, .{}, buf_writer) catch unreachable;
1306 const frac = kunits % 1000;
1307 if (frac > 0) {
1308 // Write up to 3 decimal places
1309 var decimal_buf = [_]u8{ '.', 0, 0, 0 };
1310 _ = formatIntBuf(decimal_buf[1..], frac, 10, .lower, .{ .fill = '0', .width = 3 });
1311 var end: usize = 4;
1312 while (end > 1) : (end -= 1) {
1313 if (decimal_buf[end - 1] != '0') break;
1314 }
1315 buf_writer.writeAll(decimal_buf[0..end]) catch unreachable;
1316 }
1317 buf_writer.writeAll(unit.sep) catch unreachable;
1318 return formatBuf(fbs.getWritten(), options, writer);
1319 }
1320 }
1321
1322 formatInt(ns_remaining, 10, .lower, .{}, buf_writer) catch unreachable;
1323 buf_writer.writeAll("ns") catch unreachable;
1324 return formatBuf(fbs.getWritten(), options, writer);
1325}
1326
1327/// Return a Formatter for number of nanoseconds according to its magnitude:
1328/// [#y][#w][#d][#h][#m]#[.###][n|u|m]s
1329pub fn fmtDuration(ns: u64) Formatter(formatDuration) {
1330 const data = FormatDurationData{ .ns = ns };
1331 return .{ .data = data };
1332}
1333
1334test fmtDuration {
1335 var buf: [24]u8 = undefined;
1336 inline for (.{
1337 .{ .s = "0ns", .d = 0 },
1338 .{ .s = "1ns", .d = 1 },
1339 .{ .s = "999ns", .d = std.time.ns_per_us - 1 },
1340 .{ .s = "1us", .d = std.time.ns_per_us },
1341 .{ .s = "1.45us", .d = 1450 },
1342 .{ .s = "1.5us", .d = 3 * std.time.ns_per_us / 2 },
1343 .{ .s = "14.5us", .d = 14500 },
1344 .{ .s = "145us", .d = 145000 },
1345 .{ .s = "999.999us", .d = std.time.ns_per_ms - 1 },
1346 .{ .s = "1ms", .d = std.time.ns_per_ms + 1 },
1347 .{ .s = "1.5ms", .d = 3 * std.time.ns_per_ms / 2 },
1348 .{ .s = "1.11ms", .d = 1110000 },
1349 .{ .s = "1.111ms", .d = 1111000 },
1350 .{ .s = "1.111ms", .d = 1111100 },
1351 .{ .s = "999.999ms", .d = std.time.ns_per_s - 1 },
1352 .{ .s = "1s", .d = std.time.ns_per_s },
1353 .{ .s = "59.999s", .d = std.time.ns_per_min - 1 },
1354 .{ .s = "1m", .d = std.time.ns_per_min },
1355 .{ .s = "1h", .d = std.time.ns_per_hour },
1356 .{ .s = "1d", .d = std.time.ns_per_day },
1357 .{ .s = "1w", .d = std.time.ns_per_week },
1358 .{ .s = "1y", .d = 365 * std.time.ns_per_day },
1359 .{ .s = "1y52w23h59m59.999s", .d = 730 * std.time.ns_per_day - 1 }, // 365d = 52w1d
1360 .{ .s = "1y1h1.001s", .d = 365 * std.time.ns_per_day + std.time.ns_per_hour + std.time.ns_per_s + std.time.ns_per_ms },
1361 .{ .s = "1y1h1s", .d = 365 * std.time.ns_per_day + std.time.ns_per_hour + std.time.ns_per_s + 999 * std.time.ns_per_us },
1362 .{ .s = "1y1h999.999us", .d = 365 * std.time.ns_per_day + std.time.ns_per_hour + std.time.ns_per_ms - 1 },
1363 .{ .s = "1y1h1ms", .d = 365 * std.time.ns_per_day + std.time.ns_per_hour + std.time.ns_per_ms },
1364 .{ .s = "1y1h1ms", .d = 365 * std.time.ns_per_day + std.time.ns_per_hour + std.time.ns_per_ms + 1 },
1365 .{ .s = "1y1m999ns", .d = 365 * std.time.ns_per_day + std.time.ns_per_min + 999 },
1366 .{ .s = "584y49w23h34m33.709s", .d = math.maxInt(u64) },
1367 }) |tc| {
1368 const slice = try bufPrint(&buf, "{}", .{fmtDuration(tc.d)});
1369 try std.testing.expectEqualStrings(tc.s, slice);
1370 }
1371
1372 inline for (.{
1373 .{ .s = "=======0ns", .f = "{s:=>10}", .d = 0 },
1374 .{ .s = "1ns=======", .f = "{s:=<10}", .d = 1 },
1375 .{ .s = " 999ns ", .f = "{s:^10}", .d = std.time.ns_per_us - 1 },
1376 }) |tc| {
1377 const slice = try bufPrint(&buf, tc.f, .{fmtDuration(tc.d)});
1378 try std.testing.expectEqualStrings(tc.s, slice);
1379 }
1380}
1381
1382fn formatDurationSigned(ns: i64, comptime fmt: []const u8, options: std.fmt.FormatOptions, writer: anytype) !void {
1383 const data = FormatDurationData{ .ns = @abs(ns), .negative = ns < 0 };
1384 try formatDuration(data, fmt, options, writer);
1385}
1386
1387/// Return a Formatter for number of nanoseconds according to its signed magnitude:
1388/// [#y][#w][#d][#h][#m]#[.###][n|u|m]s
1389pub fn fmtDurationSigned(ns: i64) Formatter(formatDurationSigned) {
1390 return .{ .data = ns };
1391}
1392
1393test fmtDurationSigned {
1394 var buf: [24]u8 = undefined;
1395 inline for (.{
1396 .{ .s = "0ns", .d = 0 },
1397 .{ .s = "1ns", .d = 1 },
1398 .{ .s = "-1ns", .d = -(1) },
1399 .{ .s = "999ns", .d = std.time.ns_per_us - 1 },
1400 .{ .s = "-999ns", .d = -(std.time.ns_per_us - 1) },
1401 .{ .s = "1us", .d = std.time.ns_per_us },
1402 .{ .s = "-1us", .d = -(std.time.ns_per_us) },
1403 .{ .s = "1.45us", .d = 1450 },
1404 .{ .s = "-1.45us", .d = -(1450) },
1405 .{ .s = "1.5us", .d = 3 * std.time.ns_per_us / 2 },
1406 .{ .s = "-1.5us", .d = -(3 * std.time.ns_per_us / 2) },
1407 .{ .s = "14.5us", .d = 14500 },
1408 .{ .s = "-14.5us", .d = -(14500) },
1409 .{ .s = "145us", .d = 145000 },
1410 .{ .s = "-145us", .d = -(145000) },
1411 .{ .s = "999.999us", .d = std.time.ns_per_ms - 1 },
1412 .{ .s = "-999.999us", .d = -(std.time.ns_per_ms - 1) },
1413 .{ .s = "1ms", .d = std.time.ns_per_ms + 1 },
1414 .{ .s = "-1ms", .d = -(std.time.ns_per_ms + 1) },
1415 .{ .s = "1.5ms", .d = 3 * std.time.ns_per_ms / 2 },
1416 .{ .s = "-1.5ms", .d = -(3 * std.time.ns_per_ms / 2) },
1417 .{ .s = "1.11ms", .d = 1110000 },
1418 .{ .s = "-1.11ms", .d = -(1110000) },
1419 .{ .s = "1.111ms", .d = 1111000 },
1420 .{ .s = "-1.111ms", .d = -(1111000) },
1421 .{ .s = "1.111ms", .d = 1111100 },
1422 .{ .s = "-1.111ms", .d = -(1111100) },
1423 .{ .s = "999.999ms", .d = std.time.ns_per_s - 1 },
1424 .{ .s = "-999.999ms", .d = -(std.time.ns_per_s - 1) },
1425 .{ .s = "1s", .d = std.time.ns_per_s },
1426 .{ .s = "-1s", .d = -(std.time.ns_per_s) },
1427 .{ .s = "59.999s", .d = std.time.ns_per_min - 1 },
1428 .{ .s = "-59.999s", .d = -(std.time.ns_per_min - 1) },
1429 .{ .s = "1m", .d = std.time.ns_per_min },
1430 .{ .s = "-1m", .d = -(std.time.ns_per_min) },
1431 .{ .s = "1h", .d = std.time.ns_per_hour },
1432 .{ .s = "-1h", .d = -(std.time.ns_per_hour) },
1433 .{ .s = "1d", .d = std.time.ns_per_day },
1434 .{ .s = "-1d", .d = -(std.time.ns_per_day) },
1435 .{ .s = "1w", .d = std.time.ns_per_week },
1436 .{ .s = "-1w", .d = -(std.time.ns_per_week) },
1437 .{ .s = "1y", .d = 365 * std.time.ns_per_day },
1438 .{ .s = "-1y", .d = -(365 * std.time.ns_per_day) },
1439 .{ .s = "1y52w23h59m59.999s", .d = 730 * std.time.ns_per_day - 1 }, // 365d = 52w1d
1440 .{ .s = "-1y52w23h59m59.999s", .d = -(730 * std.time.ns_per_day - 1) }, // 365d = 52w1d
1441 .{ .s = "1y1h1.001s", .d = 365 * std.time.ns_per_day + std.time.ns_per_hour + std.time.ns_per_s + std.time.ns_per_ms },
1442 .{ .s = "-1y1h1.001s", .d = -(365 * std.time.ns_per_day + std.time.ns_per_hour + std.time.ns_per_s + std.time.ns_per_ms) },
1443 .{ .s = "1y1h1s", .d = 365 * std.time.ns_per_day + std.time.ns_per_hour + std.time.ns_per_s + 999 * std.time.ns_per_us },
1444 .{ .s = "-1y1h1s", .d = -(365 * std.time.ns_per_day + std.time.ns_per_hour + std.time.ns_per_s + 999 * std.time.ns_per_us) },
1445 .{ .s = "1y1h999.999us", .d = 365 * std.time.ns_per_day + std.time.ns_per_hour + std.time.ns_per_ms - 1 },
1446 .{ .s = "-1y1h999.999us", .d = -(365 * std.time.ns_per_day + std.time.ns_per_hour + std.time.ns_per_ms - 1) },
1447 .{ .s = "1y1h1ms", .d = 365 * std.time.ns_per_day + std.time.ns_per_hour + std.time.ns_per_ms },
1448 .{ .s = "-1y1h1ms", .d = -(365 * std.time.ns_per_day + std.time.ns_per_hour + std.time.ns_per_ms) },
1449 .{ .s = "1y1h1ms", .d = 365 * std.time.ns_per_day + std.time.ns_per_hour + std.time.ns_per_ms + 1 },
1450 .{ .s = "-1y1h1ms", .d = -(365 * std.time.ns_per_day + std.time.ns_per_hour + std.time.ns_per_ms + 1) },
1451 .{ .s = "1y1m999ns", .d = 365 * std.time.ns_per_day + std.time.ns_per_min + 999 },
1452 .{ .s = "-1y1m999ns", .d = -(365 * std.time.ns_per_day + std.time.ns_per_min + 999) },
1453 .{ .s = "292y24w3d23h47m16.854s", .d = math.maxInt(i64) },
1454 .{ .s = "-292y24w3d23h47m16.854s", .d = math.minInt(i64) + 1 },
1455 .{ .s = "-292y24w3d23h47m16.854s", .d = math.minInt(i64) },
1456 }) |tc| {
1457 const slice = try bufPrint(&buf, "{}", .{fmtDurationSigned(tc.d)});
1458 try std.testing.expectEqualStrings(tc.s, slice);
1459 }
1460
1461 inline for (.{
1462 .{ .s = "=======0ns", .f = "{s:=>10}", .d = 0 },
1463 .{ .s = "1ns=======", .f = "{s:=<10}", .d = 1 },
1464 .{ .s = "-1ns======", .f = "{s:=<10}", .d = -(1) },
1465 .{ .s = " -999ns ", .f = "{s:^10}", .d = -(std.time.ns_per_us - 1) },
1466 }) |tc| {
1467 const slice = try bufPrint(&buf, tc.f, .{fmtDurationSigned(tc.d)});
1468 try std.testing.expectEqualStrings(tc.s, slice);
1469 }
1470}
1471
1472512pub const ParseIntError = error{
1473513 /// The result cannot fit in the type specified
1474514 Overflow,
......@@ -1484,7 +524,7 @@ pub const ParseIntError = error{
1484524/// fn formatExample(
1485525/// data: T,
1486526/// comptime fmt: []const u8,
1487/// options: std.fmt.FormatOptions,
527/// options: std.fmt.Options,
1488528/// writer: anytype,
1489529/// ) !void;
1490530///
......@@ -1495,9 +535,9 @@ pub fn Formatter(comptime formatFn: anytype) type {
1495535 pub fn format(
1496536 self: @This(),
1497537 comptime fmt: []const u8,
1498 options: std.fmt.FormatOptions,
1499 writer: anytype,
1500 ) @TypeOf(writer).Error!void {
538 options: std.fmt.Options,
539 writer: *std.io.BufferedWriter,
540 ) anyerror!void {
1501541 try formatFn(self.data, fmt, options, writer);
1502542 }
1503543 };
......@@ -1796,12 +836,13 @@ pub const BufPrintError = error{
1796836/// Print a Formatter string into `buf`. Actually just a thin wrapper around `format` and `fixedBufferStream`.
1797837/// Returns a slice of the bytes printed to.
1798838pub fn bufPrint(buf: []u8, comptime fmt: []const u8, args: anytype) BufPrintError![]u8 {
1799 var fbs = std.io.fixedBufferStream(buf);
1800 format(fbs.writer().any(), fmt, args) catch |err| switch (err) {
839 var bw: std.io.BufferedWriter = undefined;
840 bw.initFixed(buf);
841 bw.print(fmt, args) catch |err| switch (err) {
1801842 error.NoSpaceLeft => return error.NoSpaceLeft,
1802843 else => unreachable,
1803844 };
1804 return fbs.getWritten();
845 return bw.getWritten();
1805846}
1806847
1807848pub fn bufPrintZ(buf: []u8, comptime fmt: []const u8, args: anytype) BufPrintError![:0]u8 {
......@@ -1809,10 +850,11 @@ pub fn bufPrintZ(buf: []u8, comptime fmt: []const u8, args: anytype) BufPrintErr
1809850 return result[0 .. result.len - 1 :0];
1810851}
1811852
1812/// Count the characters needed for format. Useful for preallocating memory
853/// Count the characters needed for format.
1813854pub fn count(comptime fmt: []const u8, args: anytype) u64 {
1814 var counting_writer = std.io.countingWriter(std.io.null_writer);
1815 format(counting_writer.writer().any(), fmt, args) catch unreachable;
855 var counting_writer: std.io.CountingWriter = .{ .child_writer = std.io.null_writer };
856 var bw = counting_writer.unbufferedWriter();
857 bw.print(fmt, args) catch unreachable;
1816858 return counting_writer.bytes_written;
1817859}
1818860
......@@ -1831,31 +873,6 @@ pub fn allocPrintZ(allocator: mem.Allocator, comptime fmt: []const u8, args: any
1831873 return result[0 .. result.len - 1 :0];
1832874}
1833875
1834test bufPrintIntToSlice {
1835 var buffer: [100]u8 = undefined;
1836 const buf = buffer[0..];
1837
1838 try std.testing.expectEqualSlices(u8, "-1", bufPrintIntToSlice(buf, @as(i1, -1), 10, .lower, FormatOptions{}));
1839
1840 try std.testing.expectEqualSlices(u8, "-101111000110000101001110", bufPrintIntToSlice(buf, @as(i32, -12345678), 2, .lower, FormatOptions{}));
1841 try std.testing.expectEqualSlices(u8, "-12345678", bufPrintIntToSlice(buf, @as(i32, -12345678), 10, .lower, FormatOptions{}));
1842 try std.testing.expectEqualSlices(u8, "-bc614e", bufPrintIntToSlice(buf, @as(i32, -12345678), 16, .lower, FormatOptions{}));
1843 try std.testing.expectEqualSlices(u8, "-BC614E", bufPrintIntToSlice(buf, @as(i32, -12345678), 16, .upper, FormatOptions{}));
1844
1845 try std.testing.expectEqualSlices(u8, "12345678", bufPrintIntToSlice(buf, @as(u32, 12345678), 10, .upper, FormatOptions{}));
1846
1847 try std.testing.expectEqualSlices(u8, " 666", bufPrintIntToSlice(buf, @as(u32, 666), 10, .lower, FormatOptions{ .width = 6 }));
1848 try std.testing.expectEqualSlices(u8, " 1234", bufPrintIntToSlice(buf, @as(u32, 0x1234), 16, .lower, FormatOptions{ .width = 6 }));
1849 try std.testing.expectEqualSlices(u8, "1234", bufPrintIntToSlice(buf, @as(u32, 0x1234), 16, .lower, FormatOptions{ .width = 1 }));
1850
1851 try std.testing.expectEqualSlices(u8, "+42", bufPrintIntToSlice(buf, @as(i32, 42), 10, .lower, FormatOptions{ .width = 3 }));
1852 try std.testing.expectEqualSlices(u8, "-42", bufPrintIntToSlice(buf, @as(i32, -42), 10, .lower, FormatOptions{ .width = 3 }));
1853}
1854
1855pub fn bufPrintIntToSlice(buf: []u8, value: anytype, base: u8, case: Case, options: FormatOptions) []u8 {
1856 return buf[0..formatIntBuf(buf, value, base, case, options)];
1857}
1858
1859876pub inline fn comptimePrint(comptime fmt: []const u8, args: anytype) *const [count(fmt, args):0]u8 {
1860877 comptime {
1861878 var buf: [count(fmt, args):0]u8 = undefined;
......@@ -1994,15 +1011,16 @@ test "buffer" {
19941011 {
19951012 var buf1: [32]u8 = undefined;
19961013 var fbs = std.io.fixedBufferStream(&buf1);
1997 try formatType(1234, "", FormatOptions{}, fbs.writer(), std.options.fmt_max_depth);
1014 var bw = fbs.writer();
1015 try bw.printValue("", .{}, 1234, std.options.fmt_max_depth);
19981016 try std.testing.expectEqualStrings("1234", fbs.getWritten());
19991017
20001018 fbs.reset();
2001 try formatType('a', "c", FormatOptions{}, fbs.writer(), std.options.fmt_max_depth);
1019 try bw.printValue("c", .{}, 'a', std.options.fmt_max_depth);
20021020 try std.testing.expectEqualStrings("a", fbs.getWritten());
20031021
20041022 fbs.reset();
2005 try formatType(0b1100, "b", FormatOptions{}, fbs.writer(), std.options.fmt_max_depth);
1023 try bw.printValue("b", .{}, 0b1100, std.options.fmt_max_depth);
20061024 try std.testing.expectEqualStrings("1100", fbs.getWritten());
20071025 }
20081026}
......@@ -2083,7 +1101,7 @@ test "slice" {
20831101 const S2 = struct {
20841102 x: u8,
20851103
2086 pub fn format(s: @This(), comptime _: []const u8, _: std.fmt.FormatOptions, writer: anytype) !void {
1104 pub fn format(s: @This(), comptime _: []const u8, _: std.fmt.Options, writer: anytype) !void {
20871105 try writer.print("S2({})", .{s.x});
20881106 }
20891107 };
......@@ -2129,21 +1147,6 @@ test "cstr" {
21291147 );
21301148}
21311149
2132test "filesize" {
2133 try expectFmt("file size: 42B\n", "file size: {}\n", .{fmtIntSizeDec(42)});
2134 try expectFmt("file size: 42B\n", "file size: {}\n", .{fmtIntSizeBin(42)});
2135 try expectFmt("file size: 63MB\n", "file size: {}\n", .{fmtIntSizeDec(63 * 1000 * 1000)});
2136 try expectFmt("file size: 63MiB\n", "file size: {}\n", .{fmtIntSizeBin(63 * 1024 * 1024)});
2137 try expectFmt("file size: 42B\n", "file size: {:.2}\n", .{fmtIntSizeDec(42)});
2138 try expectFmt("file size: 42B\n", "file size: {:>9.2}\n", .{fmtIntSizeDec(42)});
2139 try expectFmt("file size: 66.06MB\n", "file size: {:.2}\n", .{fmtIntSizeDec(63 * 1024 * 1024)});
2140 try expectFmt("file size: 60.08MiB\n", "file size: {:.2}\n", .{fmtIntSizeBin(63 * 1000 * 1000)});
2141 try expectFmt("file size: =66.06MB=\n", "file size: {:=^9.2}\n", .{fmtIntSizeDec(63 * 1024 * 1024)});
2142 try expectFmt("file size: 66.06MB\n", "file size: {: >9.2}\n", .{fmtIntSizeDec(63 * 1024 * 1024)});
2143 try expectFmt("file size: 66.06MB \n", "file size: {: <9.2}\n", .{fmtIntSizeDec(63 * 1024 * 1024)});
2144 try expectFmt("file size: 0.01844674407370955ZB\n", "file size: {}\n", .{fmtIntSizeDec(math.maxInt(u64))});
2145}
2146
21471150test "struct" {
21481151 {
21491152 const Struct = struct {
......@@ -2354,7 +1357,7 @@ test "custom" {
23541357 pub fn format(
23551358 self: SelfType,
23561359 comptime fmt: []const u8,
2357 options: FormatOptions,
1360 options: Options,
23581361 writer: anytype,
23591362 ) !void {
23601363 _ = options;
......@@ -2439,17 +1442,6 @@ test "struct.zero-size" {
24391442 try expectFmt("fmt.test.struct.zero-size.B{ .a = fmt.test.struct.zero-size.A{ }, .c = 0 }", "{}", .{b});
24401443}
24411444
2442test "bytes.hex" {
2443 const some_bytes = "\xCA\xFE\xBA\xBE";
2444 try expectFmt("lowercase: cafebabe\n", "lowercase: {x}\n", .{fmtSliceHexLower(some_bytes)});
2445 try expectFmt("uppercase: CAFEBABE\n", "uppercase: {X}\n", .{fmtSliceHexUpper(some_bytes)});
2446 //Test Slices
2447 try expectFmt("uppercase: CAFE\n", "uppercase: {X}\n", .{fmtSliceHexUpper(some_bytes[0..2])});
2448 try expectFmt("lowercase: babe\n", "lowercase: {x}\n", .{fmtSliceHexLower(some_bytes[2..])});
2449 const bytes_with_zeros = "\x00\x0E\xBA\xBE";
2450 try expectFmt("lowercase: 000ebabe\n", "lowercase: {x}\n", .{fmtSliceHexLower(bytes_with_zeros)});
2451}
2452
24531445/// Encodes a sequence of bytes as hexadecimal digits.
24541446/// Returns an array containing the encoded bytes.
24551447pub fn bytesToHex(input: anytype, case: Case) [input.len * 2]u8 {
......@@ -2494,110 +1486,14 @@ test bytesToHex {
24941486
24951487test hexToBytes {
24961488 var buf: [32]u8 = undefined;
2497 try expectFmt("90" ** 32, "{s}", .{fmtSliceHexUpper(try hexToBytes(&buf, "90" ** 32))});
2498 try expectFmt("ABCD", "{s}", .{fmtSliceHexUpper(try hexToBytes(&buf, "ABCD"))});
2499 try expectFmt("", "{s}", .{fmtSliceHexUpper(try hexToBytes(&buf, ""))});
1489 try expectFmt("90" ** 32, "{X}", .{try hexToBytes(&buf, "90" ** 32)});
1490 try expectFmt("ABCD", "{X}", .{try hexToBytes(&buf, "ABCD")});
1491 try expectFmt("", "{X}", .{try hexToBytes(&buf, "")});
25001492 try std.testing.expectError(error.InvalidCharacter, hexToBytes(&buf, "012Z"));
25011493 try std.testing.expectError(error.InvalidLength, hexToBytes(&buf, "AAA"));
25021494 try std.testing.expectError(error.NoSpaceLeft, hexToBytes(buf[0..1], "ABAB"));
25031495}
25041496
2505test "formatIntValue with comptime_int" {
2506 const value: comptime_int = 123456789123456789;
2507
2508 var buf: [20]u8 = undefined;
2509 var fbs = std.io.fixedBufferStream(&buf);
2510 try formatIntValue(value, "", FormatOptions{}, fbs.writer());
2511 try std.testing.expectEqualStrings("123456789123456789", fbs.getWritten());
2512}
2513
2514test "formatFloatValue with comptime_float" {
2515 const value: comptime_float = 1.0;
2516
2517 var buf: [20]u8 = undefined;
2518 var fbs = std.io.fixedBufferStream(&buf);
2519 try formatFloatValue(value, "", FormatOptions{}, fbs.writer());
2520 try std.testing.expectEqualStrings(fbs.getWritten(), "1e0");
2521
2522 try expectFmt("1e0", "{}", .{value});
2523 try expectFmt("1e0", "{}", .{1.0});
2524}
2525
2526test "formatType max_depth" {
2527 const Vec2 = struct {
2528 const SelfType = @This();
2529 x: f32,
2530 y: f32,
2531
2532 pub fn format(
2533 self: SelfType,
2534 comptime fmt: []const u8,
2535 options: FormatOptions,
2536 writer: anytype,
2537 ) !void {
2538 _ = options;
2539 if (fmt.len == 0) {
2540 return std.fmt.format(writer, "({d:.3},{d:.3})", .{ self.x, self.y });
2541 } else {
2542 @compileError("unknown format string: '" ++ fmt ++ "'");
2543 }
2544 }
2545 };
2546 const E = enum {
2547 One,
2548 Two,
2549 Three,
2550 };
2551 const TU = union(enum) {
2552 const SelfType = @This();
2553 float: f32,
2554 int: u32,
2555 ptr: ?*SelfType,
2556 };
2557 const S = struct {
2558 const SelfType = @This();
2559 a: ?*SelfType,
2560 tu: TU,
2561 e: E,
2562 vec: Vec2,
2563 };
2564
2565 var inst = S{
2566 .a = null,
2567 .tu = TU{ .ptr = null },
2568 .e = E.Two,
2569 .vec = Vec2{ .x = 10.2, .y = 2.22 },
2570 };
2571 inst.a = &inst;
2572 inst.tu.ptr = &inst.tu;
2573
2574 var buf: [1000]u8 = undefined;
2575 var fbs = std.io.fixedBufferStream(&buf);
2576 try formatType(inst, "", FormatOptions{}, fbs.writer(), 0);
2577 try std.testing.expectEqualStrings("fmt.test.formatType max_depth.S{ ... }", fbs.getWritten());
2578
2579 fbs.reset();
2580 try formatType(inst, "", FormatOptions{}, fbs.writer(), 1);
2581 try std.testing.expectEqualStrings("fmt.test.formatType max_depth.S{ .a = fmt.test.formatType max_depth.S{ ... }, .tu = fmt.test.formatType max_depth.TU{ ... }, .e = fmt.test.formatType max_depth.E.Two, .vec = (10.200,2.220) }", fbs.getWritten());
2582
2583 fbs.reset();
2584 try formatType(inst, "", FormatOptions{}, fbs.writer(), 2);
2585 try std.testing.expectEqualStrings("fmt.test.formatType max_depth.S{ .a = fmt.test.formatType max_depth.S{ .a = fmt.test.formatType max_depth.S{ ... }, .tu = fmt.test.formatType max_depth.TU{ ... }, .e = fmt.test.formatType max_depth.E.Two, .vec = (10.200,2.220) }, .tu = fmt.test.formatType max_depth.TU{ .ptr = fmt.test.formatType max_depth.TU{ ... } }, .e = fmt.test.formatType max_depth.E.Two, .vec = (10.200,2.220) }", fbs.getWritten());
2586
2587 fbs.reset();
2588 try formatType(inst, "", FormatOptions{}, fbs.writer(), 3);
2589 try std.testing.expectEqualStrings("fmt.test.formatType max_depth.S{ .a = fmt.test.formatType max_depth.S{ .a = fmt.test.formatType max_depth.S{ .a = fmt.test.formatType max_depth.S{ ... }, .tu = fmt.test.formatType max_depth.TU{ ... }, .e = fmt.test.formatType max_depth.E.Two, .vec = (10.200,2.220) }, .tu = fmt.test.formatType max_depth.TU{ .ptr = fmt.test.formatType max_depth.TU{ ... } }, .e = fmt.test.formatType max_depth.E.Two, .vec = (10.200,2.220) }, .tu = fmt.test.formatType max_depth.TU{ .ptr = fmt.test.formatType max_depth.TU{ .ptr = fmt.test.formatType max_depth.TU{ ... } } }, .e = fmt.test.formatType max_depth.E.Two, .vec = (10.200,2.220) }", fbs.getWritten());
2590
2591 const vec: @Vector(4, i32) = .{ 1, 2, 3, 4 };
2592 fbs.reset();
2593 try formatType(vec, "", FormatOptions{}, fbs.writer(), 0);
2594 try std.testing.expectEqualStrings("{ ... }", fbs.getWritten());
2595
2596 fbs.reset();
2597 try formatType(vec, "", FormatOptions{}, fbs.writer(), 1);
2598 try std.testing.expectEqualStrings("{ 1, 2, 3, 4 }", fbs.getWritten());
2599}
2600
26011497test "positional" {
26021498 try expectFmt("2 1 0", "{2} {1} {0}", .{ @as(usize, 0), @as(usize, 1), @as(usize, 2) });
26031499 try expectFmt("2 1 0", "{2} {1} {}", .{ @as(usize, 0), @as(usize, 1), @as(usize, 2) });
......@@ -2742,7 +1638,7 @@ test "recursive format function" {
27421638 Leaf: i32,
27431639 Branch: struct { left: *const R, right: *const R },
27441640
2745 pub fn format(self: R, comptime _: []const u8, _: std.fmt.FormatOptions, writer: anytype) !void {
1641 pub fn format(self: R, comptime _: []const u8, _: std.fmt.Options, writer: anytype) !void {
27461642 return switch (self) {
27471643 .Leaf => |n| std.fmt.format(writer, "Leaf({})", .{n}),
27481644 .Branch => |b| std.fmt.format(writer, "Branch({}, {})", .{ b.left, b.right }),
lib/std/fmt/float.zig created+1695
......@@ -0,0 +1,1695 @@
1//! This file implements the ryu floating point conversion algorithm:
2//! https://dl.acm.org/doi/pdf/10.1145/3360595
3
4const std = @import("std");
5const expectFmt = std.testing.expectFmt;
6
7const special_exponent = 0x7fffffff;
8
9/// Any buffer used for `format` must be at least this large. This is asserted. A runtime check will
10/// additionally be performed if more bytes are required.
11pub const min_buffer_size = 53;
12
13/// Returns the minimum buffer size needed to print every float of a specific type and format.
14pub fn bufferSize(comptime mode: Mode, comptime T: type) comptime_int {
15 comptime std.debug.assert(@typeInfo(T) == .float);
16 return switch (mode) {
17 .scientific => 53,
18 // Based on minimum subnormal values.
19 .decimal => switch (@bitSizeOf(T)) {
20 16 => @max(15, min_buffer_size),
21 32 => 55,
22 64 => 347,
23 80 => 4996,
24 128 => 5011,
25 else => unreachable,
26 },
27 };
28}
29
30pub const Error = error{
31 BufferTooSmall,
32};
33
34pub const Mode = enum {
35 scientific,
36 decimal,
37};
38
39pub const Options = struct {
40 mode: Mode = .scientific,
41 precision: ?usize = null,
42};
43
44/// Format a floating-point value and write it to buffer. Returns a slice to the buffer containing
45/// the string representation.
46///
47/// Full precision is the default. Any full precision float can be reparsed with std.fmt.parseFloat
48/// unambiguously.
49///
50/// Scientific mode is recommended generally as the output is more compact and any type can be
51/// written in full precision using a buffer of only `min_buffer_size`.
52///
53/// When printing full precision decimals, use `bufferSize` to get the required space. It is
54/// recommended to bound decimal output with a fixed precision to reduce the required buffer size.
55pub fn render(buf: []u8, value: anytype, options: Options) Error![]const u8 {
56 const v = switch (@TypeOf(value)) {
57 // comptime_float internally is a f128; this preserves precision.
58 comptime_float => @as(f128, value),
59 else => value,
60 };
61
62 const T = @TypeOf(v);
63 comptime std.debug.assert(@typeInfo(T) == .float);
64 const I = @Type(.{ .int = .{ .signedness = .unsigned, .bits = @bitSizeOf(T) } });
65
66 const DT = if (@bitSizeOf(T) <= 64) u64 else u128;
67 const tables = switch (DT) {
68 u64 => if (@import("builtin").mode == .ReleaseSmall) &Backend64_TablesSmall else &Backend64_TablesFull,
69 u128 => &Backend128_Tables,
70 else => unreachable,
71 };
72
73 const has_explicit_leading_bit = std.math.floatMantissaBits(T) - std.math.floatFractionalBits(T) != 0;
74 const d = binaryToDecimal(DT, @as(I, @bitCast(v)), std.math.floatMantissaBits(T), std.math.floatExponentBits(T), has_explicit_leading_bit, tables);
75
76 return switch (options.mode) {
77 .scientific => formatScientific(DT, buf, d, options.precision),
78 .decimal => formatDecimal(DT, buf, d, options.precision),
79 };
80}
81
82pub fn FloatDecimal(comptime T: type) type {
83 comptime std.debug.assert(T == u64 or T == u128);
84 return struct {
85 mantissa: T,
86 exponent: i32,
87 sign: bool,
88 };
89}
90
91fn copySpecialStr(buf: []u8, f: anytype) []const u8 {
92 if (f.sign) {
93 buf[0] = '-';
94 }
95 const offset: usize = @intFromBool(f.sign);
96 if (f.mantissa != 0) {
97 @memcpy(buf[offset..][0..3], "nan");
98 return buf[0 .. 3 + offset];
99 }
100 @memcpy(buf[offset..][0..3], "inf");
101 return buf[0 .. 3 + offset];
102}
103
104fn writeDecimal(buf: []u8, value: anytype, count: usize) void {
105 var i: usize = 0;
106
107 while (i + 2 < count) : (i += 2) {
108 const c: u8 = @intCast(value.* % 100);
109 value.* /= 100;
110 const d = std.fmt.digits2(c);
111 buf[count - i - 1] = d[1];
112 buf[count - i - 2] = d[0];
113 }
114
115 while (i < count) : (i += 1) {
116 const c: u8 = @intCast(value.* % 10);
117 value.* /= 10;
118 buf[count - i - 1] = '0' + c;
119 }
120}
121
122fn isPowerOf10(n_: u128) bool {
123 var n = n_;
124 while (n != 0) : (n /= 10) {
125 if (n % 10 != 0) return false;
126 }
127 return true;
128}
129
130const RoundMode = enum {
131 /// 1234.56 = precision 2
132 decimal,
133 /// 1.23456e3 = precision 5
134 scientific,
135};
136
137fn round(comptime T: type, f: FloatDecimal(T), mode: RoundMode, precision: usize) FloatDecimal(T) {
138 var round_digit: usize = 0;
139 var output = f.mantissa;
140 var exp = f.exponent;
141 const olength = decimalLength(output);
142
143 switch (mode) {
144 .decimal => {
145 if (f.exponent > 0) {
146 round_digit = (olength - 1) + precision + @as(usize, @intCast(f.exponent));
147 } else {
148 const min_exp_required = @as(usize, @intCast(-f.exponent));
149 if (precision + olength > min_exp_required) {
150 round_digit = precision + olength - min_exp_required;
151 }
152 }
153 },
154 .scientific => {
155 round_digit = 1 + precision;
156 },
157 }
158
159 if (round_digit < olength) {
160 var nlength = olength;
161 for (round_digit + 1..olength) |_| {
162 output /= 10;
163 exp += 1;
164 nlength -= 1;
165 }
166
167 if (output % 10 >= 5) {
168 output /= 10;
169 output += 1;
170 exp += 1;
171
172 // e.g. 9999 -> 10000
173 if (isPowerOf10(output)) {
174 output /= 10;
175 exp += 1;
176 }
177 }
178 }
179
180 return .{
181 .mantissa = output,
182 .exponent = exp,
183 .sign = f.sign,
184 };
185}
186
187/// Write a FloatDecimal to a buffer in scientific form.
188///
189/// The buffer provided must be greater than `min_buffer_size` in length. If no precision is
190/// specified, this function will never return an error. If a precision is specified, up to
191/// `8 + precision` bytes will be written to the buffer. An error will be returned if the content
192/// will not fit.
193///
194/// It is recommended to bound decimal formatting with an exact precision.
195pub fn formatScientific(comptime T: type, buf: []u8, f_: FloatDecimal(T), precision: ?usize) Error![]const u8 {
196 std.debug.assert(buf.len >= min_buffer_size);
197 var f = f_;
198
199 if (f.exponent == special_exponent) {
200 return copySpecialStr(buf, f);
201 }
202
203 if (precision) |prec| {
204 f = round(T, f, .scientific, prec);
205 }
206
207 var output = f.mantissa;
208 const olength = decimalLength(output);
209
210 if (precision) |prec| {
211 // fixed bound: sign(1) + leading_digit(1) + point(1) + exp_sign(1) + exp_max(4)
212 const req_bytes = 8 + prec;
213 if (buf.len < req_bytes) {
214 return error.BufferTooSmall;
215 }
216 }
217
218 // Step 5: Print the scientific representation
219 var index: usize = 0;
220 if (f.sign) {
221 buf[index] = '-';
222 index += 1;
223 }
224
225 // 1.12345
226 writeDecimal(buf[index + 2 ..], &output, olength - 1);
227 buf[index] = '0' + @as(u8, @intCast(output % 10));
228 buf[index + 1] = '.';
229 index += 2;
230 const dp_index = index;
231 if (olength > 1) index += olength - 1 else index -= 1;
232
233 if (precision) |prec| {
234 index += @intFromBool(olength == 1);
235 if (prec > olength - 1) {
236 const len = prec - (olength - 1);
237 @memset(buf[index..][0..len], '0');
238 index += len;
239 } else {
240 index = dp_index + prec - @intFromBool(prec == 0);
241 }
242 }
243
244 // e100
245 buf[index] = 'e';
246 index += 1;
247 var exp = f.exponent + @as(i32, @intCast(olength)) - 1;
248 if (exp < 0) {
249 buf[index] = '-';
250 index += 1;
251 exp = -exp;
252 }
253 var uexp: u32 = @intCast(exp);
254 const elength = decimalLength(uexp);
255 writeDecimal(buf[index..], &uexp, elength);
256 index += elength;
257
258 return buf[0..index];
259}
260
261/// Write a FloatDecimal to a buffer in decimal form.
262///
263/// The buffer provided must be greater than `min_buffer_size` bytes in length. If no precision is
264/// specified, this may still return an error. If precision is specified, `2 + precision` bytes will
265/// always be written.
266pub fn formatDecimal(comptime T: type, buf: []u8, f_: FloatDecimal(T), precision: ?usize) Error![]const u8 {
267 std.debug.assert(buf.len >= min_buffer_size);
268 var f = f_;
269
270 if (f.exponent == special_exponent) {
271 return copySpecialStr(buf, f);
272 }
273
274 if (precision) |prec| {
275 f = round(T, f, .decimal, prec);
276 }
277
278 var output = f.mantissa;
279 const olength = decimalLength(output);
280
281 // fixed bound: leading_digit(1) + point(1)
282 const req_bytes = if (f.exponent >= 0)
283 @as(usize, 2) + @abs(f.exponent) + olength + (precision orelse 0)
284 else
285 @as(usize, 2) + @max(@abs(f.exponent) + olength, precision orelse 0);
286 if (buf.len < req_bytes) {
287 return error.BufferTooSmall;
288 }
289
290 // Step 5: Print the decimal representation
291 var index: usize = 0;
292 if (f.sign) {
293 buf[index] = '-';
294 index += 1;
295 }
296
297 const dp_offset = f.exponent + cast_i32(olength);
298 if (dp_offset <= 0) {
299 // 0.000001234
300 buf[index] = '0';
301 buf[index + 1] = '.';
302 index += 2;
303 const dp_index = index;
304
305 const dp_poffset: u32 = @intCast(-dp_offset);
306 @memset(buf[index..][0..dp_poffset], '0');
307 index += dp_poffset;
308 writeDecimal(buf[index..], &output, olength);
309 index += olength;
310
311 if (precision) |prec| {
312 const dp_written = index - dp_index;
313 if (prec > dp_written) {
314 @memset(buf[index..][0 .. prec - dp_written], '0');
315 }
316 index = dp_index + prec - @intFromBool(prec == 0);
317 }
318 } else {
319 // 123456000
320 const dp_uoffset: usize = @intCast(dp_offset);
321 if (dp_uoffset >= olength) {
322 writeDecimal(buf[index..], &output, olength);
323 index += olength;
324 @memset(buf[index..][0 .. dp_uoffset - olength], '0');
325 index += dp_uoffset - olength;
326
327 if (precision) |prec| {
328 if (prec != 0) {
329 buf[index] = '.';
330 index += 1;
331 @memset(buf[index..][0..prec], '0');
332 index += prec;
333 }
334 }
335 } else {
336 // 12345.6789
337 writeDecimal(buf[index + dp_uoffset + 1 ..], &output, olength - dp_uoffset);
338 buf[index + dp_uoffset] = '.';
339 const dp_index = index + dp_uoffset + 1;
340 writeDecimal(buf[index..], &output, dp_uoffset);
341 index += olength + 1;
342
343 if (precision) |prec| {
344 const dp_written = olength - dp_uoffset;
345 if (prec > dp_written) {
346 @memset(buf[index..][0 .. prec - dp_written], '0');
347 }
348 index = dp_index + prec - @intFromBool(prec == 0);
349 }
350 }
351 }
352
353 return buf[0..index];
354}
355
356fn cast_i32(v: anytype) i32 {
357 return @intCast(v);
358}
359
360/// Convert a binary float representation to decimal.
361pub fn binaryToDecimal(comptime T: type, bits: T, mantissa_bits: std.math.Log2Int(T), exponent_bits: u5, explicit_leading_bit: bool, comptime tables: anytype) FloatDecimal(T) {
362 if (T != tables.T) {
363 @compileError("table type does not match backend type: " ++ @typeName(tables.T) ++ " != " ++ @typeName(T));
364 }
365
366 const bias = (@as(u32, 1) << (exponent_bits - 1)) - 1;
367 const ieee_sign = ((bits >> (mantissa_bits + exponent_bits)) & 1) != 0;
368 const ieee_mantissa = bits & ((@as(T, 1) << mantissa_bits) - 1);
369 const ieee_exponent: u32 = @intCast((bits >> mantissa_bits) & ((@as(T, 1) << exponent_bits) - 1));
370
371 if (ieee_exponent == 0 and ieee_mantissa == 0) {
372 return .{
373 .mantissa = 0,
374 .exponent = 0,
375 .sign = ieee_sign,
376 };
377 }
378 if (ieee_exponent == ((@as(u32, 1) << exponent_bits) - 1)) {
379 return .{
380 .mantissa = if (explicit_leading_bit) ieee_mantissa & ((@as(T, 1) << (mantissa_bits - 1)) - 1) else ieee_mantissa,
381 .exponent = special_exponent,
382 .sign = ieee_sign,
383 };
384 }
385
386 var e2: i32 = undefined;
387 var m2: T = undefined;
388 if (explicit_leading_bit) {
389 if (ieee_exponent == 0) {
390 e2 = 1 - cast_i32(bias) - cast_i32(mantissa_bits) + 1 - 2;
391 } else {
392 e2 = cast_i32(ieee_exponent) - cast_i32(bias) - cast_i32(mantissa_bits) + 1 - 2;
393 }
394 m2 = ieee_mantissa;
395 } else {
396 if (ieee_exponent == 0) {
397 e2 = 1 - cast_i32(bias) - cast_i32(mantissa_bits) - 2;
398 m2 = ieee_mantissa;
399 } else {
400 e2 = cast_i32(ieee_exponent) - cast_i32(bias) - cast_i32(mantissa_bits) - 2;
401 m2 = (@as(T, 1) << mantissa_bits) | ieee_mantissa;
402 }
403 }
404 const even = (m2 & 1) == 0;
405 const accept_bounds = even;
406
407 // Step 2: Determine the interval of legal decimal representations.
408 const mv = 4 * m2;
409 const mm_shift: u1 = @intFromBool((ieee_mantissa != if (explicit_leading_bit) (@as(T, 1) << (mantissa_bits - 1)) else 0) or (ieee_exponent == 0));
410
411 // Step 3: Convert to a decimal power base using 128-bit arithmetic.
412 var vr: T = undefined;
413 var vp: T = undefined;
414 var vm: T = undefined;
415 var e10: i32 = undefined;
416 var vm_is_trailing_zeros = false;
417 var vr_is_trailing_zeros = false;
418 if (e2 >= 0) {
419 const q: u32 = log10Pow2(@intCast(e2)) - @intFromBool(e2 > 3);
420 e10 = cast_i32(q);
421 const k: i32 = @intCast(tables.POW5_INV_BITCOUNT + pow5Bits(q) - 1);
422 const i: u32 = @intCast(-e2 + cast_i32(q) + k);
423
424 const pow5 = tables.computeInvPow5(q);
425 vr = tables.mulShift(4 * m2, &pow5, i);
426 vp = tables.mulShift(4 * m2 + 2, &pow5, i);
427 vm = tables.mulShift(4 * m2 - 1 - mm_shift, &pow5, i);
428
429 if (q <= tables.bound1) {
430 if (mv % 5 == 0) {
431 vr_is_trailing_zeros = multipleOfPowerOf5(mv, if (tables.adjust_q) q -% 1 else q);
432 } else if (accept_bounds) {
433 vm_is_trailing_zeros = multipleOfPowerOf5(mv - 1 - mm_shift, q);
434 } else {
435 vp -= @intFromBool(multipleOfPowerOf5(mv + 2, q));
436 }
437 }
438 } else {
439 const q: u32 = log10Pow5(@intCast(-e2)) - @intFromBool(-e2 > 1);
440 e10 = cast_i32(q) + e2;
441 const i: i32 = -e2 - cast_i32(q);
442 const k: i32 = cast_i32(pow5Bits(@intCast(i))) - tables.POW5_BITCOUNT;
443 const j: u32 = @intCast(cast_i32(q) - k);
444
445 const pow5 = tables.computePow5(@intCast(i));
446 vr = tables.mulShift(4 * m2, &pow5, j);
447 vp = tables.mulShift(4 * m2 + 2, &pow5, j);
448 vm = tables.mulShift(4 * m2 - 1 - mm_shift, &pow5, j);
449
450 if (q <= 1) {
451 vr_is_trailing_zeros = true;
452 if (accept_bounds) {
453 vm_is_trailing_zeros = mm_shift == 1;
454 } else {
455 vp -= 1;
456 }
457 } else if (q < tables.bound2) {
458 vr_is_trailing_zeros = multipleOfPowerOf2(mv, if (tables.adjust_q) q - 1 else q);
459 }
460 }
461
462 // Step 4: Find the shortest decimal representation in the interval of legal representations.
463 var removed: u32 = 0;
464 var last_removed_digit: u8 = 0;
465
466 while (vp / 10 > vm / 10) {
467 vm_is_trailing_zeros = vm_is_trailing_zeros and vm % 10 == 0;
468 vr_is_trailing_zeros = vr_is_trailing_zeros and last_removed_digit == 0;
469 last_removed_digit = @intCast(vr % 10);
470 vr /= 10;
471 vp /= 10;
472 vm /= 10;
473 removed += 1;
474 }
475
476 if (vm_is_trailing_zeros) {
477 while (vm % 10 == 0) {
478 vr_is_trailing_zeros = vr_is_trailing_zeros and last_removed_digit == 0;
479 last_removed_digit = @intCast(vr % 10);
480 vr /= 10;
481 vp /= 10;
482 vm /= 10;
483 removed += 1;
484 }
485 }
486
487 if (vr_is_trailing_zeros and (last_removed_digit == 5) and (vr % 2 == 0)) {
488 last_removed_digit = 4;
489 }
490
491 return .{
492 .mantissa = vr + @intFromBool((vr == vm and (!accept_bounds or !vm_is_trailing_zeros)) or last_removed_digit >= 5),
493 .exponent = e10 + cast_i32(removed),
494 .sign = ieee_sign,
495 };
496}
497
498fn decimalLength(v: anytype) u32 {
499 switch (@TypeOf(v)) {
500 u32, u64 => {
501 std.debug.assert(v < 100000000000000000);
502 if (v >= 10000000000000000) return 17;
503 if (v >= 1000000000000000) return 16;
504 if (v >= 100000000000000) return 15;
505 if (v >= 10000000000000) return 14;
506 if (v >= 1000000000000) return 13;
507 if (v >= 100000000000) return 12;
508 if (v >= 10000000000) return 11;
509 if (v >= 1000000000) return 10;
510 if (v >= 100000000) return 9;
511 if (v >= 10000000) return 8;
512 if (v >= 1000000) return 7;
513 if (v >= 100000) return 6;
514 if (v >= 10000) return 5;
515 if (v >= 1000) return 4;
516 if (v >= 100) return 3;
517 if (v >= 10) return 2;
518 return 1;
519 },
520 u128 => {
521 const LARGEST_POW10 = (@as(u128, 5421010862427522170) << 64) | 687399551400673280;
522 var p10 = LARGEST_POW10;
523 var i: u32 = 39;
524 while (i > 0) : (i -= 1) {
525 if (v >= p10) return i;
526 p10 /= 10;
527 }
528 return 1;
529 },
530 else => unreachable,
531 }
532}
533
534// floor(log_10(2^e))
535fn log10Pow2(e: u32) u32 {
536 std.debug.assert(e <= 1 << 15);
537 return @intCast((@as(u64, @intCast(e)) * 169464822037455) >> 49);
538}
539
540// floor(log_10(5^e))
541fn log10Pow5(e: u32) u32 {
542 std.debug.assert(e <= 1 << 15);
543 return @intCast((@as(u64, @intCast(e)) * 196742565691928) >> 48);
544}
545
546// if (e == 0) 1 else ceil(log_2(5^e))
547fn pow5Bits(e: u32) u32 {
548 std.debug.assert(e <= 1 << 15);
549 return @intCast(((@as(u64, @intCast(e)) * 163391164108059) >> 46) + 1);
550}
551
552fn pow5Factor(value_: anytype) u32 {
553 var count: u32 = 0;
554 var value = value_;
555 while (value > 0) : ({
556 count += 1;
557 value /= 5;
558 }) {
559 if (value % 5 != 0) return count;
560 }
561 return 0;
562}
563
564fn multipleOfPowerOf5(value: anytype, p: u32) bool {
565 const T = @TypeOf(value);
566 std.debug.assert(@typeInfo(T) == .int);
567 return pow5Factor(value) >= p;
568}
569
570fn multipleOfPowerOf2(value: anytype, p: u32) bool {
571 const T = @TypeOf(value);
572 std.debug.assert(@typeInfo(T) == .int);
573 return (value & ((@as(T, 1) << @as(std.math.Log2Int(T), @intCast(p))) - 1)) == 0;
574}
575
576fn mulShift128(m: u128, mul: *const [4]u64, j: u32) u128 {
577 std.debug.assert(j > 128);
578 const a: [2]u64 = .{ @truncate(m), @truncate(m >> 64) };
579 const r = mul_128_256_shift(&a, mul, j, 0);
580 return (@as(u128, r[1]) << 64) | r[0];
581}
582
583fn mul_128_256_shift(a: *const [2]u64, b: *const [4]u64, shift: u32, corr: u32) [4]u64 {
584 std.debug.assert(shift > 0);
585 std.debug.assert(shift < 256);
586
587 const b00 = @as(u128, a[0]) * b[0];
588 const b01 = @as(u128, a[0]) * b[1];
589 const b02 = @as(u128, a[0]) * b[2];
590 const b03 = @as(u128, a[0]) * b[3];
591 const b10 = @as(u128, a[1]) * b[0];
592 const b11 = @as(u128, a[1]) * b[1];
593 const b12 = @as(u128, a[1]) * b[2];
594 const b13 = @as(u128, a[1]) * b[3];
595
596 const s0 = b00;
597 const s1 = b01 +% b10;
598 const c1: u128 = @intFromBool(s1 < b01);
599 const s2 = b02 +% b11;
600 const c2: u128 = @intFromBool(s2 < b02);
601 const s3 = b03 +% b12;
602 const c3: u128 = @intFromBool(s3 < b03);
603
604 const p0 = s0 +% (s1 << 64);
605 const d0: u128 = @intFromBool(p0 < b00);
606 const q1 = s2 +% (s1 >> 64) +% (s3 << 64);
607 const d1: u128 = @intFromBool(q1 < s2);
608 const p1 = q1 +% (c1 << 64) +% d0;
609 const d2: u128 = @intFromBool(p1 < q1);
610 const p2 = b13 +% (s3 >> 64) +% c2 +% (c3 << 64) +% d1 +% d2;
611
612 var r0: u128 = undefined;
613 var r1: u128 = undefined;
614 if (shift < 128) {
615 const cshift: u7 = @intCast(shift);
616 const sshift: u7 = @intCast(128 - shift);
617 r0 = corr +% ((p0 >> cshift) | (p1 << sshift));
618 r1 = ((p1 >> cshift) | (p2 << sshift)) +% @intFromBool(r0 < corr);
619 } else if (shift == 128) {
620 r0 = corr +% p1;
621 r1 = p2 +% @intFromBool(r0 < corr);
622 } else {
623 const ashift: u7 = @intCast(shift - 128);
624 const sshift: u7 = @intCast(256 - shift);
625 r0 = corr +% ((p1 >> ashift) | (p2 << sshift));
626 r1 = (p2 >> ashift) +% @intFromBool(r0 < corr);
627 }
628
629 return .{ @truncate(r0), @truncate(r0 >> 64), @truncate(r1), @truncate(r1 >> 64) };
630}
631
632pub const Backend128_Tables = struct {
633 const T = u128;
634 const mulShift = mulShift128;
635 const POW5_INV_BITCOUNT = FLOAT128_POW5_INV_BITCOUNT;
636 const POW5_BITCOUNT = FLOAT128_POW5_BITCOUNT;
637
638 const bound1 = 55;
639 const bound2 = 127;
640 const adjust_q = true;
641
642 fn computePow5(i: u32) [4]u64 {
643 const base = i / FLOAT128_POW5_TABLE_SIZE;
644 const base2 = base * FLOAT128_POW5_TABLE_SIZE;
645 const mul = &FLOAT128_POW5_SPLIT[base];
646 if (i == base2) {
647 return mul.*;
648 } else {
649 const offset = i - base2;
650 const m = &FLOAT128_POW5_TABLE[offset];
651 const delta = pow5Bits(i) - pow5Bits(base2);
652
653 const shift: u6 = @intCast(2 * (i % 32));
654 const corr: u32 = @intCast((FLOAT128_POW5_ERRORS[i / 32] >> shift) & 3);
655 return mul_128_256_shift(m, mul, delta, corr);
656 }
657 }
658
659 fn computeInvPow5(i: u32) [4]u64 {
660 const base = (i + FLOAT128_POW5_TABLE_SIZE - 1) / FLOAT128_POW5_TABLE_SIZE;
661 const base2 = base * FLOAT128_POW5_TABLE_SIZE;
662 const mul = &FLOAT128_POW5_INV_SPLIT[base]; // 1 / 5^base2
663 if (i == base2) {
664 return .{ mul[0] + 1, mul[1], mul[2], mul[3] };
665 } else {
666 const offset = base2 - i;
667 const m = &FLOAT128_POW5_TABLE[offset]; // 5^offset
668 const delta = pow5Bits(base2) - pow5Bits(i);
669
670 const shift: u6 = @intCast(2 * (i % 32));
671 const corr: u32 = @intCast(((FLOAT128_POW5_INV_ERRORS[i / 32] >> shift) & 3) + 1);
672 return mul_128_256_shift(m, mul, delta, corr);
673 }
674 }
675};
676
677fn mulShift64(m: u64, mul: *const [2]u64, j: u32) u64 {
678 std.debug.assert(j > 64);
679 const b0 = @as(u128, m) * mul[0];
680 const b2 = @as(u128, m) * mul[1];
681
682 if (j < 128) {
683 const shift: u6 = @intCast(j - 64);
684 return @intCast(((b0 >> 64) + b2) >> shift);
685 } else {
686 return 0;
687 }
688}
689
690pub const Backend64_TablesFull = struct {
691 const T = u64;
692 const mulShift = mulShift64;
693 const POW5_INV_BITCOUNT = FLOAT64_POW5_INV_BITCOUNT;
694 const POW5_BITCOUNT = FLOAT64_POW5_BITCOUNT;
695
696 const bound1 = 21;
697 const bound2 = 63;
698 const adjust_q = false;
699
700 fn computePow5(i: u32) [2]u64 {
701 return FLOAT64_POW5_SPLIT[i];
702 }
703
704 fn computeInvPow5(i: u32) [2]u64 {
705 return FLOAT64_POW5_INV_SPLIT[i];
706 }
707};
708
709pub const Backend64_TablesSmall = struct {
710 const T = u64;
711 const mulShift = mulShift64;
712 const POW5_INV_BITCOUNT = FLOAT64_POW5_INV_BITCOUNT;
713 const POW5_BITCOUNT = FLOAT64_POW5_BITCOUNT;
714
715 const bound1 = 21;
716 const bound2 = 63;
717 const adjust_q = false;
718
719 fn computePow5(i: u32) [2]u64 {
720 const base = i / FLOAT64_POW5_TABLE_SIZE;
721 const base2 = base * FLOAT64_POW5_TABLE_SIZE;
722 const mul = &FLOAT64_POW5_SPLIT2[base];
723 if (i == base2) {
724 return .{ mul[0], mul[1] };
725 } else {
726 const offset = i - base2;
727 const m = FLOAT64_POW5_TABLE[offset];
728 const b0 = @as(u128, m) * mul[0];
729 const b2 = @as(u128, m) * mul[1];
730 const delta: u7 = @intCast(pow5Bits(i) - pow5Bits(base2));
731 const shift: u5 = @intCast((i % 16) << 1);
732 const shifted_sum = ((b0 >> delta) + (b2 << (64 - delta))) + 1 + ((FLOAT64_POW5_OFFSETS[i / 16] >> shift) & 3);
733 return .{ @truncate(shifted_sum), @truncate(shifted_sum >> 64) };
734 }
735 }
736
737 fn computeInvPow5(i: u32) [2]u64 {
738 const base = (i + FLOAT64_POW5_TABLE_SIZE - 1) / FLOAT64_POW5_TABLE_SIZE;
739 const base2 = base * FLOAT64_POW5_TABLE_SIZE;
740 const mul = &FLOAT64_POW5_INV_SPLIT2[base]; // 1 / 5^base2
741 if (i == base2) {
742 return .{ mul[0], mul[1] };
743 } else {
744 const offset = base2 - i;
745 const m = FLOAT64_POW5_TABLE[offset]; // 5^offset
746 const b0 = @as(u128, m) * (mul[0] - 1);
747 const b2 = @as(u128, m) * mul[1]; // 1/5^base2 * 5^offset = 1/5^(base2-offset) = 1/5^i
748 const delta: u7 = @intCast(pow5Bits(base2) - pow5Bits(i));
749 const shift: u5 = @intCast((i % 16) << 1);
750 const shifted_sum = ((b0 >> delta) + (b2 << (64 - delta))) + 1 + ((FLOAT64_POW5_INV_OFFSETS[i / 16] >> shift) & 3);
751 return .{ @truncate(shifted_sum), @truncate(shifted_sum >> 64) };
752 }
753 }
754};
755
756const FLOAT64_POW5_INV_BITCOUNT = 125;
757const FLOAT64_POW5_BITCOUNT = 125;
758
759// zig fmt: off
760//
761// f64 small tables: 816 bytes
762
763const FLOAT64_POW5_TABLE_SIZE: comptime_int = FLOAT64_POW5_TABLE.len;
764
765const FLOAT64_POW5_TABLE: [26]u64 = .{
766 1, 5,
767 25, 125,
768 625, 3125,
769 15625, 78125,
770 390625, 1953125,
771 9765625, 48828125,
772 244140625, 1220703125,
773 6103515625, 30517578125,
774 152587890625, 762939453125,
775 3814697265625, 19073486328125,
776 95367431640625, 476837158203125,
777 2384185791015625, 11920928955078125,
778 59604644775390625, 298023223876953125,
779};
780
781const FLOAT64_POW5_SPLIT2: [13][2]u64 = .{
782 .{ 0, 1152921504606846976 },
783 .{ 0, 1490116119384765625 },
784 .{ 1032610780636961552, 1925929944387235853 },
785 .{ 7910200175544436838, 1244603055572228341 },
786 .{ 16941905809032713930, 1608611746708759036 },
787 .{ 13024893955298202172, 2079081953128979843 },
788 .{ 6607496772837067824, 1343575221513417750 },
789 .{ 17332926989895652603, 1736530273035216783 },
790 .{ 13037379183483547984, 2244412773384604712 },
791 .{ 1605989338741628675, 1450417759929778918 },
792 .{ 9630225068416591280, 1874621017369538693 },
793 .{ 665883850346957067, 1211445438634777304 },
794 .{ 14931890668723713708, 1565756531257009982 }
795};
796
797const FLOAT64_POW5_OFFSETS: [21]u32 = .{
798 0x00000000, 0x00000000, 0x00000000, 0x00000000,
799 0x40000000, 0x59695995, 0x55545555, 0x56555515,
800 0x41150504, 0x40555410, 0x44555145, 0x44504540,
801 0x45555550, 0x40004000, 0x96440440, 0x55565565,
802 0x54454045, 0x40154151, 0x55559155, 0x51405555,
803 0x00000105,
804};
805
806const FLOAT64_POW5_INV_SPLIT2: [15][2]u64 = .{
807 .{ 1, 2305843009213693952 },
808 .{ 5955668970331000884, 1784059615882449851 },
809 .{ 8982663654677661702, 1380349269358112757 },
810 .{ 7286864317269821294, 2135987035920910082 },
811 .{ 7005857020398200553, 1652639921975621497 },
812 .{ 17965325103354776697, 1278668206209430417 },
813 .{ 8928596168509315048, 1978643211784836272 },
814 .{ 10075671573058298858, 1530901034580419511 },
815 .{ 597001226353042382, 1184477304306571148 },
816 .{ 1527430471115325346, 1832889850782397517 },
817 .{ 12533209867169019542, 1418129833677084982 },
818 .{ 5577825024675947042, 2194449627517475473 },
819 .{ 11006974540203867551, 1697873161311732311 },
820 .{ 10313493231639821582, 1313665730009899186 },
821 .{ 12701016819766672773, 2032799256770390445 }
822};
823
824const FLOAT64_POW5_INV_OFFSETS: [19]u32 = .{
825 0x54544554, 0x04055545, 0x10041000, 0x00400414,
826 0x40010000, 0x41155555, 0x00000454, 0x00010044,
827 0x40000000, 0x44000041, 0x50454450, 0x55550054,
828 0x51655554, 0x40004000, 0x01000001, 0x00010500,
829 0x51515411, 0x05555554, 0x00000000,
830};
831
832
833// zig fmt: off
834
835// f64 full tables: 10688 bytes
836
837const FLOAT64_POW5_SPLIT: [326][2]u64 = .{
838 .{ 0, 1152921504606846976 }, .{ 0, 1441151880758558720 },
839 .{ 0, 1801439850948198400 }, .{ 0, 2251799813685248000 },
840 .{ 0, 1407374883553280000 }, .{ 0, 1759218604441600000 },
841 .{ 0, 2199023255552000000 }, .{ 0, 1374389534720000000 },
842 .{ 0, 1717986918400000000 }, .{ 0, 2147483648000000000 },
843 .{ 0, 1342177280000000000 }, .{ 0, 1677721600000000000 },
844 .{ 0, 2097152000000000000 }, .{ 0, 1310720000000000000 },
845 .{ 0, 1638400000000000000 }, .{ 0, 2048000000000000000 },
846 .{ 0, 1280000000000000000 }, .{ 0, 1600000000000000000 },
847 .{ 0, 2000000000000000000 }, .{ 0, 1250000000000000000 },
848 .{ 0, 1562500000000000000 }, .{ 0, 1953125000000000000 },
849 .{ 0, 1220703125000000000 }, .{ 0, 1525878906250000000 },
850 .{ 0, 1907348632812500000 }, .{ 0, 1192092895507812500 },
851 .{ 0, 1490116119384765625 }, .{ 4611686018427387904, 1862645149230957031 },
852 .{ 9799832789158199296, 1164153218269348144 }, .{ 12249790986447749120, 1455191522836685180 },
853 .{ 15312238733059686400, 1818989403545856475 }, .{ 14528612397897220096, 2273736754432320594 },
854 .{ 13692068767113150464, 1421085471520200371 }, .{ 12503399940464050176, 1776356839400250464 },
855 .{ 15629249925580062720, 2220446049250313080 }, .{ 9768281203487539200, 1387778780781445675 },
856 .{ 7598665485932036096, 1734723475976807094 }, .{ 274959820560269312, 2168404344971008868 },
857 .{ 9395221924704944128, 1355252715606880542 }, .{ 2520655369026404352, 1694065894508600678 },
858 .{ 12374191248137781248, 2117582368135750847 }, .{ 14651398557727195136, 1323488980084844279 },
859 .{ 13702562178731606016, 1654361225106055349 }, .{ 3293144668132343808, 2067951531382569187 },
860 .{ 18199116482078572544, 1292469707114105741 }, .{ 8913837547316051968, 1615587133892632177 },
861 .{ 15753982952572452864, 2019483917365790221 }, .{ 12152082354571476992, 1262177448353618888 },
862 .{ 15190102943214346240, 1577721810442023610 }, .{ 9764256642163156992, 1972152263052529513 },
863 .{ 17631875447420442880, 1232595164407830945 }, .{ 8204786253993389888, 1540743955509788682 },
864 .{ 1032610780636961552, 1925929944387235853 }, .{ 2951224747111794922, 1203706215242022408 },
865 .{ 3689030933889743652, 1504632769052528010 }, .{ 13834660704216955373, 1880790961315660012 },
866 .{ 17870034976990372916, 1175494350822287507 }, .{ 17725857702810578241, 1469367938527859384 },
867 .{ 3710578054803671186, 1836709923159824231 }, .{ 26536550077201078, 2295887403949780289 },
868 .{ 11545800389866720434, 1434929627468612680 }, .{ 14432250487333400542, 1793662034335765850 },
869 .{ 8816941072311974870, 2242077542919707313 }, .{ 17039803216263454053, 1401298464324817070 },
870 .{ 12076381983474541759, 1751623080406021338 }, .{ 5872105442488401391, 2189528850507526673 },
871 .{ 15199280947623720629, 1368455531567204170 }, .{ 9775729147674874978, 1710569414459005213 },
872 .{ 16831347453020981627, 2138211768073756516 }, .{ 1296220121283337709, 1336382355046097823 },
873 .{ 15455333206886335848, 1670477943807622278 }, .{ 10095794471753144002, 2088097429759527848 },
874 .{ 6309871544845715001, 1305060893599704905 }, .{ 12499025449484531656, 1631326116999631131 },
875 .{ 11012095793428276666, 2039157646249538914 }, .{ 11494245889320060820, 1274473528905961821 },
876 .{ 532749306367912313, 1593091911132452277 }, .{ 5277622651387278295, 1991364888915565346 },
877 .{ 7910200175544436838, 1244603055572228341 }, .{ 14499436237857933952, 1555753819465285426 },
878 .{ 8900923260467641632, 1944692274331606783 }, .{ 12480606065433357876, 1215432671457254239 },
879 .{ 10989071563364309441, 1519290839321567799 }, .{ 9124653435777998898, 1899113549151959749 },
880 .{ 8008751406574943263, 1186945968219974843 }, .{ 5399253239791291175, 1483682460274968554 },
881 .{ 15972438586593889776, 1854603075343710692 }, .{ 759402079766405302, 1159126922089819183 },
882 .{ 14784310654990170340, 1448908652612273978 }, .{ 9257016281882937117, 1811135815765342473 },
883 .{ 16182956370781059300, 2263919769706678091 }, .{ 7808504722524468110, 1414949856066673807 },
884 .{ 5148944884728197234, 1768687320083342259 }, .{ 1824495087482858639, 2210859150104177824 },
885 .{ 1140309429676786649, 1381786968815111140 }, .{ 1425386787095983311, 1727233711018888925 },
886 .{ 6393419502297367043, 2159042138773611156 }, .{ 13219259225790630210, 1349401336733506972 },
887 .{ 16524074032238287762, 1686751670916883715 }, .{ 16043406521870471799, 2108439588646104644 },
888 .{ 803757039314269066, 1317774742903815403 }, .{ 14839754354425000045, 1647218428629769253 },
889 .{ 4714634887749086344, 2059023035787211567 }, .{ 9864175832484260821, 1286889397367007229 },
890 .{ 16941905809032713930, 1608611746708759036 }, .{ 2730638187581340797, 2010764683385948796 },
891 .{ 10930020904093113806, 1256727927116217997 }, .{ 18274212148543780162, 1570909908895272496 },
892 .{ 4396021111970173586, 1963637386119090621 }, .{ 5053356204195052443, 1227273366324431638 },
893 .{ 15540067292098591362, 1534091707905539547 }, .{ 14813398096695851299, 1917614634881924434 },
894 .{ 13870059828862294966, 1198509146801202771 }, .{ 12725888767650480803, 1498136433501503464 },
895 .{ 15907360959563101004, 1872670541876879330 }, .{ 14553786618154326031, 1170419088673049581 },
896 .{ 4357175217410743827, 1463023860841311977 }, .{ 10058155040190817688, 1828779826051639971 },
897 .{ 7961007781811134206, 2285974782564549964 }, .{ 14199001900486734687, 1428734239102843727 },
898 .{ 13137066357181030455, 1785917798878554659 }, .{ 11809646928048900164, 2232397248598193324 },
899 .{ 16604401366885338411, 1395248280373870827 }, .{ 16143815690179285109, 1744060350467338534 },
900 .{ 10956397575869330579, 2180075438084173168 }, .{ 6847748484918331612, 1362547148802608230 },
901 .{ 17783057643002690323, 1703183936003260287 }, .{ 17617136035325974999, 2128979920004075359 },
902 .{ 17928239049719816230, 1330612450002547099 }, .{ 17798612793722382384, 1663265562503183874 },
903 .{ 13024893955298202172, 2079081953128979843 }, .{ 5834715712847682405, 1299426220705612402 },
904 .{ 16516766677914378815, 1624282775882015502 }, .{ 11422586310538197711, 2030353469852519378 },
905 .{ 11750802462513761473, 1268970918657824611 }, .{ 10076817059714813937, 1586213648322280764 },
906 .{ 12596021324643517422, 1982767060402850955 }, .{ 5566670318688504437, 1239229412751781847 },
907 .{ 2346651879933242642, 1549036765939727309 }, .{ 7545000868343941206, 1936295957424659136 },
908 .{ 4715625542714963254, 1210184973390411960 }, .{ 5894531928393704067, 1512731216738014950 },
909 .{ 16591536947346905892, 1890914020922518687 }, .{ 17287239619732898039, 1181821263076574179 },
910 .{ 16997363506238734644, 1477276578845717724 }, .{ 2799960309088866689, 1846595723557147156 },
911 .{ 10973347230035317489, 1154122327223216972 }, .{ 13716684037544146861, 1442652909029021215 },
912 .{ 12534169028502795672, 1803316136286276519 }, .{ 11056025267201106687, 2254145170357845649 },
913 .{ 18439230838069161439, 1408840731473653530 }, .{ 13825666510731675991, 1761050914342066913 },
914 .{ 3447025083132431277, 2201313642927583642 }, .{ 6766076695385157452, 1375821026829739776 },
915 .{ 8457595869231446815, 1719776283537174720 }, .{ 10571994836539308519, 2149720354421468400 },
916 .{ 6607496772837067824, 1343575221513417750 }, .{ 17482743002901110588, 1679469026891772187 },
917 .{ 17241742735199000331, 2099336283614715234 }, .{ 15387775227926763111, 1312085177259197021 },
918 .{ 5399660979626290177, 1640106471573996277 }, .{ 11361262242960250625, 2050133089467495346 },
919 .{ 11712474920277544544, 1281333180917184591 }, .{ 10028907631919542777, 1601666476146480739 },
920 .{ 7924448521472040567, 2002083095183100924 }, .{ 14176152362774801162, 1251301934489438077 },
921 .{ 3885132398186337741, 1564127418111797597 }, .{ 9468101516160310080, 1955159272639746996 },
922 .{ 15140935484454969608, 1221974545399841872 }, .{ 479425281859160394, 1527468181749802341 },
923 .{ 5210967620751338397, 1909335227187252926 }, .{ 17091912818251750210, 1193334516992033078 },
924 .{ 12141518985959911954, 1491668146240041348 }, .{ 15176898732449889943, 1864585182800051685 },
925 .{ 11791404716994875166, 1165365739250032303 }, .{ 10127569877816206054, 1456707174062540379 },
926 .{ 8047776328842869663, 1820883967578175474 }, .{ 836348374198811271, 2276104959472719343 },
927 .{ 7440246761515338900, 1422565599670449589 }, .{ 13911994470321561530, 1778206999588061986 },
928 .{ 8166621051047176104, 2222758749485077483 }, .{ 2798295147690791113, 1389224218428173427 },
929 .{ 17332926989895652603, 1736530273035216783 }, .{ 17054472718942177850, 2170662841294020979 },
930 .{ 8353202440125167204, 1356664275808763112 }, .{ 10441503050156459005, 1695830344760953890 },
931 .{ 3828506775840797949, 2119787930951192363 }, .{ 86973725686804766, 1324867456844495227 },
932 .{ 13943775212390669669, 1656084321055619033 }, .{ 3594660960206173375, 2070105401319523792 },
933 .{ 2246663100128858359, 1293815875824702370 }, .{ 12031700912015848757, 1617269844780877962 },
934 .{ 5816254103165035138, 2021587305976097453 }, .{ 5941001823691840913, 1263492066235060908 },
935 .{ 7426252279614801142, 1579365082793826135 }, .{ 4671129331091113523, 1974206353492282669 },
936 .{ 5225298841145639904, 1233878970932676668 }, .{ 6531623551432049880, 1542348713665845835 },
937 .{ 3552843420862674446, 1927935892082307294 }, .{ 16055585193321335241, 1204959932551442058 },
938 .{ 10846109454796893243, 1506199915689302573 }, .{ 18169322836923504458, 1882749894611628216 },
939 .{ 11355826773077190286, 1176718684132267635 }, .{ 9583097447919099954, 1470898355165334544 },
940 .{ 11978871809898874942, 1838622943956668180 }, .{ 14973589762373593678, 2298278679945835225 },
941 .{ 2440964573842414192, 1436424174966147016 }, .{ 3051205717303017741, 1795530218707683770 },
942 .{ 13037379183483547984, 2244412773384604712 }, .{ 8148361989677217490, 1402757983365377945 },
943 .{ 14797138505523909766, 1753447479206722431 }, .{ 13884737113477499304, 2191809349008403039 },
944 .{ 15595489723564518921, 1369880843130251899 }, .{ 14882676136028260747, 1712351053912814874 },
945 .{ 9379973133180550126, 2140438817391018593 }, .{ 17391698254306313589, 1337774260869386620 },
946 .{ 3292878744173340370, 1672217826086733276 }, .{ 4116098430216675462, 2090272282608416595 },
947 .{ 266718509671728212, 1306420176630260372 }, .{ 333398137089660265, 1633025220787825465 },
948 .{ 5028433689789463235, 2041281525984781831 }, .{ 10060300083759496378, 1275800953740488644 },
949 .{ 12575375104699370472, 1594751192175610805 }, .{ 1884160825592049379, 1993438990219513507 },
950 .{ 17318501580490888525, 1245899368887195941 }, .{ 7813068920331446945, 1557374211108994927 },
951 .{ 5154650131986920777, 1946717763886243659 }, .{ 915813323278131534, 1216698602428902287 },
952 .{ 14979824709379828129, 1520873253036127858 }, .{ 9501408849870009354, 1901091566295159823 },
953 .{ 12855909558809837702, 1188182228934474889 }, .{ 2234828893230133415, 1485227786168093612 },
954 .{ 2793536116537666769, 1856534732710117015 }, .{ 8663489100477123587, 1160334207943823134 },
955 .{ 1605989338741628675, 1450417759929778918 }, .{ 11230858710281811652, 1813022199912223647 },
956 .{ 9426887369424876662, 2266277749890279559 }, .{ 12809333633531629769, 1416423593681424724 },
957 .{ 16011667041914537212, 1770529492101780905 }, .{ 6179525747111007803, 2213161865127226132 },
958 .{ 13085575628799155685, 1383226165704516332 }, .{ 16356969535998944606, 1729032707130645415 },
959 .{ 15834525901571292854, 2161290883913306769 }, .{ 2979049660840976177, 1350806802445816731 },
960 .{ 17558870131333383934, 1688508503057270913 }, .{ 8113529608884566205, 2110635628821588642 },
961 .{ 9682642023980241782, 1319147268013492901 }, .{ 16714988548402690132, 1648934085016866126 },
962 .{ 11670363648648586857, 2061167606271082658 }, .{ 11905663298832754689, 1288229753919426661 },
963 .{ 1047021068258779650, 1610287192399283327 }, .{ 15143834390605638274, 2012858990499104158 },
964 .{ 4853210475701136017, 1258036869061940099 }, .{ 1454827076199032118, 1572546086327425124 },
965 .{ 1818533845248790147, 1965682607909281405 }, .{ 3442426662494187794, 1228551629943300878 },
966 .{ 13526405364972510550, 1535689537429126097 }, .{ 3072948650933474476, 1919611921786407622 },
967 .{ 15755650962115585259, 1199757451116504763 }, .{ 15082877684217093670, 1499696813895630954 },
968 .{ 9630225068416591280, 1874621017369538693 }, .{ 8324733676974063502, 1171638135855961683 },
969 .{ 5794231077790191473, 1464547669819952104 }, .{ 7242788847237739342, 1830684587274940130 },
970 .{ 18276858095901949986, 2288355734093675162 }, .{ 16034722328366106645, 1430222333808546976 },
971 .{ 1596658836748081690, 1787777917260683721 }, .{ 6607509564362490017, 2234722396575854651 },
972 .{ 1823850468512862308, 1396701497859909157 }, .{ 6891499104068465790, 1745876872324886446 },
973 .{ 17837745916940358045, 2182346090406108057 }, .{ 4231062170446641922, 1363966306503817536 },
974 .{ 5288827713058302403, 1704957883129771920 }, .{ 6611034641322878003, 2131197353912214900 },
975 .{ 13355268687681574560, 1331998346195134312 }, .{ 16694085859601968200, 1664997932743917890 },
976 .{ 11644235287647684442, 2081247415929897363 }, .{ 4971804045566108824, 1300779634956185852 },
977 .{ 6214755056957636030, 1625974543695232315 }, .{ 3156757802769657134, 2032468179619040394 },
978 .{ 6584659645158423613, 1270292612261900246 }, .{ 17454196593302805324, 1587865765327375307 },
979 .{ 17206059723201118751, 1984832206659219134 }, .{ 6142101308573311315, 1240520129162011959 },
980 .{ 3065940617289251240, 1550650161452514949 }, .{ 8444111790038951954, 1938312701815643686 },
981 .{ 665883850346957067, 1211445438634777304 }, .{ 832354812933696334, 1514306798293471630 },
982 .{ 10263815553021896226, 1892883497866839537 }, .{ 17944099766707154901, 1183052186166774710 },
983 .{ 13206752671529167818, 1478815232708468388 }, .{ 16508440839411459773, 1848519040885585485 },
984 .{ 12623618533845856310, 1155324400553490928 }, .{ 15779523167307320387, 1444155500691863660 },
985 .{ 1277659885424598868, 1805194375864829576 }, .{ 1597074856780748586, 2256492969831036970 },
986 .{ 5609857803915355770, 1410308106144398106 }, .{ 16235694291748970521, 1762885132680497632 },
987 .{ 1847873790976661535, 2203606415850622041 }, .{ 12684136165428883219, 1377254009906638775 },
988 .{ 11243484188358716120, 1721567512383298469 }, .{ 219297180166231438, 2151959390479123087 },
989 .{ 7054589765244976505, 1344974619049451929 }, .{ 13429923224983608535, 1681218273811814911 },
990 .{ 12175718012802122765, 2101522842264768639 }, .{ 14527352785642408584, 1313451776415480399 },
991 .{ 13547504963625622826, 1641814720519350499 }, .{ 12322695186104640628, 2052268400649188124 },
992 .{ 16925056528170176201, 1282667750405742577 }, .{ 7321262604930556539, 1603334688007178222 },
993 .{ 18374950293017971482, 2004168360008972777 }, .{ 4566814905495150320, 1252605225005607986 },
994 .{ 14931890668723713708, 1565756531257009982 }, .{ 9441491299049866327, 1957195664071262478 },
995 .{ 1289246043478778550, 1223247290044539049 }, .{ 6223243572775861092, 1529059112555673811 },
996 .{ 3167368447542438461, 1911323890694592264 }, .{ 1979605279714024038, 1194577431684120165 },
997 .{ 7086192618069917952, 1493221789605150206 }, .{ 18081112809442173248, 1866527237006437757 },
998 .{ 13606538515115052232, 1166579523129023598 }, .{ 7784801107039039482, 1458224403911279498 },
999 .{ 507629346944023544, 1822780504889099373 }, .{ 5246222702107417334, 2278475631111374216 },
1000 .{ 3278889188817135834, 1424047269444608885 }, .{ 8710297504448807696, 1780059086805761106 }
1001};
1002
1003const FLOAT64_POW5_INV_SPLIT: [342][2]u64 = .{
1004 .{ 1, 2305843009213693952 }, .{ 11068046444225730970, 1844674407370955161 },
1005 .{ 5165088340638674453, 1475739525896764129 }, .{ 7821419487252849886, 1180591620717411303 },
1006 .{ 8824922364862649494, 1888946593147858085 }, .{ 7059937891890119595, 1511157274518286468 },
1007 .{ 13026647942995916322, 1208925819614629174 }, .{ 9774590264567735146, 1934281311383406679 },
1008 .{ 11509021026396098440, 1547425049106725343 }, .{ 16585914450600699399, 1237940039285380274 },
1009 .{ 15469416676735388068, 1980704062856608439 }, .{ 16064882156130220778, 1584563250285286751 },
1010 .{ 9162556910162266299, 1267650600228229401 }, .{ 7281393426775805432, 2028240960365167042 },
1011 .{ 16893161185646375315, 1622592768292133633 }, .{ 2446482504291369283, 1298074214633706907 },
1012 .{ 7603720821608101175, 2076918743413931051 }, .{ 2393627842544570617, 1661534994731144841 },
1013 .{ 16672297533003297786, 1329227995784915872 }, .{ 11918280793837635165, 2126764793255865396 },
1014 .{ 5845275820328197809, 1701411834604692317 }, .{ 15744267100488289217, 1361129467683753853 },
1015 .{ 3054734472329800808, 2177807148294006166 }, .{ 17201182836831481939, 1742245718635204932 },
1016 .{ 6382248639981364905, 1393796574908163946 }, .{ 2832900194486363201, 2230074519853062314 },
1017 .{ 5955668970331000884, 1784059615882449851 }, .{ 1075186361522890384, 1427247692705959881 },
1018 .{ 12788344622662355584, 2283596308329535809 }, .{ 13920024512871794791, 1826877046663628647 },
1019 .{ 3757321980813615186, 1461501637330902918 }, .{ 10384555214134712795, 1169201309864722334 },
1020 .{ 5547241898389809503, 1870722095783555735 }, .{ 4437793518711847602, 1496577676626844588 },
1021 .{ 10928932444453298728, 1197262141301475670 }, .{ 17486291911125277965, 1915619426082361072 },
1022 .{ 6610335899416401726, 1532495540865888858 }, .{ 12666966349016942027, 1225996432692711086 },
1023 .{ 12888448528943286597, 1961594292308337738 }, .{ 17689456452638449924, 1569275433846670190 },
1024 .{ 14151565162110759939, 1255420347077336152 }, .{ 7885109000409574610, 2008672555323737844 },
1025 .{ 9997436015069570011, 1606938044258990275 }, .{ 7997948812055656009, 1285550435407192220 },
1026 .{ 12796718099289049614, 2056880696651507552 }, .{ 2858676849947419045, 1645504557321206042 },
1027 .{ 13354987924183666206, 1316403645856964833 }, .{ 17678631863951955605, 2106245833371143733 },
1028 .{ 3074859046935833515, 1684996666696914987 }, .{ 13527933681774397782, 1347997333357531989 },
1029 .{ 10576647446613305481, 2156795733372051183 }, .{ 15840015586774465031, 1725436586697640946 },
1030 .{ 8982663654677661702, 1380349269358112757 }, .{ 18061610662226169046, 2208558830972980411 },
1031 .{ 10759939715039024913, 1766847064778384329 }, .{ 12297300586773130254, 1413477651822707463 },
1032 .{ 15986332124095098083, 2261564242916331941 }, .{ 9099716884534168143, 1809251394333065553 },
1033 .{ 14658471137111155161, 1447401115466452442 }, .{ 4348079280205103483, 1157920892373161954 },
1034 .{ 14335624477811986218, 1852673427797059126 }, .{ 7779150767507678651, 1482138742237647301 },
1035 .{ 2533971799264232598, 1185710993790117841 }, .{ 15122401323048503126, 1897137590064188545 },
1036 .{ 12097921058438802501, 1517710072051350836 }, .{ 5988988032009131678, 1214168057641080669 },
1037 .{ 16961078480698431330, 1942668892225729070 }, .{ 13568862784558745064, 1554135113780583256 },
1038 .{ 7165741412905085728, 1243308091024466605 }, .{ 11465186260648137165, 1989292945639146568 },
1039 .{ 16550846638002330379, 1591434356511317254 }, .{ 16930026125143774626, 1273147485209053803 },
1040 .{ 4951948911778577463, 2037035976334486086 }, .{ 272210314680951647, 1629628781067588869 },
1041 .{ 3907117066486671641, 1303703024854071095 }, .{ 6251387306378674625, 2085924839766513752 },
1042 .{ 16069156289328670670, 1668739871813211001 }, .{ 9165976216721026213, 1334991897450568801 },
1043 .{ 7286864317269821294, 2135987035920910082 }, .{ 16897537898041588005, 1708789628736728065 },
1044 .{ 13518030318433270404, 1367031702989382452 }, .{ 6871453250525591353, 2187250724783011924 },
1045 .{ 9186511415162383406, 1749800579826409539 }, .{ 11038557946871817048, 1399840463861127631 },
1046 .{ 10282995085511086630, 2239744742177804210 }, .{ 8226396068408869304, 1791795793742243368 },
1047 .{ 13959814484210916090, 1433436634993794694 }, .{ 11267656730511734774, 2293498615990071511 },
1048 .{ 5324776569667477496, 1834798892792057209 }, .{ 7949170070475892320, 1467839114233645767 },
1049 .{ 17427382500606444826, 1174271291386916613 }, .{ 5747719112518849781, 1878834066219066582 },
1050 .{ 15666221734240810795, 1503067252975253265 }, .{ 12532977387392648636, 1202453802380202612 },
1051 .{ 5295368560860596524, 1923926083808324180 }, .{ 4236294848688477220, 1539140867046659344 },
1052 .{ 7078384693692692099, 1231312693637327475 }, .{ 11325415509908307358, 1970100309819723960 },
1053 .{ 9060332407926645887, 1576080247855779168 }, .{ 14626963555825137356, 1260864198284623334 },
1054 .{ 12335095245094488799, 2017382717255397335 }, .{ 9868076196075591040, 1613906173804317868 },
1055 .{ 15273158586344293478, 1291124939043454294 }, .{ 13369007293925138595, 2065799902469526871 },
1056 .{ 7005857020398200553, 1652639921975621497 }, .{ 16672732060544291412, 1322111937580497197 },
1057 .{ 11918976037903224966, 2115379100128795516 }, .{ 5845832015580669650, 1692303280103036413 },
1058 .{ 12055363241948356366, 1353842624082429130 }, .{ 841837113407818570, 2166148198531886609 },
1059 .{ 4362818505468165179, 1732918558825509287 }, .{ 14558301248600263113, 1386334847060407429 },
1060 .{ 12225235553534690011, 2218135755296651887 }, .{ 2401490813343931363, 1774508604237321510 },
1061 .{ 1921192650675145090, 1419606883389857208 }, .{ 17831303500047873437, 2271371013423771532 },
1062 .{ 6886345170554478103, 1817096810739017226 }, .{ 1819727321701672159, 1453677448591213781 },
1063 .{ 16213177116328979020, 1162941958872971024 }, .{ 14873036941900635463, 1860707134196753639 },
1064 .{ 15587778368262418694, 1488565707357402911 }, .{ 8780873879868024632, 1190852565885922329 },
1065 .{ 2981351763563108441, 1905364105417475727 }, .{ 13453127855076217722, 1524291284333980581 },
1066 .{ 7073153469319063855, 1219433027467184465 }, .{ 11317045550910502167, 1951092843947495144 },
1067 .{ 12742985255470312057, 1560874275157996115 }, .{ 10194388204376249646, 1248699420126396892 },
1068 .{ 1553625868034358140, 1997919072202235028 }, .{ 8621598323911307159, 1598335257761788022 },
1069 .{ 17965325103354776697, 1278668206209430417 }, .{ 13987124906400001422, 2045869129935088668 },
1070 .{ 121653480894270168, 1636695303948070935 }, .{ 97322784715416134, 1309356243158456748 },
1071 .{ 14913111714512307107, 2094969989053530796 }, .{ 8241140556867935363, 1675975991242824637 },
1072 .{ 17660958889720079260, 1340780792994259709 }, .{ 17189487779326395846, 2145249268790815535 },
1073 .{ 13751590223461116677, 1716199415032652428 }, .{ 18379969808252713988, 1372959532026121942 },
1074 .{ 14650556434236701088, 2196735251241795108 }, .{ 652398703163629901, 1757388200993436087 },
1075 .{ 11589965406756634890, 1405910560794748869 }, .{ 7475898206584884855, 2249456897271598191 },
1076 .{ 2291369750525997561, 1799565517817278553 }, .{ 9211793429904618695, 1439652414253822842 },
1077 .{ 18428218302589300235, 2303443862806116547 }, .{ 7363877012587619542, 1842755090244893238 },
1078 .{ 13269799239553916280, 1474204072195914590 }, .{ 10615839391643133024, 1179363257756731672 },
1079 .{ 2227947767661371545, 1886981212410770676 }, .{ 16539753473096738529, 1509584969928616540 },
1080 .{ 13231802778477390823, 1207667975942893232 }, .{ 6413489186596184024, 1932268761508629172 },
1081 .{ 16198837793502678189, 1545815009206903337 }, .{ 5580372605318321905, 1236652007365522670 },
1082 .{ 8928596168509315048, 1978643211784836272 }, .{ 18210923379033183008, 1582914569427869017 },
1083 .{ 7190041073742725760, 1266331655542295214 }, .{ 436019273762630246, 2026130648867672343 },
1084 .{ 7727513048493924843, 1620904519094137874 }, .{ 9871359253537050198, 1296723615275310299 },
1085 .{ 4726128361433549347, 2074757784440496479 }, .{ 7470251503888749801, 1659806227552397183 },
1086 .{ 13354898832594820487, 1327844982041917746 }, .{ 13989140502667892133, 2124551971267068394 },
1087 .{ 14880661216876224029, 1699641577013654715 }, .{ 11904528973500979224, 1359713261610923772 },
1088 .{ 4289851098633925465, 2175541218577478036 }, .{ 18189276137874781665, 1740432974861982428 },
1089 .{ 3483374466074094362, 1392346379889585943 }, .{ 1884050330976640656, 2227754207823337509 },
1090 .{ 5196589079523222848, 1782203366258670007 }, .{ 15225317707844309248, 1425762693006936005 },
1091 .{ 5913764258841343181, 2281220308811097609 }, .{ 8420360221814984868, 1824976247048878087 },
1092 .{ 17804334621677718864, 1459980997639102469 }, .{ 17932816512084085415, 1167984798111281975 },
1093 .{ 10245762345624985047, 1868775676978051161 }, .{ 4507261061758077715, 1495020541582440929 },
1094 .{ 7295157664148372495, 1196016433265952743 }, .{ 7982903447895485668, 1913626293225524389 },
1095 .{ 10075671573058298858, 1530901034580419511 }, .{ 4371188443704728763, 1224720827664335609 },
1096 .{ 14372599139411386667, 1959553324262936974 }, .{ 15187428126271019657, 1567642659410349579 },
1097 .{ 15839291315758726049, 1254114127528279663 }, .{ 3206773216762499739, 2006582604045247462 },
1098 .{ 13633465017635730761, 1605266083236197969 }, .{ 14596120828850494932, 1284212866588958375 },
1099 .{ 4907049252451240275, 2054740586542333401 }, .{ 236290587219081897, 1643792469233866721 },
1100 .{ 14946427728742906810, 1315033975387093376 }, .{ 16535586736504830250, 2104054360619349402 },
1101 .{ 5849771759720043554, 1683243488495479522 }, .{ 15747863852001765813, 1346594790796383617 },
1102 .{ 10439186904235184007, 2154551665274213788 }, .{ 15730047152871967852, 1723641332219371030 },
1103 .{ 12584037722297574282, 1378913065775496824 }, .{ 9066413911450387881, 2206260905240794919 },
1104 .{ 10942479943902220628, 1765008724192635935 }, .{ 8753983955121776503, 1412006979354108748 },
1105 .{ 10317025513452932081, 2259211166966573997 }, .{ 874922781278525018, 1807368933573259198 },
1106 .{ 8078635854506640661, 1445895146858607358 }, .{ 13841606313089133175, 1156716117486885886 },
1107 .{ 14767872471458792434, 1850745787979017418 }, .{ 746251532941302978, 1480596630383213935 },
1108 .{ 597001226353042382, 1184477304306571148 }, .{ 15712597221132509104, 1895163686890513836 },
1109 .{ 8880728962164096960, 1516130949512411069 }, .{ 10793931984473187891, 1212904759609928855 },
1110 .{ 17270291175157100626, 1940647615375886168 }, .{ 2748186495899949531, 1552518092300708935 },
1111 .{ 2198549196719959625, 1242014473840567148 }, .{ 18275073973719576693, 1987223158144907436 },
1112 .{ 10930710364233751031, 1589778526515925949 }, .{ 12433917106128911148, 1271822821212740759 },
1113 .{ 8826220925580526867, 2034916513940385215 }, .{ 7060976740464421494, 1627933211152308172 },
1114 .{ 16716827836597268165, 1302346568921846537 }, .{ 11989529279587987770, 2083754510274954460 },
1115 .{ 9591623423670390216, 1667003608219963568 }, .{ 15051996368420132820, 1333602886575970854 },
1116 .{ 13015147745246481542, 2133764618521553367 }, .{ 3033420566713364587, 1707011694817242694 },
1117 .{ 6116085268112601993, 1365609355853794155 }, .{ 9785736428980163188, 2184974969366070648 },
1118 .{ 15207286772667951197, 1747979975492856518 }, .{ 1097782973908629988, 1398383980394285215 },
1119 .{ 1756452758253807981, 2237414368630856344 }, .{ 5094511021344956708, 1789931494904685075 },
1120 .{ 4075608817075965366, 1431945195923748060 }, .{ 6520974107321544586, 2291112313477996896 },
1121 .{ 1527430471115325346, 1832889850782397517 }, .{ 12289990821117991246, 1466311880625918013 },
1122 .{ 17210690286378213644, 1173049504500734410 }, .{ 9090360384495590213, 1876879207201175057 },
1123 .{ 18340334751822203140, 1501503365760940045 }, .{ 14672267801457762512, 1201202692608752036 },
1124 .{ 16096930852848599373, 1921924308174003258 }, .{ 1809498238053148529, 1537539446539202607 },
1125 .{ 12515645034668249793, 1230031557231362085 }, .{ 1578287981759648052, 1968050491570179337 },
1126 .{ 12330676829633449412, 1574440393256143469 }, .{ 13553890278448669853, 1259552314604914775 },
1127 .{ 3239480371808320148, 2015283703367863641 }, .{ 17348979556414297411, 1612226962694290912 },
1128 .{ 6500486015647617283, 1289781570155432730 }, .{ 10400777625036187652, 2063650512248692368 },
1129 .{ 15699319729512770768, 1650920409798953894 }, .{ 16248804598352126938, 1320736327839163115 },
1130 .{ 7551343283653851484, 2113178124542660985 }, .{ 6041074626923081187, 1690542499634128788 },
1131 .{ 12211557331022285596, 1352433999707303030 }, .{ 1091747655926105338, 2163894399531684849 },
1132 .{ 4562746939482794594, 1731115519625347879 }, .{ 7339546366328145998, 1384892415700278303 },
1133 .{ 8053925371383123274, 2215827865120445285 }, .{ 6443140297106498619, 1772662292096356228 },
1134 .{ 12533209867169019542, 1418129833677084982 }, .{ 5295740528502789974, 2269007733883335972 },
1135 .{ 15304638867027962949, 1815206187106668777 }, .{ 4865013464138549713, 1452164949685335022 },
1136 .{ 14960057215536570740, 1161731959748268017 }, .{ 9178696285890871890, 1858771135597228828 },
1137 .{ 14721654658196518159, 1487016908477783062 }, .{ 4398626097073393881, 1189613526782226450 },
1138 .{ 7037801755317430209, 1903381642851562320 }, .{ 5630241404253944167, 1522705314281249856 },
1139 .{ 814844308661245011, 1218164251424999885 }, .{ 1303750893857992017, 1949062802279999816 },
1140 .{ 15800395974054034906, 1559250241823999852 }, .{ 5261619149759407279, 1247400193459199882 },
1141 .{ 12107939454356961969, 1995840309534719811 }, .{ 5997002748743659252, 1596672247627775849 },
1142 .{ 8486951013736837725, 1277337798102220679 }, .{ 2511075177753209390, 2043740476963553087 },
1143 .{ 13076906586428298482, 1634992381570842469 }, .{ 14150874083884549109, 1307993905256673975 },
1144 .{ 4194654460505726958, 2092790248410678361 }, .{ 18113118827372222859, 1674232198728542688 },
1145 .{ 3422448617672047318, 1339385758982834151 }, .{ 16543964232501006678, 2143017214372534641 },
1146 .{ 9545822571258895019, 1714413771498027713 }, .{ 15015355686490936662, 1371531017198422170 },
1147 .{ 5577825024675947042, 2194449627517475473 }, .{ 11840957649224578280, 1755559702013980378 },
1148 .{ 16851463748863483271, 1404447761611184302 }, .{ 12204946739213931940, 2247116418577894884 },
1149 .{ 13453306206113055875, 1797693134862315907 }, .{ 3383947335406624054, 1438154507889852726 },
1150 .{ 16482362180876329456, 2301047212623764361 }, .{ 9496540929959153242, 1840837770099011489 },
1151 .{ 11286581558709232917, 1472670216079209191 }, .{ 5339916432225476010, 1178136172863367353 },
1152 .{ 4854517476818851293, 1885017876581387765 }, .{ 3883613981455081034, 1508014301265110212 },
1153 .{ 14174937629389795797, 1206411441012088169 }, .{ 11611853762797942306, 1930258305619341071 },
1154 .{ 5600134195496443521, 1544206644495472857 }, .{ 15548153800622885787, 1235365315596378285 },
1155 .{ 6430302007287065643, 1976584504954205257 }, .{ 16212288050055383484, 1581267603963364205 },
1156 .{ 12969830440044306787, 1265014083170691364 }, .{ 9683682259845159889, 2024022533073106183 },
1157 .{ 15125643437359948558, 1619218026458484946 }, .{ 8411165935146048523, 1295374421166787957 },
1158 .{ 17147214310975587960, 2072599073866860731 }, .{ 10028422634038560045, 1658079259093488585 },
1159 .{ 8022738107230848036, 1326463407274790868 }, .{ 9147032156827446534, 2122341451639665389 },
1160 .{ 11006974540203867551, 1697873161311732311 }, .{ 5116230817421183718, 1358298529049385849 },
1161 .{ 15564666937357714594, 2173277646479017358 }, .{ 1383687105660440706, 1738622117183213887 },
1162 .{ 12174996128754083534, 1390897693746571109 }, .{ 8411947361780802685, 2225436309994513775 },
1163 .{ 6729557889424642148, 1780349047995611020 }, .{ 5383646311539713719, 1424279238396488816 },
1164 .{ 1235136468979721303, 2278846781434382106 }, .{ 15745504434151418335, 1823077425147505684 },
1165 .{ 16285752362063044992, 1458461940118004547 }, .{ 5649904260166615347, 1166769552094403638 },
1166 .{ 5350498001524674232, 1866831283351045821 }, .{ 591049586477829062, 1493465026680836657 },
1167 .{ 11540886113407994219, 1194772021344669325 }, .{ 18673707743239135, 1911635234151470921 },
1168 .{ 14772334225162232601, 1529308187321176736 }, .{ 8128518565387875758, 1223446549856941389 },
1169 .{ 1937583260394870242, 1957514479771106223 }, .{ 8928764237799716840, 1566011583816884978 },
1170 .{ 14521709019723594119, 1252809267053507982 }, .{ 8477339172590109297, 2004494827285612772 },
1171 .{ 17849917782297818407, 1603595861828490217 }, .{ 6901236596354434079, 1282876689462792174 },
1172 .{ 18420676183650915173, 2052602703140467478 }, .{ 3668494502695001169, 1642082162512373983 },
1173 .{ 10313493231639821582, 1313665730009899186 }, .{ 9122891541139893884, 2101865168015838698 },
1174 .{ 14677010862395735754, 1681492134412670958 }, .{ 673562245690857633, 1345193707530136767 }
1175};
1176
1177// zig fmt: off
1178//
1179// f128 small tables: 9072 bytes
1180
1181const FLOAT128_POW5_INV_BITCOUNT = 249;
1182const FLOAT128_POW5_BITCOUNT = 249;
1183const FLOAT128_POW5_TABLE_SIZE: comptime_int = FLOAT128_POW5_TABLE.len;
1184
1185const FLOAT128_POW5_TABLE: [56][2]u64 = .{
1186 .{ 1, 0 },
1187 .{ 5, 0 },
1188 .{ 25, 0 },
1189 .{ 125, 0 },
1190 .{ 625, 0 },
1191 .{ 3125, 0 },
1192 .{ 15625, 0 },
1193 .{ 78125, 0 },
1194 .{ 390625, 0 },
1195 .{ 1953125, 0 },
1196 .{ 9765625, 0 },
1197 .{ 48828125, 0 },
1198 .{ 244140625, 0 },
1199 .{ 1220703125, 0 },
1200 .{ 6103515625, 0 },
1201 .{ 30517578125, 0 },
1202 .{ 152587890625, 0 },
1203 .{ 762939453125, 0 },
1204 .{ 3814697265625, 0 },
1205 .{ 19073486328125, 0 },
1206 .{ 95367431640625, 0 },
1207 .{ 476837158203125, 0 },
1208 .{ 2384185791015625, 0 },
1209 .{ 11920928955078125, 0 },
1210 .{ 59604644775390625, 0 },
1211 .{ 298023223876953125, 0 },
1212 .{ 1490116119384765625, 0 },
1213 .{ 7450580596923828125, 0 },
1214 .{ 359414837200037393, 2 },
1215 .{ 1797074186000186965, 10 },
1216 .{ 8985370930000934825, 50 },
1217 .{ 8033366502585570893, 252 },
1218 .{ 3273344365508751233, 1262 },
1219 .{ 16366721827543756165, 6310 },
1220 .{ 8046632842880574361, 31554 },
1221 .{ 3339676066983768573, 157772 },
1222 .{ 16698380334918842865, 788860 },
1223 .{ 9704925379756007861, 3944304 },
1224 .{ 11631138751360936073, 19721522 },
1225 .{ 2815461535676025517, 98607613 },
1226 .{ 14077307678380127585, 493038065 },
1227 .{ 15046306170771983077, 2465190328 },
1228 .{ 1444554559021708921, 12325951644 },
1229 .{ 7222772795108544605, 61629758220 },
1230 .{ 17667119901833171409, 308148791101 },
1231 .{ 14548623214327650581, 1540743955509 },
1232 .{ 17402883850509598057, 7703719777548 },
1233 .{ 13227442957709783821, 38518598887744 },
1234 .{ 10796982567420264257, 192592994438723 },
1235 .{ 17091424689682218053, 962964972193617 },
1236 .{ 11670147153572883801, 4814824860968089 },
1237 .{ 3010503546735764157, 24074124304840448 },
1238 .{ 15052517733678820785, 120370621524202240 },
1239 .{ 1475612373555897461, 601853107621011204 },
1240 .{ 7378061867779487305, 3009265538105056020 },
1241 .{ 18443565265187884909, 15046327690525280101 },
1242};
1243
1244const FLOAT128_POW5_SPLIT: [89][4]u64 = .{
1245 .{ 0, 0, 0, 72057594037927936 },
1246 .{ 0, 5206161169240293376, 4575641699882439235, 73468396926392969 },
1247 .{ 3360510775605221349, 6983200512169538081, 4325643253124434363, 74906821675075173 },
1248 .{ 11917660854915489451, 9652941469841108803, 946308467778435600, 76373409087490117 },
1249 .{ 1994853395185689235, 16102657350889591545, 6847013871814915412, 77868710555449746 },
1250 .{ 958415760277438274, 15059347134713823592, 7329070255463483331, 79393288266368765 },
1251 .{ 2065144883315240188, 7145278325844925976, 14718454754511147343, 80947715414629833 },
1252 .{ 8980391188862868935, 13709057401304208685, 8230434828742694591, 82532576417087045 },
1253 .{ 432148644612782575, 7960151582448466064, 12056089168559840552, 84148467132788711 },
1254 .{ 484109300864744403, 15010663910730448582, 16824949663447227068, 85795995087002057 },
1255 .{ 14793711725276144220, 16494403799991899904, 10145107106505865967, 87475779699624060 },
1256 .{ 15427548291869817042, 12330588654550505203, 13980791795114552342, 89188452518064298 },
1257 .{ 9979404135116626552, 13477446383271537499, 14459862802511591337, 90934657454687378 },
1258 .{ 12385121150303452775, 9097130814231585614, 6523855782339765207, 92715051028904201 },
1259 .{ 1822931022538209743, 16062974719797586441, 3619180286173516788, 94530302614003091 },
1260 .{ 12318611738248470829, 13330752208259324507, 10986694768744162601, 96381094688813589 },
1261 .{ 13684493829640282333, 7674802078297225834, 15208116197624593182, 98268123094297527 },
1262 .{ 5408877057066295332, 6470124174091971006, 15112713923117703147, 100192097295163851 },
1263 .{ 11407083166564425062, 18189998238742408185, 4337638702446708282, 102153740646605557 },
1264 .{ 4112405898036935485, 924624216579956435, 14251108172073737125, 104153790666259019 },
1265 .{ 16996739107011444789, 10015944118339042475, 2395188869672266257, 106192999311487969 },
1266 .{ 4588314690421337879, 5339991768263654604, 15441007590670620066, 108272133262096356 },
1267 .{ 2286159977890359825, 14329706763185060248, 5980012964059367667, 110391974208576409 },
1268 .{ 9654767503237031099, 11293544302844823188, 11739932712678287805, 112553319146000238 },
1269 .{ 11362964448496095896, 7990659682315657680, 251480263940996374, 114756980673665505 },
1270 .{ 1423410421096377129, 14274395557581462179, 16553482793602208894, 117003787300607788 },
1271 .{ 2070444190619093137, 11517140404712147401, 11657844572835578076, 119294583757094535 },
1272 .{ 7648316884775828921, 15264332483297977688, 247182277434709002, 121630231312217685 },
1273 .{ 17410896758132241352, 10923914482914417070, 13976383996795783649, 124011608097704390 },
1274 .{ 9542674537907272703, 3079432708831728956, 14235189590642919676, 126439609438067572 },
1275 .{ 10364666969937261816, 8464573184892924210, 12758646866025101190, 128915148187220428 },
1276 .{ 14720354822146013883, 11480204489231511423, 7449876034836187038, 131439155071681461 },
1277 .{ 1692907053653558553, 17835392458598425233, 1754856712536736598, 134012579040499057 },
1278 .{ 5620591334531458755, 11361776175667106627, 13350215315297937856, 136636387622027174 },
1279 .{ 17455759733928092601, 10362573084069962561, 11246018728801810510, 139311567287686283 },
1280 .{ 2465404073814044982, 17694822665274381860, 1509954037718722697, 142039123822846312 },
1281 .{ 2152236053329638369, 11202280800589637091, 16388426812920420176, 72410041352485523 },
1282 .{ 17319024055671609028, 10944982848661280484, 2457150158022562661, 73827744744583080 },
1283 .{ 17511219308535248024, 5122059497846768077, 2089605804219668451, 75273205100637900 },
1284 .{ 10082673333144031533, 14429008783411894887, 12842832230171903890, 76746965869337783 },
1285 .{ 16196653406315961184, 10260180891682904501, 10537411930446752461, 78249581139456266 },
1286 .{ 15084422041749743389, 234835370106753111, 16662517110286225617, 79781615848172976 },
1287 .{ 8199644021067702606, 3787318116274991885, 7438130039325743106, 81343645993472659 },
1288 .{ 12039493937039359765, 9773822153580393709, 5945428874398357806, 82936258850702722 },
1289 .{ 984543865091303961, 7975107621689454830, 6556665988501773347, 84560053193370726 },
1290 .{ 9633317878125234244, 16099592426808915028, 9706674539190598200, 86215639518264828 },
1291 .{ 6860695058870476186, 4471839111886709592, 7828342285492709568, 87903640274981819 },
1292 .{ 14583324717644598331, 4496120889473451238, 5290040788305728466, 89624690099949049 },
1293 .{ 18093669366515003715, 12879506572606942994, 18005739787089675377, 91379436055028227 },
1294 .{ 17997493966862379937, 14646222655265145582, 10265023312844161858, 93168537870790806 },
1295 .{ 12283848109039722318, 11290258077250314935, 9878160025624946825, 94992668194556404 },
1296 .{ 8087752761883078164, 5262596608437575693, 11093553063763274413, 96852512843287537 },
1297 .{ 15027787746776840781, 12250273651168257752, 9290470558712181914, 98748771061435726 },
1298 .{ 15003915578366724489, 2937334162439764327, 5404085603526796602, 100682155783835929 },
1299 .{ 5225610465224746757, 14932114897406142027, 2774647558180708010, 102653393903748137 },
1300 .{ 17112957703385190360, 12069082008339002412, 3901112447086388439, 104663226546146909 },
1301 .{ 4062324464323300238, 3992768146772240329, 15757196565593695724, 106712409346361594 },
1302 .{ 5525364615810306701, 11855206026704935156, 11344868740897365300, 108801712734172003 },
1303 .{ 9274143661888462646, 4478365862348432381, 18010077872551661771, 110931922223466333 },
1304 .{ 12604141221930060148, 8930937759942591500, 9382183116147201338, 113103838707570263 },
1305 .{ 14513929377491886653, 1410646149696279084, 587092196850797612, 115318278760358235 },
1306 .{ 2226851524999454362, 7717102471110805679, 7187441550995571734, 117576074943260147 },
1307 .{ 5527526061344932763, 2347100676188369132, 16976241418824030445, 119878076118278875 },
1308 .{ 6088479778147221611, 17669593130014777580, 10991124207197663546, 122225147767136307 },
1309 .{ 11107734086759692041, 3391795220306863431, 17233960908859089158, 124618172316667879 },
1310 .{ 7913172514655155198, 17726879005381242552, 641069866244011540, 127058049470587962 },
1311 .{ 12596991768458713949, 15714785522479904446, 6035972567136116512, 129545696547750811 },
1312 .{ 16901996933781815980, 4275085211437148707, 14091642539965169063, 132082048827034281 },
1313 .{ 7524574627987869240, 15661204384239316051, 2444526454225712267, 134668059898975949 },
1314 .{ 8199251625090479942, 6803282222165044067, 16064817666437851504, 137304702024293857 },
1315 .{ 4453256673338111920, 15269922543084434181, 3139961729834750852, 139992966499426682 },
1316 .{ 15841763546372731299, 3013174075437671812, 4383755396295695606, 142733864029230733 },
1317 .{ 9771896230907310329, 4900659362437687569, 12386126719044266361, 72764212553486967 },
1318 .{ 9420455527449565190, 1859606122611023693, 6555040298902684281, 74188850200884818 },
1319 .{ 5146105983135678095, 2287300449992174951, 4325371679080264751, 75641380576797959 },
1320 .{ 11019359372592553360, 8422686425957443718, 7175176077944048210, 77122349788024458 },
1321 .{ 11005742969399620716, 4132174559240043701, 9372258443096612118, 78632314633490790 },
1322 .{ 8887589641394725840, 8029899502466543662, 14582206497241572853, 80171842813591127 },
1323 .{ 360247523705545899, 12568341805293354211, 14653258284762517866, 81741513143625247 },
1324 .{ 12314272731984275834, 4740745023227177044, 6141631472368337539, 83341915771415304 },
1325 .{ 441052047733984759, 7940090120939869826, 11750200619921094248, 84973652399183278 },
1326 .{ 3436657868127012749, 9187006432149937667, 16389726097323041290, 86637336509772529 },
1327 .{ 13490220260784534044, 15339072891382896702, 8846102360835316895, 88333593597298497 },
1328 .{ 4125672032094859833, 158347675704003277, 10592598512749774447, 90063061402315272 },
1329 .{ 12189928252974395775, 2386931199439295891, 7009030566469913276, 91826390151586454 },
1330 .{ 9256479608339282969, 2844900158963599229, 11148388908923225596, 93624242802550437 },
1331 .{ 11584393507658707408, 2863659090805147914, 9873421561981063551, 95457295292572042 },
1332 .{ 13984297296943171390, 1931468383973130608, 12905719743235082319, 97326236793074198 },
1333 .{ 5837045222254987499, 10213498696735864176, 14893951506257020749, 99231769968645227 },
1334};
1335
1336// Unfortunately, the results are sometimes off by one or two. We use an additional
1337// lookup table to store those cases and adjust the result.
1338const FLOAT128_POW5_ERRORS: [156]u64 = .{
1339 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x9555596400000000,
1340 0x65a6569525565555, 0x4415551445449655, 0x5105015504144541, 0x65a69969a6965964,
1341 0x5054955969959656, 0x5105154515554145, 0x4055511051591555, 0x5500514455550115,
1342 0x0041140014145515, 0x1005440545511051, 0x0014405450411004, 0x0414440010500000,
1343 0x0044000440010040, 0x5551155000004001, 0x4554555454544114, 0x5150045544005441,
1344 0x0001111400054501, 0x6550955555554554, 0x1504159645559559, 0x4105055141454545,
1345 0x1411541410405454, 0x0415555044545555, 0x0014154115405550, 0x1540055040411445,
1346 0x0000000500000000, 0x5644000000000000, 0x1155555591596555, 0x0410440054569565,
1347 0x5145100010010005, 0x0555041405500150, 0x4141450455140450, 0x0000000144000140,
1348 0x5114004001105410, 0x4444100404005504, 0x0414014410001015, 0x5145055155555015,
1349 0x0141041444445540, 0x0000100451541414, 0x4105041104155550, 0x0500501150451145,
1350 0x1001050000004114, 0x5551504400141045, 0x5110545410151454, 0x0100001400004040,
1351 0x5040010111040000, 0x0140000150541100, 0x4400140400104110, 0x5011014405545004,
1352 0x0000000044155440, 0x0000000010000000, 0x1100401444440001, 0x0040401010055111,
1353 0x5155155551405454, 0x0444440015514411, 0x0054505054014101, 0x0451015441115511,
1354 0x1541411401140551, 0x4155104514445110, 0x4141145450145515, 0x5451445055155050,
1355 0x4400515554110054, 0x5111145104501151, 0x565a655455500501, 0x5565555555525955,
1356 0x0550511500405695, 0x4415504051054544, 0x6555595965555554, 0x0100915915555655,
1357 0x5540001510001001, 0x5450051414000544, 0x1405010555555551, 0x5555515555644155,
1358 0x5555055595496555, 0x5451045004415000, 0x5450510144040144, 0x5554155555556455,
1359 0x5051555495415555, 0x5555554555555545, 0x0000000010005455, 0x4000005000040000,
1360 0x5565555555555954, 0x5554559555555505, 0x9645545495552555, 0x4000400055955564,
1361 0x0040000000000001, 0x4004100100000000, 0x5540040440000411, 0x4565555955545644,
1362 0x1140659549651556, 0x0100000410010000, 0x5555515400004001, 0x5955545555155255,
1363 0x5151055545505556, 0x5051454510554515, 0x0501500050415554, 0x5044154005441005,
1364 0x1455445450550455, 0x0010144055144545, 0x0000401100000004, 0x1050145050000010,
1365 0x0415004554011540, 0x1000510100151150, 0x0100040400001144, 0x0000000000000000,
1366 0x0550004400000100, 0x0151145041451151, 0x0000400400005450, 0x0000100044010004,
1367 0x0100054100050040, 0x0504400005410010, 0x4011410445500105, 0x0000404000144411,
1368 0x0101504404500000, 0x0000005044400400, 0x0000000014000100, 0x0404440414000000,
1369 0x5554100410000140, 0x4555455544505555, 0x5454105055455455, 0x0115454155454015,
1370 0x4404110000045100, 0x4400001100101501, 0x6596955956966a94, 0x0040655955665965,
1371 0x5554144400100155, 0xa549495401011041, 0x5596555565955555, 0x5569965959549555,
1372 0x969565a655555456, 0x0000001000000000, 0x0000000040000140, 0x0000040100000000,
1373 0x1415454400000000, 0x5410415411454114, 0x0400040104000154, 0x0504045000000411,
1374 0x0000001000000010, 0x5554000000001040, 0x5549155551556595, 0x1455541055515555,
1375 0x0510555454554541, 0x9555555555540455, 0x6455456555556465, 0x4524565555654514,
1376 0x5554655255559545, 0x9555455441155556, 0x0000000051515555, 0x0010005040000550,
1377 0x5044044040000000, 0x1045040440010500, 0x0000400000040000, 0x0000000000000000,
1378};
1379
1380const FLOAT128_POW5_INV_SPLIT: [89][4]u64 = .{
1381 .{ 0, 0, 0, 144115188075855872 },
1382 .{ 1573859546583440065, 2691002611772552616, 6763753280790178510, 141347765182270746 },
1383 .{ 12960290449513840412, 12345512957918226762, 18057899791198622765, 138633484706040742 },
1384 .{ 7615871757716765416, 9507132263365501332, 4879801712092008245, 135971326161092377 },
1385 .{ 7869961150745287587, 5804035291554591636, 8883897266325833928, 133360288657597085 },
1386 .{ 2942118023529634767, 15128191429820565086, 10638459445243230718, 130799390525667397 },
1387 .{ 14188759758411913794, 5362791266439207815, 8068821289119264054, 128287668946279217 },
1388 .{ 7183196927902545212, 1952291723540117099, 12075928209936341512, 125824179589281448 },
1389 .{ 5672588001402349748, 17892323620748423487, 9874578446960390364, 123407996258356868 },
1390 .{ 4442590541217566325, 4558254706293456445, 10343828952663182727, 121038210542800766 },
1391 .{ 3005560928406962566, 2082271027139057888, 13961184524927245081, 118713931475986426 },
1392 .{ 13299058168408384786, 17834349496131278595, 9029906103900731664, 116434285200389047 },
1393 .{ 5414878118283973035, 13079825470227392078, 17897304791683760280, 114198414639042157 },
1394 .{ 14609755883382484834, 14991702445765844156, 3269802549772755411, 112005479173303009 },
1395 .{ 15967774957605076027, 2511532636717499923, 16221038267832563171, 109854654326805788 },
1396 .{ 9269330061621627145, 3332501053426257392, 16223281189403734630, 107745131455483836 },
1397 .{ 16739559299223642282, 1873986623300664530, 6546709159471442872, 105676117443544318 },
1398 .{ 17116435360051202055, 1359075105581853924, 2038341371621886470, 103646834405281051 },
1399 .{ 17144715798009627550, 3201623802661132408, 9757551605154622431, 101656519392613377 },
1400 .{ 17580479792687825857, 6546633380567327312, 15099972427870912398, 99704424108241124 },
1401 .{ 9726477118325522902, 14578369026754005435, 11728055595254428803, 97789814624307808 },
1402 .{ 134593949518343635, 5715151379816901985, 1660163707976377376, 95911971106466306 },
1403 .{ 5515914027713859358, 7124354893273815720, 5548463282858794077, 94070187543243255 },
1404 .{ 6188403395862945512, 5681264392632320838, 15417410852121406654, 92263771480600430 },
1405 .{ 15908890877468271457, 10398888261125597540, 4817794962769172309, 90492043761593298 },
1406 .{ 1413077535082201005, 12675058125384151580, 7731426132303759597, 88754338271028867 },
1407 .{ 1486733163972670293, 11369385300195092554, 11610016711694864110, 87050001685026843 },
1408 .{ 8788596583757589684, 3978580923851924802, 9255162428306775812, 85378393225389919 },
1409 .{ 7203518319660962120, 15044736224407683725, 2488132019818199792, 83738884418690858 },
1410 .{ 4004175967662388707, 18236988667757575407, 15613100370957482671, 82130858859985791 },
1411 .{ 18371903370586036463, 53497579022921640, 16465963977267203307, 80553711981064899 },
1412 .{ 10170778323887491315, 1999668801648976001, 10209763593579456445, 79006850823153334 },
1413 .{ 17108131712433974546, 16825784443029944237, 2078700786753338945, 77489693813976938 },
1414 .{ 17221789422665858532, 12145427517550446164, 5391414622238668005, 76001670549108934 },
1415 .{ 4859588996898795878, 1715798948121313204, 3950858167455137171, 74542221577515387 },
1416 .{ 13513469241795711526, 631367850494860526, 10517278915021816160, 73110798191218799 },
1417 .{ 11757513142672073111, 2581974932255022228, 17498959383193606459, 143413724438001539 },
1418 .{ 14524355192525042817, 5640643347559376447, 1309659274756813016, 140659771648132296 },
1419 .{ 2765095348461978538, 11021111021896007722, 3224303603779962366, 137958702611185230 },
1420 .{ 12373410389187981037, 13679193545685856195, 11644609038462631561, 135309501808182158 },
1421 .{ 12813176257562780151, 3754199046160268020, 9954691079802960722, 132711173221007413 },
1422 .{ 17557452279667723458, 3237799193992485824, 17893947919029030695, 130162739957935629 },
1423 .{ 14634200999559435155, 4123869946105211004, 6955301747350769239, 127663243886350468 },
1424 .{ 2185352760627740240, 2864813346878886844, 13049218671329690184, 125211745272516185 },
1425 .{ 6143438674322183002, 10464733336980678750, 6982925169933978309, 122807322428266620 },
1426 .{ 1099509117817174576, 10202656147550524081, 754997032816608484, 120449071364478757 },
1427 .{ 2410631293559367023, 17407273750261453804, 15307291918933463037, 118136105451200587 },
1428 .{ 12224968375134586697, 1664436604907828062, 11506086230137787358, 115867555084305488 },
1429 .{ 3495926216898000888, 18392536965197424288, 10992889188570643156, 113642567358547782 },
1430 .{ 8744506286256259680, 3966568369496879937, 18342264969761820037, 111460305746896569 },
1431 .{ 7689600520560455039, 5254331190877624630, 9628558080573245556, 109319949786027263 },
1432 .{ 11862637625618819436, 3456120362318976488, 14690471063106001082, 107220694767852583 },
1433 .{ 5697330450030126444, 12424082405392918899, 358204170751754904, 105161751436977040 },
1434 .{ 11257457505097373622, 15373192700214208870, 671619062372033814, 103142345693961148 },
1435 .{ 16850355018477166700, 1913910419361963966, 4550257919755970531, 101161718304283822 },
1436 .{ 9670835567561997011, 10584031339132130638, 3060560222974851757, 99219124612893520 },
1437 .{ 7698686577353054710, 11689292838639130817, 11806331021588878241, 97313834264240819 },
1438 .{ 12233569599615692137, 3347791226108469959, 10333904326094451110, 95445130927687169 },
1439 .{ 13049400362825383933, 17142621313007799680, 3790542585289224168, 93612312028186576 },
1440 .{ 12430457242474442072, 5625077542189557960, 14765055286236672238, 91814688482138969 },
1441 .{ 4759444137752473128, 2230562561567025078, 4954443037339580076, 90051584438315940 },
1442 .{ 7246913525170274758, 8910297835195760709, 4015904029508858381, 88322337023761438 },
1443 .{ 12854430245836432067, 8135139748065431455, 11548083631386317976, 86626296094571907 },
1444 .{ 4848827254502687803, 4789491250196085625, 3988192420450664125, 84962823991462151 },
1445 .{ 7435538409611286684, 904061756819742353, 14598026519493048444, 83331295300025028 },
1446 .{ 11042616160352530997, 8948390828345326218, 10052651191118271927, 81731096615594853 },
1447 .{ 11059348291563778943, 11696515766184685544, 3783210511290897367, 80161626312626082 },
1448 .{ 7020010856491885826, 5025093219346041680, 8960210401638911765, 78622294318500592 },
1449 .{ 17732844474490699984, 7820866704994446502, 6088373186798844243, 77112521891678506 },
1450 .{ 688278527545590501, 3045610706602776618, 8684243536999567610, 75631741404109150 },
1451 .{ 2734573255120657297, 3903146411440697663, 9470794821691856713, 74179396127820347 },
1452 .{ 15996457521023071259, 4776627823451271680, 12394856457265744744, 72754940025605801 },
1453 .{ 13492065758834518331, 7390517611012222399, 1630485387832860230, 142715675091463768 },
1454 .{ 13665021627282055864, 9897834675523659302, 17907668136755296849, 139975126841173266 },
1455 .{ 9603773719399446181, 10771916301484339398, 10672699855989487527, 137287204938390542 },
1456 .{ 3630218541553511265, 8139010004241080614, 2876479648932814543, 134650898807055963 },
1457 .{ 8318835909686377084, 9525369258927993371, 2796120270400437057, 132065217277054270 },
1458 .{ 11190003059043290163, 12424345635599592110, 12539346395388933763, 129529188211565064 },
1459 .{ 8701968833973242276, 820569587086330727, 2315591597351480110, 127041858141569228 },
1460 .{ 5115113890115690487, 16906305245394587826, 9899749468931071388, 124602291907373862 },
1461 .{ 15543535488939245974, 10945189844466391399, 3553863472349432246, 122209572307020975 },
1462 .{ 7709257252608325038, 1191832167690640880, 15077137020234258537, 119862799751447719 },
1463 .{ 7541333244210021737, 9790054727902174575, 5160944773155322014, 117561091926268545 },
1464 .{ 12297384708782857832, 1281328873123467374, 4827925254630475769, 115303583460052092 },
1465 .{ 13243237906232367265, 15873887428139547641, 3607993172301799599, 113089425598968120 },
1466 .{ 11384616453739611114, 15184114243769211033, 13148448124803481057, 110917785887682141 },
1467 .{ 17727970963596660683, 1196965221832671990, 14537830463956404138, 108787847856377790 },
1468 .{ 17241367586707330931, 8880584684128262874, 11173506540726547818, 106698810713789254 },
1469 .{ 7184427196661305643, 14332510582433188173, 14230167953789677901, 104649889046128358 },
1470};
1471
1472const FLOAT128_POW5_INV_ERRORS: [154]u64 = .{
1473 0x1144155514145504, 0x0000541555401141, 0x0000000000000000, 0x0154454000000000,
1474 0x4114105515544440, 0x0001001111500415, 0x4041411410011000, 0x5550114515155014,
1475 0x1404100041554551, 0x0515000450404410, 0x5054544401140004, 0x5155501005555105,
1476 0x1144141000105515, 0x0541500000500000, 0x1104105540444140, 0x4000015055514110,
1477 0x0054010450004005, 0x4155515404100005, 0x5155145045155555, 0x1511555515440558,
1478 0x5558544555515555, 0x0000000000000010, 0x5004000000000050, 0x1415510100000010,
1479 0x4545555444514500, 0x5155151555555551, 0x1441540144044554, 0x5150104045544400,
1480 0x5450545401444040, 0x5554455045501400, 0x4655155555555145, 0x1000010055455055,
1481 0x1000004000055004, 0x4455405104000005, 0x4500114504150545, 0x0000000014000000,
1482 0x5450000000000000, 0x5514551511445555, 0x4111501040555451, 0x4515445500054444,
1483 0x5101500104100441, 0x1545115155545055, 0x0000000000000000, 0x1554000000100000,
1484 0x5555545595551555, 0x5555051851455955, 0x5555555555555559, 0x0000400011001555,
1485 0x0000004400040000, 0x5455511555554554, 0x5614555544115445, 0x6455156145555155,
1486 0x5455855455415455, 0x5515555144555545, 0x0114400000145155, 0x0000051000450511,
1487 0x4455154554445100, 0x4554150141544455, 0x65955555559a5965, 0x5555555854559559,
1488 0x9569654559616595, 0x1040044040005565, 0x1010010500011044, 0x1554015545154540,
1489 0x4440555401545441, 0x1014441450550105, 0x4545400410504145, 0x5015111541040151,
1490 0x5145051154000410, 0x1040001044545044, 0x4001400000151410, 0x0540000044040000,
1491 0x0510555454411544, 0x0400054054141550, 0x1001041145001100, 0x0000000140000000,
1492 0x0000000014100000, 0x1544005454000140, 0x4050055505445145, 0x0011511104504155,
1493 0x5505544415045055, 0x1155154445515554, 0x0000000000004555, 0x0000000000000000,
1494 0x5101010510400004, 0x1514045044440400, 0x5515519555515555, 0x4554545441555545,
1495 0x1551055955551515, 0x0150000011505515, 0x0044005040400000, 0x0004001004010050,
1496 0x0000051004450414, 0x0114001101001144, 0x0401000001000001, 0x4500010001000401,
1497 0x0004100000005000, 0x0105000441101100, 0x0455455550454540, 0x5404050144105505,
1498 0x4101510540555455, 0x1055541411451555, 0x5451445110115505, 0x1154110010101545,
1499 0x1145140450054055, 0x5555565415551554, 0x1550559555555555, 0x5555541545045141,
1500 0x4555455450500100, 0x5510454545554555, 0x1510140115045455, 0x1001050040111510,
1501 0x5555454555555504, 0x9954155545515554, 0x6596656555555555, 0x0140410051555559,
1502 0x0011104010001544, 0x965669659a680501, 0x5655a55955556955, 0x4015111014404514,
1503 0x1414155554505145, 0x0540040011051404, 0x1010000000015005, 0x0010054050004410,
1504 0x5041104014000100, 0x4440010500100001, 0x1155510504545554, 0x0450151545115541,
1505 0x4000100400110440, 0x1004440010514440, 0x0000115050450000, 0x0545404455541500,
1506 0x1051051555505101, 0x5505144554544144, 0x4550545555515550, 0x0015400450045445,
1507 0x4514155400554415, 0x4555055051050151, 0x1511441450001014, 0x4544554510404414,
1508 0x4115115545545450, 0x5500541555551555, 0x5550010544155015, 0x0144414045545500,
1509 0x4154050001050150, 0x5550511111000145, 0x1114504055000151, 0x5104041101451040,
1510 0x0010501401051441, 0x0010501450504401, 0x4554585440044444, 0x5155555951450455,
1511 0x0040000400105555, 0x0000000000000001,
1512};
1513
1514// zig fmt: on
1515
1516const builtin = @import("builtin");
1517
1518fn check(comptime T: type, value: T, comptime expected: []const u8) !void {
1519 const I = @Type(.{ .int = .{ .signedness = .unsigned, .bits = @bitSizeOf(T) } });
1520
1521 var buf: [6000]u8 = undefined;
1522 const value_bits: I = @bitCast(value);
1523 const s = try render(&buf, value, .{});
1524 try std.testing.expectEqualStrings(expected, s);
1525
1526 if (T == f80 and builtin.target.os.tag == .windows and builtin.target.cpu.arch == .x86_64) return;
1527
1528 const o = try std.fmt.parseFloat(T, s);
1529 const o_bits: I = @bitCast(o);
1530
1531 if (std.math.isNan(value)) {
1532 try std.testing.expect(std.math.isNan(o));
1533 } else {
1534 try std.testing.expectEqual(value_bits, o_bits);
1535 }
1536}
1537
1538test "format f32" {
1539 try check(f32, 0.0, "0e0");
1540 try check(f32, -0.0, "-0e0");
1541 try check(f32, 1.0, "1e0");
1542 try check(f32, -1.0, "-1e0");
1543 try check(f32, std.math.nan(f32), "nan");
1544 try check(f32, std.math.inf(f32), "inf");
1545 try check(f32, -std.math.inf(f32), "-inf");
1546 try check(f32, 1.1754944e-38, "1.1754944e-38");
1547 try check(f32, @bitCast(@as(u32, 0x7f7fffff)), "3.4028235e38");
1548 try check(f32, @bitCast(@as(u32, 1)), "1e-45");
1549 try check(f32, 3.355445E7, "3.355445e7");
1550 try check(f32, 8.999999e9, "9e9");
1551 try check(f32, 3.4366717e10, "3.436672e10");
1552 try check(f32, 3.0540412e5, "3.0540412e5");
1553 try check(f32, 8.0990312e3, "8.0990312e3");
1554 try check(f32, 2.4414062e-4, "2.4414062e-4");
1555 try check(f32, 2.4414062e-3, "2.4414062e-3");
1556 try check(f32, 4.3945312e-3, "4.3945312e-3");
1557 try check(f32, 6.3476562e-3, "6.3476562e-3");
1558 try check(f32, 4.7223665e21, "4.7223665e21");
1559 try check(f32, 8388608.0, "8.388608e6");
1560 try check(f32, 1.6777216e7, "1.6777216e7");
1561 try check(f32, 3.3554436e7, "3.3554436e7");
1562 try check(f32, 6.7131496e7, "6.7131496e7");
1563 try check(f32, 1.9310392e-38, "1.9310392e-38");
1564 try check(f32, -2.47e-43, "-2.47e-43");
1565 try check(f32, 1.993244e-38, "1.993244e-38");
1566 try check(f32, 4103.9003, "4.1039004e3");
1567 try check(f32, 5.3399997e9, "5.3399997e9");
1568 try check(f32, 6.0898e-39, "6.0898e-39");
1569 try check(f32, 0.0010310042, "1.0310042e-3");
1570 try check(f32, 2.8823261e17, "2.882326e17");
1571 try check(f32, 7.038531e-26, "7.038531e-26");
1572 try check(f32, 9.2234038e17, "9.223404e17");
1573 try check(f32, 6.7108872e7, "6.710887e7");
1574 try check(f32, 1.0e-44, "1e-44");
1575 try check(f32, 2.816025e14, "2.816025e14");
1576 try check(f32, 9.223372e18, "9.223372e18");
1577 try check(f32, 1.5846085e29, "1.5846086e29");
1578 try check(f32, 1.1811161e19, "1.1811161e19");
1579 try check(f32, 5.368709e18, "5.368709e18");
1580 try check(f32, 4.6143165e18, "4.6143166e18");
1581 try check(f32, 0.007812537, "7.812537e-3");
1582 try check(f32, 1.4e-45, "1e-45");
1583 try check(f32, 1.18697724e20, "1.18697725e20");
1584 try check(f32, 1.00014165e-36, "1.00014165e-36");
1585 try check(f32, 200.0, "2e2");
1586 try check(f32, 3.3554432e7, "3.3554432e7");
1587
1588 try check(f32, 1.0, "1e0");
1589 try check(f32, 1.2, "1.2e0");
1590 try check(f32, 1.23, "1.23e0");
1591 try check(f32, 1.234, "1.234e0");
1592 try check(f32, 1.2345, "1.2345e0");
1593 try check(f32, 1.23456, "1.23456e0");
1594 try check(f32, 1.234567, "1.234567e0");
1595 try check(f32, 1.2345678, "1.2345678e0");
1596 try check(f32, 1.23456735e-36, "1.23456735e-36");
1597}
1598
1599test "format f64" {
1600 try check(f64, 0.0, "0e0");
1601 try check(f64, -0.0, "-0e0");
1602 try check(f64, 1.0, "1e0");
1603 try check(f64, -1.0, "-1e0");
1604 try check(f64, std.math.nan(f64), "nan");
1605 try check(f64, std.math.inf(f64), "inf");
1606 try check(f64, -std.math.inf(f64), "-inf");
1607 try check(f64, 2.2250738585072014e-308, "2.2250738585072014e-308");
1608 try check(f64, @bitCast(@as(u64, 0x7fefffffffffffff)), "1.7976931348623157e308");
1609 try check(f64, @bitCast(@as(u64, 1)), "5e-324");
1610 try check(f64, 2.98023223876953125e-8, "2.9802322387695312e-8");
1611 try check(f64, -2.109808898695963e16, "-2.109808898695963e16");
1612 try check(f64, 4.940656e-318, "4.940656e-318");
1613 try check(f64, 1.18575755e-316, "1.18575755e-316");
1614 try check(f64, 2.989102097996e-312, "2.989102097996e-312");
1615 try check(f64, 9.0608011534336e15, "9.0608011534336e15");
1616 try check(f64, 4.708356024711512e18, "4.708356024711512e18");
1617 try check(f64, 9.409340012568248e18, "9.409340012568248e18");
1618 try check(f64, 1.2345678, "1.2345678e0");
1619 try check(f64, @bitCast(@as(u64, 0x4830f0cf064dd592)), "5.764607523034235e39");
1620 try check(f64, @bitCast(@as(u64, 0x4840f0cf064dd592)), "1.152921504606847e40");
1621 try check(f64, @bitCast(@as(u64, 0x4850f0cf064dd592)), "2.305843009213694e40");
1622
1623 try check(f64, 1, "1e0");
1624 try check(f64, 1.2, "1.2e0");
1625 try check(f64, 1.23, "1.23e0");
1626 try check(f64, 1.234, "1.234e0");
1627 try check(f64, 1.2345, "1.2345e0");
1628 try check(f64, 1.23456, "1.23456e0");
1629 try check(f64, 1.234567, "1.234567e0");
1630 try check(f64, 1.2345678, "1.2345678e0");
1631 try check(f64, 1.23456789, "1.23456789e0");
1632 try check(f64, 1.234567895, "1.234567895e0");
1633 try check(f64, 1.2345678901, "1.2345678901e0");
1634 try check(f64, 1.23456789012, "1.23456789012e0");
1635 try check(f64, 1.234567890123, "1.234567890123e0");
1636 try check(f64, 1.2345678901234, "1.2345678901234e0");
1637 try check(f64, 1.23456789012345, "1.23456789012345e0");
1638 try check(f64, 1.234567890123456, "1.234567890123456e0");
1639 try check(f64, 1.2345678901234567, "1.2345678901234567e0");
1640
1641 try check(f64, 4.294967294, "4.294967294e0");
1642 try check(f64, 4.294967295, "4.294967295e0");
1643 try check(f64, 4.294967296, "4.294967296e0");
1644 try check(f64, 4.294967297, "4.294967297e0");
1645 try check(f64, 4.294967298, "4.294967298e0");
1646}
1647
1648test "format f80" {
1649 try check(f80, 0.0, "0e0");
1650 try check(f80, -0.0, "-0e0");
1651 try check(f80, 1.0, "1e0");
1652 try check(f80, -1.0, "-1e0");
1653 try check(f80, std.math.nan(f80), "nan");
1654 try check(f80, std.math.inf(f80), "inf");
1655 try check(f80, -std.math.inf(f80), "-inf");
1656
1657 try check(f80, 2.2250738585072014e-308, "2.2250738585072014e-308");
1658 try check(f80, 2.98023223876953125e-8, "2.98023223876953125e-8");
1659 try check(f80, -2.109808898695963e16, "-2.109808898695963e16");
1660 try check(f80, 4.940656e-318, "4.940656e-318");
1661 try check(f80, 1.18575755e-316, "1.18575755e-316");
1662 try check(f80, 2.989102097996e-312, "2.989102097996e-312");
1663 try check(f80, 9.0608011534336e15, "9.0608011534336e15");
1664 try check(f80, 4.708356024711512e18, "4.708356024711512e18");
1665 try check(f80, 9.409340012568248e18, "9.409340012568248e18");
1666 try check(f80, 1.2345678, "1.2345678e0");
1667}
1668
1669test "format f128" {
1670 try check(f128, 0.0, "0e0");
1671 try check(f128, -0.0, "-0e0");
1672 try check(f128, 1.0, "1e0");
1673 try check(f128, -1.0, "-1e0");
1674 try check(f128, std.math.nan(f128), "nan");
1675 try check(f128, std.math.inf(f128), "inf");
1676 try check(f128, -std.math.inf(f128), "-inf");
1677
1678 try check(f128, 2.2250738585072014e-308, "2.2250738585072014e-308");
1679 try check(f128, 2.98023223876953125e-8, "2.98023223876953125e-8");
1680 try check(f128, -2.109808898695963e16, "-2.109808898695963e16");
1681 try check(f128, 4.940656e-318, "4.940656e-318");
1682 try check(f128, 1.18575755e-316, "1.18575755e-316");
1683 try check(f128, 2.989102097996e-312, "2.989102097996e-312");
1684 try check(f128, 9.0608011534336e15, "9.0608011534336e15");
1685 try check(f128, 4.708356024711512e18, "4.708356024711512e18");
1686 try check(f128, 9.409340012568248e18, "9.409340012568248e18");
1687 try check(f128, 1.2345678, "1.2345678e0");
1688}
1689
1690test "format float to decimal with zero precision" {
1691 try expectFmt("5", "{d:.0}", .{5});
1692 try expectFmt("6", "{d:.0}", .{6});
1693 try expectFmt("7", "{d:.0}", .{7});
1694 try expectFmt("8", "{d:.0}", .{8});
1695}
lib/std/fmt/format_float.zig deleted-1695
......@@ -1,1695 +0,0 @@
1//! This file implements the ryu floating point conversion algorithm:
2//! https://dl.acm.org/doi/pdf/10.1145/3360595
3
4const std = @import("std");
5const expectFmt = std.testing.expectFmt;
6
7const special_exponent = 0x7fffffff;
8
9/// Any buffer used for `format` must be at least this large. This is asserted. A runtime check will
10/// additionally be performed if more bytes are required.
11pub const min_buffer_size = 53;
12
13/// Returns the minimum buffer size needed to print every float of a specific type and format.
14pub fn bufferSize(comptime mode: Format, comptime T: type) comptime_int {
15 comptime std.debug.assert(@typeInfo(T) == .float);
16 return switch (mode) {
17 .scientific => 53,
18 // Based on minimum subnormal values.
19 .decimal => switch (@bitSizeOf(T)) {
20 16 => @max(15, min_buffer_size),
21 32 => 55,
22 64 => 347,
23 80 => 4996,
24 128 => 5011,
25 else => unreachable,
26 },
27 };
28}
29
30pub const FormatError = error{
31 BufferTooSmall,
32};
33
34pub const Format = enum {
35 scientific,
36 decimal,
37};
38
39pub const FormatOptions = struct {
40 mode: Format = .scientific,
41 precision: ?usize = null,
42};
43
44/// Format a floating-point value and write it to buffer. Returns a slice to the buffer containing
45/// the string representation.
46///
47/// Full precision is the default. Any full precision float can be reparsed with std.fmt.parseFloat
48/// unambiguously.
49///
50/// Scientific mode is recommended generally as the output is more compact and any type can be
51/// written in full precision using a buffer of only `min_buffer_size`.
52///
53/// When printing full precision decimals, use `bufferSize` to get the required space. It is
54/// recommended to bound decimal output with a fixed precision to reduce the required buffer size.
55pub fn formatFloat(buf: []u8, v_: anytype, options: FormatOptions) FormatError![]const u8 {
56 const v = switch (@TypeOf(v_)) {
57 // comptime_float internally is a f128; this preserves precision.
58 comptime_float => @as(f128, v_),
59 else => v_,
60 };
61
62 const T = @TypeOf(v);
63 comptime std.debug.assert(@typeInfo(T) == .float);
64 const I = @Type(.{ .int = .{ .signedness = .unsigned, .bits = @bitSizeOf(T) } });
65
66 const DT = if (@bitSizeOf(T) <= 64) u64 else u128;
67 const tables = switch (DT) {
68 u64 => if (@import("builtin").mode == .ReleaseSmall) &Backend64_TablesSmall else &Backend64_TablesFull,
69 u128 => &Backend128_Tables,
70 else => unreachable,
71 };
72
73 const has_explicit_leading_bit = std.math.floatMantissaBits(T) - std.math.floatFractionalBits(T) != 0;
74 const d = binaryToDecimal(DT, @as(I, @bitCast(v)), std.math.floatMantissaBits(T), std.math.floatExponentBits(T), has_explicit_leading_bit, tables);
75
76 return switch (options.mode) {
77 .scientific => formatScientific(DT, buf, d, options.precision),
78 .decimal => formatDecimal(DT, buf, d, options.precision),
79 };
80}
81
82pub fn FloatDecimal(comptime T: type) type {
83 comptime std.debug.assert(T == u64 or T == u128);
84 return struct {
85 mantissa: T,
86 exponent: i32,
87 sign: bool,
88 };
89}
90
91fn copySpecialStr(buf: []u8, f: anytype) []const u8 {
92 if (f.sign) {
93 buf[0] = '-';
94 }
95 const offset: usize = @intFromBool(f.sign);
96 if (f.mantissa != 0) {
97 @memcpy(buf[offset..][0..3], "nan");
98 return buf[0 .. 3 + offset];
99 }
100 @memcpy(buf[offset..][0..3], "inf");
101 return buf[0 .. 3 + offset];
102}
103
104fn writeDecimal(buf: []u8, value: anytype, count: usize) void {
105 var i: usize = 0;
106
107 while (i + 2 < count) : (i += 2) {
108 const c: u8 = @intCast(value.* % 100);
109 value.* /= 100;
110 const d = std.fmt.digits2(c);
111 buf[count - i - 1] = d[1];
112 buf[count - i - 2] = d[0];
113 }
114
115 while (i < count) : (i += 1) {
116 const c: u8 = @intCast(value.* % 10);
117 value.* /= 10;
118 buf[count - i - 1] = '0' + c;
119 }
120}
121
122fn isPowerOf10(n_: u128) bool {
123 var n = n_;
124 while (n != 0) : (n /= 10) {
125 if (n % 10 != 0) return false;
126 }
127 return true;
128}
129
130const RoundMode = enum {
131 /// 1234.56 = precision 2
132 decimal,
133 /// 1.23456e3 = precision 5
134 scientific,
135};
136
137fn round(comptime T: type, f: FloatDecimal(T), mode: RoundMode, precision: usize) FloatDecimal(T) {
138 var round_digit: usize = 0;
139 var output = f.mantissa;
140 var exp = f.exponent;
141 const olength = decimalLength(output);
142
143 switch (mode) {
144 .decimal => {
145 if (f.exponent > 0) {
146 round_digit = (olength - 1) + precision + @as(usize, @intCast(f.exponent));
147 } else {
148 const min_exp_required = @as(usize, @intCast(-f.exponent));
149 if (precision + olength > min_exp_required) {
150 round_digit = precision + olength - min_exp_required;
151 }
152 }
153 },
154 .scientific => {
155 round_digit = 1 + precision;
156 },
157 }
158
159 if (round_digit < olength) {
160 var nlength = olength;
161 for (round_digit + 1..olength) |_| {
162 output /= 10;
163 exp += 1;
164 nlength -= 1;
165 }
166
167 if (output % 10 >= 5) {
168 output /= 10;
169 output += 1;
170 exp += 1;
171
172 // e.g. 9999 -> 10000
173 if (isPowerOf10(output)) {
174 output /= 10;
175 exp += 1;
176 }
177 }
178 }
179
180 return .{
181 .mantissa = output,
182 .exponent = exp,
183 .sign = f.sign,
184 };
185}
186
187/// Write a FloatDecimal to a buffer in scientific form.
188///
189/// The buffer provided must be greater than `min_buffer_size` in length. If no precision is
190/// specified, this function will never return an error. If a precision is specified, up to
191/// `8 + precision` bytes will be written to the buffer. An error will be returned if the content
192/// will not fit.
193///
194/// It is recommended to bound decimal formatting with an exact precision.
195pub fn formatScientific(comptime T: type, buf: []u8, f_: FloatDecimal(T), precision: ?usize) FormatError![]const u8 {
196 std.debug.assert(buf.len >= min_buffer_size);
197 var f = f_;
198
199 if (f.exponent == special_exponent) {
200 return copySpecialStr(buf, f);
201 }
202
203 if (precision) |prec| {
204 f = round(T, f, .scientific, prec);
205 }
206
207 var output = f.mantissa;
208 const olength = decimalLength(output);
209
210 if (precision) |prec| {
211 // fixed bound: sign(1) + leading_digit(1) + point(1) + exp_sign(1) + exp_max(4)
212 const req_bytes = 8 + prec;
213 if (buf.len < req_bytes) {
214 return error.BufferTooSmall;
215 }
216 }
217
218 // Step 5: Print the scientific representation
219 var index: usize = 0;
220 if (f.sign) {
221 buf[index] = '-';
222 index += 1;
223 }
224
225 // 1.12345
226 writeDecimal(buf[index + 2 ..], &output, olength - 1);
227 buf[index] = '0' + @as(u8, @intCast(output % 10));
228 buf[index + 1] = '.';
229 index += 2;
230 const dp_index = index;
231 if (olength > 1) index += olength - 1 else index -= 1;
232
233 if (precision) |prec| {
234 index += @intFromBool(olength == 1);
235 if (prec > olength - 1) {
236 const len = prec - (olength - 1);
237 @memset(buf[index..][0..len], '0');
238 index += len;
239 } else {
240 index = dp_index + prec - @intFromBool(prec == 0);
241 }
242 }
243
244 // e100
245 buf[index] = 'e';
246 index += 1;
247 var exp = f.exponent + @as(i32, @intCast(olength)) - 1;
248 if (exp < 0) {
249 buf[index] = '-';
250 index += 1;
251 exp = -exp;
252 }
253 var uexp: u32 = @intCast(exp);
254 const elength = decimalLength(uexp);
255 writeDecimal(buf[index..], &uexp, elength);
256 index += elength;
257
258 return buf[0..index];
259}
260
261/// Write a FloatDecimal to a buffer in decimal form.
262///
263/// The buffer provided must be greater than `min_buffer_size` bytes in length. If no precision is
264/// specified, this may still return an error. If precision is specified, `2 + precision` bytes will
265/// always be written.
266pub fn formatDecimal(comptime T: type, buf: []u8, f_: FloatDecimal(T), precision: ?usize) FormatError![]const u8 {
267 std.debug.assert(buf.len >= min_buffer_size);
268 var f = f_;
269
270 if (f.exponent == special_exponent) {
271 return copySpecialStr(buf, f);
272 }
273
274 if (precision) |prec| {
275 f = round(T, f, .decimal, prec);
276 }
277
278 var output = f.mantissa;
279 const olength = decimalLength(output);
280
281 // fixed bound: leading_digit(1) + point(1)
282 const req_bytes = if (f.exponent >= 0)
283 @as(usize, 2) + @abs(f.exponent) + olength + (precision orelse 0)
284 else
285 @as(usize, 2) + @max(@abs(f.exponent) + olength, precision orelse 0);
286 if (buf.len < req_bytes) {
287 return error.BufferTooSmall;
288 }
289
290 // Step 5: Print the decimal representation
291 var index: usize = 0;
292 if (f.sign) {
293 buf[index] = '-';
294 index += 1;
295 }
296
297 const dp_offset = f.exponent + cast_i32(olength);
298 if (dp_offset <= 0) {
299 // 0.000001234
300 buf[index] = '0';
301 buf[index + 1] = '.';
302 index += 2;
303 const dp_index = index;
304
305 const dp_poffset: u32 = @intCast(-dp_offset);
306 @memset(buf[index..][0..dp_poffset], '0');
307 index += dp_poffset;
308 writeDecimal(buf[index..], &output, olength);
309 index += olength;
310
311 if (precision) |prec| {
312 const dp_written = index - dp_index;
313 if (prec > dp_written) {
314 @memset(buf[index..][0 .. prec - dp_written], '0');
315 }
316 index = dp_index + prec - @intFromBool(prec == 0);
317 }
318 } else {
319 // 123456000
320 const dp_uoffset: usize = @intCast(dp_offset);
321 if (dp_uoffset >= olength) {
322 writeDecimal(buf[index..], &output, olength);
323 index += olength;
324 @memset(buf[index..][0 .. dp_uoffset - olength], '0');
325 index += dp_uoffset - olength;
326
327 if (precision) |prec| {
328 if (prec != 0) {
329 buf[index] = '.';
330 index += 1;
331 @memset(buf[index..][0..prec], '0');
332 index += prec;
333 }
334 }
335 } else {
336 // 12345.6789
337 writeDecimal(buf[index + dp_uoffset + 1 ..], &output, olength - dp_uoffset);
338 buf[index + dp_uoffset] = '.';
339 const dp_index = index + dp_uoffset + 1;
340 writeDecimal(buf[index..], &output, dp_uoffset);
341 index += olength + 1;
342
343 if (precision) |prec| {
344 const dp_written = olength - dp_uoffset;
345 if (prec > dp_written) {
346 @memset(buf[index..][0 .. prec - dp_written], '0');
347 }
348 index = dp_index + prec - @intFromBool(prec == 0);
349 }
350 }
351 }
352
353 return buf[0..index];
354}
355
356fn cast_i32(v: anytype) i32 {
357 return @intCast(v);
358}
359
360/// Convert a binary float representation to decimal.
361pub fn binaryToDecimal(comptime T: type, bits: T, mantissa_bits: std.math.Log2Int(T), exponent_bits: u5, explicit_leading_bit: bool, comptime tables: anytype) FloatDecimal(T) {
362 if (T != tables.T) {
363 @compileError("table type does not match backend type: " ++ @typeName(tables.T) ++ " != " ++ @typeName(T));
364 }
365
366 const bias = (@as(u32, 1) << (exponent_bits - 1)) - 1;
367 const ieee_sign = ((bits >> (mantissa_bits + exponent_bits)) & 1) != 0;
368 const ieee_mantissa = bits & ((@as(T, 1) << mantissa_bits) - 1);
369 const ieee_exponent: u32 = @intCast((bits >> mantissa_bits) & ((@as(T, 1) << exponent_bits) - 1));
370
371 if (ieee_exponent == 0 and ieee_mantissa == 0) {
372 return .{
373 .mantissa = 0,
374 .exponent = 0,
375 .sign = ieee_sign,
376 };
377 }
378 if (ieee_exponent == ((@as(u32, 1) << exponent_bits) - 1)) {
379 return .{
380 .mantissa = if (explicit_leading_bit) ieee_mantissa & ((@as(T, 1) << (mantissa_bits - 1)) - 1) else ieee_mantissa,
381 .exponent = special_exponent,
382 .sign = ieee_sign,
383 };
384 }
385
386 var e2: i32 = undefined;
387 var m2: T = undefined;
388 if (explicit_leading_bit) {
389 if (ieee_exponent == 0) {
390 e2 = 1 - cast_i32(bias) - cast_i32(mantissa_bits) + 1 - 2;
391 } else {
392 e2 = cast_i32(ieee_exponent) - cast_i32(bias) - cast_i32(mantissa_bits) + 1 - 2;
393 }
394 m2 = ieee_mantissa;
395 } else {
396 if (ieee_exponent == 0) {
397 e2 = 1 - cast_i32(bias) - cast_i32(mantissa_bits) - 2;
398 m2 = ieee_mantissa;
399 } else {
400 e2 = cast_i32(ieee_exponent) - cast_i32(bias) - cast_i32(mantissa_bits) - 2;
401 m2 = (@as(T, 1) << mantissa_bits) | ieee_mantissa;
402 }
403 }
404 const even = (m2 & 1) == 0;
405 const accept_bounds = even;
406
407 // Step 2: Determine the interval of legal decimal representations.
408 const mv = 4 * m2;
409 const mm_shift: u1 = @intFromBool((ieee_mantissa != if (explicit_leading_bit) (@as(T, 1) << (mantissa_bits - 1)) else 0) or (ieee_exponent == 0));
410
411 // Step 3: Convert to a decimal power base using 128-bit arithmetic.
412 var vr: T = undefined;
413 var vp: T = undefined;
414 var vm: T = undefined;
415 var e10: i32 = undefined;
416 var vm_is_trailing_zeros = false;
417 var vr_is_trailing_zeros = false;
418 if (e2 >= 0) {
419 const q: u32 = log10Pow2(@intCast(e2)) - @intFromBool(e2 > 3);
420 e10 = cast_i32(q);
421 const k: i32 = @intCast(tables.POW5_INV_BITCOUNT + pow5Bits(q) - 1);
422 const i: u32 = @intCast(-e2 + cast_i32(q) + k);
423
424 const pow5 = tables.computeInvPow5(q);
425 vr = tables.mulShift(4 * m2, &pow5, i);
426 vp = tables.mulShift(4 * m2 + 2, &pow5, i);
427 vm = tables.mulShift(4 * m2 - 1 - mm_shift, &pow5, i);
428
429 if (q <= tables.bound1) {
430 if (mv % 5 == 0) {
431 vr_is_trailing_zeros = multipleOfPowerOf5(mv, if (tables.adjust_q) q -% 1 else q);
432 } else if (accept_bounds) {
433 vm_is_trailing_zeros = multipleOfPowerOf5(mv - 1 - mm_shift, q);
434 } else {
435 vp -= @intFromBool(multipleOfPowerOf5(mv + 2, q));
436 }
437 }
438 } else {
439 const q: u32 = log10Pow5(@intCast(-e2)) - @intFromBool(-e2 > 1);
440 e10 = cast_i32(q) + e2;
441 const i: i32 = -e2 - cast_i32(q);
442 const k: i32 = cast_i32(pow5Bits(@intCast(i))) - tables.POW5_BITCOUNT;
443 const j: u32 = @intCast(cast_i32(q) - k);
444
445 const pow5 = tables.computePow5(@intCast(i));
446 vr = tables.mulShift(4 * m2, &pow5, j);
447 vp = tables.mulShift(4 * m2 + 2, &pow5, j);
448 vm = tables.mulShift(4 * m2 - 1 - mm_shift, &pow5, j);
449
450 if (q <= 1) {
451 vr_is_trailing_zeros = true;
452 if (accept_bounds) {
453 vm_is_trailing_zeros = mm_shift == 1;
454 } else {
455 vp -= 1;
456 }
457 } else if (q < tables.bound2) {
458 vr_is_trailing_zeros = multipleOfPowerOf2(mv, if (tables.adjust_q) q - 1 else q);
459 }
460 }
461
462 // Step 4: Find the shortest decimal representation in the interval of legal representations.
463 var removed: u32 = 0;
464 var last_removed_digit: u8 = 0;
465
466 while (vp / 10 > vm / 10) {
467 vm_is_trailing_zeros = vm_is_trailing_zeros and vm % 10 == 0;
468 vr_is_trailing_zeros = vr_is_trailing_zeros and last_removed_digit == 0;
469 last_removed_digit = @intCast(vr % 10);
470 vr /= 10;
471 vp /= 10;
472 vm /= 10;
473 removed += 1;
474 }
475
476 if (vm_is_trailing_zeros) {
477 while (vm % 10 == 0) {
478 vr_is_trailing_zeros = vr_is_trailing_zeros and last_removed_digit == 0;
479 last_removed_digit = @intCast(vr % 10);
480 vr /= 10;
481 vp /= 10;
482 vm /= 10;
483 removed += 1;
484 }
485 }
486
487 if (vr_is_trailing_zeros and (last_removed_digit == 5) and (vr % 2 == 0)) {
488 last_removed_digit = 4;
489 }
490
491 return .{
492 .mantissa = vr + @intFromBool((vr == vm and (!accept_bounds or !vm_is_trailing_zeros)) or last_removed_digit >= 5),
493 .exponent = e10 + cast_i32(removed),
494 .sign = ieee_sign,
495 };
496}
497
498fn decimalLength(v: anytype) u32 {
499 switch (@TypeOf(v)) {
500 u32, u64 => {
501 std.debug.assert(v < 100000000000000000);
502 if (v >= 10000000000000000) return 17;
503 if (v >= 1000000000000000) return 16;
504 if (v >= 100000000000000) return 15;
505 if (v >= 10000000000000) return 14;
506 if (v >= 1000000000000) return 13;
507 if (v >= 100000000000) return 12;
508 if (v >= 10000000000) return 11;
509 if (v >= 1000000000) return 10;
510 if (v >= 100000000) return 9;
511 if (v >= 10000000) return 8;
512 if (v >= 1000000) return 7;
513 if (v >= 100000) return 6;
514 if (v >= 10000) return 5;
515 if (v >= 1000) return 4;
516 if (v >= 100) return 3;
517 if (v >= 10) return 2;
518 return 1;
519 },
520 u128 => {
521 const LARGEST_POW10 = (@as(u128, 5421010862427522170) << 64) | 687399551400673280;
522 var p10 = LARGEST_POW10;
523 var i: u32 = 39;
524 while (i > 0) : (i -= 1) {
525 if (v >= p10) return i;
526 p10 /= 10;
527 }
528 return 1;
529 },
530 else => unreachable,
531 }
532}
533
534// floor(log_10(2^e))
535fn log10Pow2(e: u32) u32 {
536 std.debug.assert(e <= 1 << 15);
537 return @intCast((@as(u64, @intCast(e)) * 169464822037455) >> 49);
538}
539
540// floor(log_10(5^e))
541fn log10Pow5(e: u32) u32 {
542 std.debug.assert(e <= 1 << 15);
543 return @intCast((@as(u64, @intCast(e)) * 196742565691928) >> 48);
544}
545
546// if (e == 0) 1 else ceil(log_2(5^e))
547fn pow5Bits(e: u32) u32 {
548 std.debug.assert(e <= 1 << 15);
549 return @intCast(((@as(u64, @intCast(e)) * 163391164108059) >> 46) + 1);
550}
551
552fn pow5Factor(value_: anytype) u32 {
553 var count: u32 = 0;
554 var value = value_;
555 while (value > 0) : ({
556 count += 1;
557 value /= 5;
558 }) {
559 if (value % 5 != 0) return count;
560 }
561 return 0;
562}
563
564fn multipleOfPowerOf5(value: anytype, p: u32) bool {
565 const T = @TypeOf(value);
566 std.debug.assert(@typeInfo(T) == .int);
567 return pow5Factor(value) >= p;
568}
569
570fn multipleOfPowerOf2(value: anytype, p: u32) bool {
571 const T = @TypeOf(value);
572 std.debug.assert(@typeInfo(T) == .int);
573 return (value & ((@as(T, 1) << @as(std.math.Log2Int(T), @intCast(p))) - 1)) == 0;
574}
575
576fn mulShift128(m: u128, mul: *const [4]u64, j: u32) u128 {
577 std.debug.assert(j > 128);
578 const a: [2]u64 = .{ @truncate(m), @truncate(m >> 64) };
579 const r = mul_128_256_shift(&a, mul, j, 0);
580 return (@as(u128, r[1]) << 64) | r[0];
581}
582
583fn mul_128_256_shift(a: *const [2]u64, b: *const [4]u64, shift: u32, corr: u32) [4]u64 {
584 std.debug.assert(shift > 0);
585 std.debug.assert(shift < 256);
586
587 const b00 = @as(u128, a[0]) * b[0];
588 const b01 = @as(u128, a[0]) * b[1];
589 const b02 = @as(u128, a[0]) * b[2];
590 const b03 = @as(u128, a[0]) * b[3];
591 const b10 = @as(u128, a[1]) * b[0];
592 const b11 = @as(u128, a[1]) * b[1];
593 const b12 = @as(u128, a[1]) * b[2];
594 const b13 = @as(u128, a[1]) * b[3];
595
596 const s0 = b00;
597 const s1 = b01 +% b10;
598 const c1: u128 = @intFromBool(s1 < b01);
599 const s2 = b02 +% b11;
600 const c2: u128 = @intFromBool(s2 < b02);
601 const s3 = b03 +% b12;
602 const c3: u128 = @intFromBool(s3 < b03);
603
604 const p0 = s0 +% (s1 << 64);
605 const d0: u128 = @intFromBool(p0 < b00);
606 const q1 = s2 +% (s1 >> 64) +% (s3 << 64);
607 const d1: u128 = @intFromBool(q1 < s2);
608 const p1 = q1 +% (c1 << 64) +% d0;
609 const d2: u128 = @intFromBool(p1 < q1);
610 const p2 = b13 +% (s3 >> 64) +% c2 +% (c3 << 64) +% d1 +% d2;
611
612 var r0: u128 = undefined;
613 var r1: u128 = undefined;
614 if (shift < 128) {
615 const cshift: u7 = @intCast(shift);
616 const sshift: u7 = @intCast(128 - shift);
617 r0 = corr +% ((p0 >> cshift) | (p1 << sshift));
618 r1 = ((p1 >> cshift) | (p2 << sshift)) +% @intFromBool(r0 < corr);
619 } else if (shift == 128) {
620 r0 = corr +% p1;
621 r1 = p2 +% @intFromBool(r0 < corr);
622 } else {
623 const ashift: u7 = @intCast(shift - 128);
624 const sshift: u7 = @intCast(256 - shift);
625 r0 = corr +% ((p1 >> ashift) | (p2 << sshift));
626 r1 = (p2 >> ashift) +% @intFromBool(r0 < corr);
627 }
628
629 return .{ @truncate(r0), @truncate(r0 >> 64), @truncate(r1), @truncate(r1 >> 64) };
630}
631
632pub const Backend128_Tables = struct {
633 const T = u128;
634 const mulShift = mulShift128;
635 const POW5_INV_BITCOUNT = FLOAT128_POW5_INV_BITCOUNT;
636 const POW5_BITCOUNT = FLOAT128_POW5_BITCOUNT;
637
638 const bound1 = 55;
639 const bound2 = 127;
640 const adjust_q = true;
641
642 fn computePow5(i: u32) [4]u64 {
643 const base = i / FLOAT128_POW5_TABLE_SIZE;
644 const base2 = base * FLOAT128_POW5_TABLE_SIZE;
645 const mul = &FLOAT128_POW5_SPLIT[base];
646 if (i == base2) {
647 return mul.*;
648 } else {
649 const offset = i - base2;
650 const m = &FLOAT128_POW5_TABLE[offset];
651 const delta = pow5Bits(i) - pow5Bits(base2);
652
653 const shift: u6 = @intCast(2 * (i % 32));
654 const corr: u32 = @intCast((FLOAT128_POW5_ERRORS[i / 32] >> shift) & 3);
655 return mul_128_256_shift(m, mul, delta, corr);
656 }
657 }
658
659 fn computeInvPow5(i: u32) [4]u64 {
660 const base = (i + FLOAT128_POW5_TABLE_SIZE - 1) / FLOAT128_POW5_TABLE_SIZE;
661 const base2 = base * FLOAT128_POW5_TABLE_SIZE;
662 const mul = &FLOAT128_POW5_INV_SPLIT[base]; // 1 / 5^base2
663 if (i == base2) {
664 return .{ mul[0] + 1, mul[1], mul[2], mul[3] };
665 } else {
666 const offset = base2 - i;
667 const m = &FLOAT128_POW5_TABLE[offset]; // 5^offset
668 const delta = pow5Bits(base2) - pow5Bits(i);
669
670 const shift: u6 = @intCast(2 * (i % 32));
671 const corr: u32 = @intCast(((FLOAT128_POW5_INV_ERRORS[i / 32] >> shift) & 3) + 1);
672 return mul_128_256_shift(m, mul, delta, corr);
673 }
674 }
675};
676
677fn mulShift64(m: u64, mul: *const [2]u64, j: u32) u64 {
678 std.debug.assert(j > 64);
679 const b0 = @as(u128, m) * mul[0];
680 const b2 = @as(u128, m) * mul[1];
681
682 if (j < 128) {
683 const shift: u6 = @intCast(j - 64);
684 return @intCast(((b0 >> 64) + b2) >> shift);
685 } else {
686 return 0;
687 }
688}
689
690pub const Backend64_TablesFull = struct {
691 const T = u64;
692 const mulShift = mulShift64;
693 const POW5_INV_BITCOUNT = FLOAT64_POW5_INV_BITCOUNT;
694 const POW5_BITCOUNT = FLOAT64_POW5_BITCOUNT;
695
696 const bound1 = 21;
697 const bound2 = 63;
698 const adjust_q = false;
699
700 fn computePow5(i: u32) [2]u64 {
701 return FLOAT64_POW5_SPLIT[i];
702 }
703
704 fn computeInvPow5(i: u32) [2]u64 {
705 return FLOAT64_POW5_INV_SPLIT[i];
706 }
707};
708
709pub const Backend64_TablesSmall = struct {
710 const T = u64;
711 const mulShift = mulShift64;
712 const POW5_INV_BITCOUNT = FLOAT64_POW5_INV_BITCOUNT;
713 const POW5_BITCOUNT = FLOAT64_POW5_BITCOUNT;
714
715 const bound1 = 21;
716 const bound2 = 63;
717 const adjust_q = false;
718
719 fn computePow5(i: u32) [2]u64 {
720 const base = i / FLOAT64_POW5_TABLE_SIZE;
721 const base2 = base * FLOAT64_POW5_TABLE_SIZE;
722 const mul = &FLOAT64_POW5_SPLIT2[base];
723 if (i == base2) {
724 return .{ mul[0], mul[1] };
725 } else {
726 const offset = i - base2;
727 const m = FLOAT64_POW5_TABLE[offset];
728 const b0 = @as(u128, m) * mul[0];
729 const b2 = @as(u128, m) * mul[1];
730 const delta: u7 = @intCast(pow5Bits(i) - pow5Bits(base2));
731 const shift: u5 = @intCast((i % 16) << 1);
732 const shifted_sum = ((b0 >> delta) + (b2 << (64 - delta))) + 1 + ((FLOAT64_POW5_OFFSETS[i / 16] >> shift) & 3);
733 return .{ @truncate(shifted_sum), @truncate(shifted_sum >> 64) };
734 }
735 }
736
737 fn computeInvPow5(i: u32) [2]u64 {
738 const base = (i + FLOAT64_POW5_TABLE_SIZE - 1) / FLOAT64_POW5_TABLE_SIZE;
739 const base2 = base * FLOAT64_POW5_TABLE_SIZE;
740 const mul = &FLOAT64_POW5_INV_SPLIT2[base]; // 1 / 5^base2
741 if (i == base2) {
742 return .{ mul[0], mul[1] };
743 } else {
744 const offset = base2 - i;
745 const m = FLOAT64_POW5_TABLE[offset]; // 5^offset
746 const b0 = @as(u128, m) * (mul[0] - 1);
747 const b2 = @as(u128, m) * mul[1]; // 1/5^base2 * 5^offset = 1/5^(base2-offset) = 1/5^i
748 const delta: u7 = @intCast(pow5Bits(base2) - pow5Bits(i));
749 const shift: u5 = @intCast((i % 16) << 1);
750 const shifted_sum = ((b0 >> delta) + (b2 << (64 - delta))) + 1 + ((FLOAT64_POW5_INV_OFFSETS[i / 16] >> shift) & 3);
751 return .{ @truncate(shifted_sum), @truncate(shifted_sum >> 64) };
752 }
753 }
754};
755
756const FLOAT64_POW5_INV_BITCOUNT = 125;
757const FLOAT64_POW5_BITCOUNT = 125;
758
759// zig fmt: off
760//
761// f64 small tables: 816 bytes
762
763const FLOAT64_POW5_TABLE_SIZE: comptime_int = FLOAT64_POW5_TABLE.len;
764
765const FLOAT64_POW5_TABLE: [26]u64 = .{
766 1, 5,
767 25, 125,
768 625, 3125,
769 15625, 78125,
770 390625, 1953125,
771 9765625, 48828125,
772 244140625, 1220703125,
773 6103515625, 30517578125,
774 152587890625, 762939453125,
775 3814697265625, 19073486328125,
776 95367431640625, 476837158203125,
777 2384185791015625, 11920928955078125,
778 59604644775390625, 298023223876953125,
779};
780
781const FLOAT64_POW5_SPLIT2: [13][2]u64 = .{
782 .{ 0, 1152921504606846976 },
783 .{ 0, 1490116119384765625 },
784 .{ 1032610780636961552, 1925929944387235853 },
785 .{ 7910200175544436838, 1244603055572228341 },
786 .{ 16941905809032713930, 1608611746708759036 },
787 .{ 13024893955298202172, 2079081953128979843 },
788 .{ 6607496772837067824, 1343575221513417750 },
789 .{ 17332926989895652603, 1736530273035216783 },
790 .{ 13037379183483547984, 2244412773384604712 },
791 .{ 1605989338741628675, 1450417759929778918 },
792 .{ 9630225068416591280, 1874621017369538693 },
793 .{ 665883850346957067, 1211445438634777304 },
794 .{ 14931890668723713708, 1565756531257009982 }
795};
796
797const FLOAT64_POW5_OFFSETS: [21]u32 = .{
798 0x00000000, 0x00000000, 0x00000000, 0x00000000,
799 0x40000000, 0x59695995, 0x55545555, 0x56555515,
800 0x41150504, 0x40555410, 0x44555145, 0x44504540,
801 0x45555550, 0x40004000, 0x96440440, 0x55565565,
802 0x54454045, 0x40154151, 0x55559155, 0x51405555,
803 0x00000105,
804};
805
806const FLOAT64_POW5_INV_SPLIT2: [15][2]u64 = .{
807 .{ 1, 2305843009213693952 },
808 .{ 5955668970331000884, 1784059615882449851 },
809 .{ 8982663654677661702, 1380349269358112757 },
810 .{ 7286864317269821294, 2135987035920910082 },
811 .{ 7005857020398200553, 1652639921975621497 },
812 .{ 17965325103354776697, 1278668206209430417 },
813 .{ 8928596168509315048, 1978643211784836272 },
814 .{ 10075671573058298858, 1530901034580419511 },
815 .{ 597001226353042382, 1184477304306571148 },
816 .{ 1527430471115325346, 1832889850782397517 },
817 .{ 12533209867169019542, 1418129833677084982 },
818 .{ 5577825024675947042, 2194449627517475473 },
819 .{ 11006974540203867551, 1697873161311732311 },
820 .{ 10313493231639821582, 1313665730009899186 },
821 .{ 12701016819766672773, 2032799256770390445 }
822};
823
824const FLOAT64_POW5_INV_OFFSETS: [19]u32 = .{
825 0x54544554, 0x04055545, 0x10041000, 0x00400414,
826 0x40010000, 0x41155555, 0x00000454, 0x00010044,
827 0x40000000, 0x44000041, 0x50454450, 0x55550054,
828 0x51655554, 0x40004000, 0x01000001, 0x00010500,
829 0x51515411, 0x05555554, 0x00000000,
830};
831
832
833// zig fmt: off
834
835// f64 full tables: 10688 bytes
836
837const FLOAT64_POW5_SPLIT: [326][2]u64 = .{
838 .{ 0, 1152921504606846976 }, .{ 0, 1441151880758558720 },
839 .{ 0, 1801439850948198400 }, .{ 0, 2251799813685248000 },
840 .{ 0, 1407374883553280000 }, .{ 0, 1759218604441600000 },
841 .{ 0, 2199023255552000000 }, .{ 0, 1374389534720000000 },
842 .{ 0, 1717986918400000000 }, .{ 0, 2147483648000000000 },
843 .{ 0, 1342177280000000000 }, .{ 0, 1677721600000000000 },
844 .{ 0, 2097152000000000000 }, .{ 0, 1310720000000000000 },
845 .{ 0, 1638400000000000000 }, .{ 0, 2048000000000000000 },
846 .{ 0, 1280000000000000000 }, .{ 0, 1600000000000000000 },
847 .{ 0, 2000000000000000000 }, .{ 0, 1250000000000000000 },
848 .{ 0, 1562500000000000000 }, .{ 0, 1953125000000000000 },
849 .{ 0, 1220703125000000000 }, .{ 0, 1525878906250000000 },
850 .{ 0, 1907348632812500000 }, .{ 0, 1192092895507812500 },
851 .{ 0, 1490116119384765625 }, .{ 4611686018427387904, 1862645149230957031 },
852 .{ 9799832789158199296, 1164153218269348144 }, .{ 12249790986447749120, 1455191522836685180 },
853 .{ 15312238733059686400, 1818989403545856475 }, .{ 14528612397897220096, 2273736754432320594 },
854 .{ 13692068767113150464, 1421085471520200371 }, .{ 12503399940464050176, 1776356839400250464 },
855 .{ 15629249925580062720, 2220446049250313080 }, .{ 9768281203487539200, 1387778780781445675 },
856 .{ 7598665485932036096, 1734723475976807094 }, .{ 274959820560269312, 2168404344971008868 },
857 .{ 9395221924704944128, 1355252715606880542 }, .{ 2520655369026404352, 1694065894508600678 },
858 .{ 12374191248137781248, 2117582368135750847 }, .{ 14651398557727195136, 1323488980084844279 },
859 .{ 13702562178731606016, 1654361225106055349 }, .{ 3293144668132343808, 2067951531382569187 },
860 .{ 18199116482078572544, 1292469707114105741 }, .{ 8913837547316051968, 1615587133892632177 },
861 .{ 15753982952572452864, 2019483917365790221 }, .{ 12152082354571476992, 1262177448353618888 },
862 .{ 15190102943214346240, 1577721810442023610 }, .{ 9764256642163156992, 1972152263052529513 },
863 .{ 17631875447420442880, 1232595164407830945 }, .{ 8204786253993389888, 1540743955509788682 },
864 .{ 1032610780636961552, 1925929944387235853 }, .{ 2951224747111794922, 1203706215242022408 },
865 .{ 3689030933889743652, 1504632769052528010 }, .{ 13834660704216955373, 1880790961315660012 },
866 .{ 17870034976990372916, 1175494350822287507 }, .{ 17725857702810578241, 1469367938527859384 },
867 .{ 3710578054803671186, 1836709923159824231 }, .{ 26536550077201078, 2295887403949780289 },
868 .{ 11545800389866720434, 1434929627468612680 }, .{ 14432250487333400542, 1793662034335765850 },
869 .{ 8816941072311974870, 2242077542919707313 }, .{ 17039803216263454053, 1401298464324817070 },
870 .{ 12076381983474541759, 1751623080406021338 }, .{ 5872105442488401391, 2189528850507526673 },
871 .{ 15199280947623720629, 1368455531567204170 }, .{ 9775729147674874978, 1710569414459005213 },
872 .{ 16831347453020981627, 2138211768073756516 }, .{ 1296220121283337709, 1336382355046097823 },
873 .{ 15455333206886335848, 1670477943807622278 }, .{ 10095794471753144002, 2088097429759527848 },
874 .{ 6309871544845715001, 1305060893599704905 }, .{ 12499025449484531656, 1631326116999631131 },
875 .{ 11012095793428276666, 2039157646249538914 }, .{ 11494245889320060820, 1274473528905961821 },
876 .{ 532749306367912313, 1593091911132452277 }, .{ 5277622651387278295, 1991364888915565346 },
877 .{ 7910200175544436838, 1244603055572228341 }, .{ 14499436237857933952, 1555753819465285426 },
878 .{ 8900923260467641632, 1944692274331606783 }, .{ 12480606065433357876, 1215432671457254239 },
879 .{ 10989071563364309441, 1519290839321567799 }, .{ 9124653435777998898, 1899113549151959749 },
880 .{ 8008751406574943263, 1186945968219974843 }, .{ 5399253239791291175, 1483682460274968554 },
881 .{ 15972438586593889776, 1854603075343710692 }, .{ 759402079766405302, 1159126922089819183 },
882 .{ 14784310654990170340, 1448908652612273978 }, .{ 9257016281882937117, 1811135815765342473 },
883 .{ 16182956370781059300, 2263919769706678091 }, .{ 7808504722524468110, 1414949856066673807 },
884 .{ 5148944884728197234, 1768687320083342259 }, .{ 1824495087482858639, 2210859150104177824 },
885 .{ 1140309429676786649, 1381786968815111140 }, .{ 1425386787095983311, 1727233711018888925 },
886 .{ 6393419502297367043, 2159042138773611156 }, .{ 13219259225790630210, 1349401336733506972 },
887 .{ 16524074032238287762, 1686751670916883715 }, .{ 16043406521870471799, 2108439588646104644 },
888 .{ 803757039314269066, 1317774742903815403 }, .{ 14839754354425000045, 1647218428629769253 },
889 .{ 4714634887749086344, 2059023035787211567 }, .{ 9864175832484260821, 1286889397367007229 },
890 .{ 16941905809032713930, 1608611746708759036 }, .{ 2730638187581340797, 2010764683385948796 },
891 .{ 10930020904093113806, 1256727927116217997 }, .{ 18274212148543780162, 1570909908895272496 },
892 .{ 4396021111970173586, 1963637386119090621 }, .{ 5053356204195052443, 1227273366324431638 },
893 .{ 15540067292098591362, 1534091707905539547 }, .{ 14813398096695851299, 1917614634881924434 },
894 .{ 13870059828862294966, 1198509146801202771 }, .{ 12725888767650480803, 1498136433501503464 },
895 .{ 15907360959563101004, 1872670541876879330 }, .{ 14553786618154326031, 1170419088673049581 },
896 .{ 4357175217410743827, 1463023860841311977 }, .{ 10058155040190817688, 1828779826051639971 },
897 .{ 7961007781811134206, 2285974782564549964 }, .{ 14199001900486734687, 1428734239102843727 },
898 .{ 13137066357181030455, 1785917798878554659 }, .{ 11809646928048900164, 2232397248598193324 },
899 .{ 16604401366885338411, 1395248280373870827 }, .{ 16143815690179285109, 1744060350467338534 },
900 .{ 10956397575869330579, 2180075438084173168 }, .{ 6847748484918331612, 1362547148802608230 },
901 .{ 17783057643002690323, 1703183936003260287 }, .{ 17617136035325974999, 2128979920004075359 },
902 .{ 17928239049719816230, 1330612450002547099 }, .{ 17798612793722382384, 1663265562503183874 },
903 .{ 13024893955298202172, 2079081953128979843 }, .{ 5834715712847682405, 1299426220705612402 },
904 .{ 16516766677914378815, 1624282775882015502 }, .{ 11422586310538197711, 2030353469852519378 },
905 .{ 11750802462513761473, 1268970918657824611 }, .{ 10076817059714813937, 1586213648322280764 },
906 .{ 12596021324643517422, 1982767060402850955 }, .{ 5566670318688504437, 1239229412751781847 },
907 .{ 2346651879933242642, 1549036765939727309 }, .{ 7545000868343941206, 1936295957424659136 },
908 .{ 4715625542714963254, 1210184973390411960 }, .{ 5894531928393704067, 1512731216738014950 },
909 .{ 16591536947346905892, 1890914020922518687 }, .{ 17287239619732898039, 1181821263076574179 },
910 .{ 16997363506238734644, 1477276578845717724 }, .{ 2799960309088866689, 1846595723557147156 },
911 .{ 10973347230035317489, 1154122327223216972 }, .{ 13716684037544146861, 1442652909029021215 },
912 .{ 12534169028502795672, 1803316136286276519 }, .{ 11056025267201106687, 2254145170357845649 },
913 .{ 18439230838069161439, 1408840731473653530 }, .{ 13825666510731675991, 1761050914342066913 },
914 .{ 3447025083132431277, 2201313642927583642 }, .{ 6766076695385157452, 1375821026829739776 },
915 .{ 8457595869231446815, 1719776283537174720 }, .{ 10571994836539308519, 2149720354421468400 },
916 .{ 6607496772837067824, 1343575221513417750 }, .{ 17482743002901110588, 1679469026891772187 },
917 .{ 17241742735199000331, 2099336283614715234 }, .{ 15387775227926763111, 1312085177259197021 },
918 .{ 5399660979626290177, 1640106471573996277 }, .{ 11361262242960250625, 2050133089467495346 },
919 .{ 11712474920277544544, 1281333180917184591 }, .{ 10028907631919542777, 1601666476146480739 },
920 .{ 7924448521472040567, 2002083095183100924 }, .{ 14176152362774801162, 1251301934489438077 },
921 .{ 3885132398186337741, 1564127418111797597 }, .{ 9468101516160310080, 1955159272639746996 },
922 .{ 15140935484454969608, 1221974545399841872 }, .{ 479425281859160394, 1527468181749802341 },
923 .{ 5210967620751338397, 1909335227187252926 }, .{ 17091912818251750210, 1193334516992033078 },
924 .{ 12141518985959911954, 1491668146240041348 }, .{ 15176898732449889943, 1864585182800051685 },
925 .{ 11791404716994875166, 1165365739250032303 }, .{ 10127569877816206054, 1456707174062540379 },
926 .{ 8047776328842869663, 1820883967578175474 }, .{ 836348374198811271, 2276104959472719343 },
927 .{ 7440246761515338900, 1422565599670449589 }, .{ 13911994470321561530, 1778206999588061986 },
928 .{ 8166621051047176104, 2222758749485077483 }, .{ 2798295147690791113, 1389224218428173427 },
929 .{ 17332926989895652603, 1736530273035216783 }, .{ 17054472718942177850, 2170662841294020979 },
930 .{ 8353202440125167204, 1356664275808763112 }, .{ 10441503050156459005, 1695830344760953890 },
931 .{ 3828506775840797949, 2119787930951192363 }, .{ 86973725686804766, 1324867456844495227 },
932 .{ 13943775212390669669, 1656084321055619033 }, .{ 3594660960206173375, 2070105401319523792 },
933 .{ 2246663100128858359, 1293815875824702370 }, .{ 12031700912015848757, 1617269844780877962 },
934 .{ 5816254103165035138, 2021587305976097453 }, .{ 5941001823691840913, 1263492066235060908 },
935 .{ 7426252279614801142, 1579365082793826135 }, .{ 4671129331091113523, 1974206353492282669 },
936 .{ 5225298841145639904, 1233878970932676668 }, .{ 6531623551432049880, 1542348713665845835 },
937 .{ 3552843420862674446, 1927935892082307294 }, .{ 16055585193321335241, 1204959932551442058 },
938 .{ 10846109454796893243, 1506199915689302573 }, .{ 18169322836923504458, 1882749894611628216 },
939 .{ 11355826773077190286, 1176718684132267635 }, .{ 9583097447919099954, 1470898355165334544 },
940 .{ 11978871809898874942, 1838622943956668180 }, .{ 14973589762373593678, 2298278679945835225 },
941 .{ 2440964573842414192, 1436424174966147016 }, .{ 3051205717303017741, 1795530218707683770 },
942 .{ 13037379183483547984, 2244412773384604712 }, .{ 8148361989677217490, 1402757983365377945 },
943 .{ 14797138505523909766, 1753447479206722431 }, .{ 13884737113477499304, 2191809349008403039 },
944 .{ 15595489723564518921, 1369880843130251899 }, .{ 14882676136028260747, 1712351053912814874 },
945 .{ 9379973133180550126, 2140438817391018593 }, .{ 17391698254306313589, 1337774260869386620 },
946 .{ 3292878744173340370, 1672217826086733276 }, .{ 4116098430216675462, 2090272282608416595 },
947 .{ 266718509671728212, 1306420176630260372 }, .{ 333398137089660265, 1633025220787825465 },
948 .{ 5028433689789463235, 2041281525984781831 }, .{ 10060300083759496378, 1275800953740488644 },
949 .{ 12575375104699370472, 1594751192175610805 }, .{ 1884160825592049379, 1993438990219513507 },
950 .{ 17318501580490888525, 1245899368887195941 }, .{ 7813068920331446945, 1557374211108994927 },
951 .{ 5154650131986920777, 1946717763886243659 }, .{ 915813323278131534, 1216698602428902287 },
952 .{ 14979824709379828129, 1520873253036127858 }, .{ 9501408849870009354, 1901091566295159823 },
953 .{ 12855909558809837702, 1188182228934474889 }, .{ 2234828893230133415, 1485227786168093612 },
954 .{ 2793536116537666769, 1856534732710117015 }, .{ 8663489100477123587, 1160334207943823134 },
955 .{ 1605989338741628675, 1450417759929778918 }, .{ 11230858710281811652, 1813022199912223647 },
956 .{ 9426887369424876662, 2266277749890279559 }, .{ 12809333633531629769, 1416423593681424724 },
957 .{ 16011667041914537212, 1770529492101780905 }, .{ 6179525747111007803, 2213161865127226132 },
958 .{ 13085575628799155685, 1383226165704516332 }, .{ 16356969535998944606, 1729032707130645415 },
959 .{ 15834525901571292854, 2161290883913306769 }, .{ 2979049660840976177, 1350806802445816731 },
960 .{ 17558870131333383934, 1688508503057270913 }, .{ 8113529608884566205, 2110635628821588642 },
961 .{ 9682642023980241782, 1319147268013492901 }, .{ 16714988548402690132, 1648934085016866126 },
962 .{ 11670363648648586857, 2061167606271082658 }, .{ 11905663298832754689, 1288229753919426661 },
963 .{ 1047021068258779650, 1610287192399283327 }, .{ 15143834390605638274, 2012858990499104158 },
964 .{ 4853210475701136017, 1258036869061940099 }, .{ 1454827076199032118, 1572546086327425124 },
965 .{ 1818533845248790147, 1965682607909281405 }, .{ 3442426662494187794, 1228551629943300878 },
966 .{ 13526405364972510550, 1535689537429126097 }, .{ 3072948650933474476, 1919611921786407622 },
967 .{ 15755650962115585259, 1199757451116504763 }, .{ 15082877684217093670, 1499696813895630954 },
968 .{ 9630225068416591280, 1874621017369538693 }, .{ 8324733676974063502, 1171638135855961683 },
969 .{ 5794231077790191473, 1464547669819952104 }, .{ 7242788847237739342, 1830684587274940130 },
970 .{ 18276858095901949986, 2288355734093675162 }, .{ 16034722328366106645, 1430222333808546976 },
971 .{ 1596658836748081690, 1787777917260683721 }, .{ 6607509564362490017, 2234722396575854651 },
972 .{ 1823850468512862308, 1396701497859909157 }, .{ 6891499104068465790, 1745876872324886446 },
973 .{ 17837745916940358045, 2182346090406108057 }, .{ 4231062170446641922, 1363966306503817536 },
974 .{ 5288827713058302403, 1704957883129771920 }, .{ 6611034641322878003, 2131197353912214900 },
975 .{ 13355268687681574560, 1331998346195134312 }, .{ 16694085859601968200, 1664997932743917890 },
976 .{ 11644235287647684442, 2081247415929897363 }, .{ 4971804045566108824, 1300779634956185852 },
977 .{ 6214755056957636030, 1625974543695232315 }, .{ 3156757802769657134, 2032468179619040394 },
978 .{ 6584659645158423613, 1270292612261900246 }, .{ 17454196593302805324, 1587865765327375307 },
979 .{ 17206059723201118751, 1984832206659219134 }, .{ 6142101308573311315, 1240520129162011959 },
980 .{ 3065940617289251240, 1550650161452514949 }, .{ 8444111790038951954, 1938312701815643686 },
981 .{ 665883850346957067, 1211445438634777304 }, .{ 832354812933696334, 1514306798293471630 },
982 .{ 10263815553021896226, 1892883497866839537 }, .{ 17944099766707154901, 1183052186166774710 },
983 .{ 13206752671529167818, 1478815232708468388 }, .{ 16508440839411459773, 1848519040885585485 },
984 .{ 12623618533845856310, 1155324400553490928 }, .{ 15779523167307320387, 1444155500691863660 },
985 .{ 1277659885424598868, 1805194375864829576 }, .{ 1597074856780748586, 2256492969831036970 },
986 .{ 5609857803915355770, 1410308106144398106 }, .{ 16235694291748970521, 1762885132680497632 },
987 .{ 1847873790976661535, 2203606415850622041 }, .{ 12684136165428883219, 1377254009906638775 },
988 .{ 11243484188358716120, 1721567512383298469 }, .{ 219297180166231438, 2151959390479123087 },
989 .{ 7054589765244976505, 1344974619049451929 }, .{ 13429923224983608535, 1681218273811814911 },
990 .{ 12175718012802122765, 2101522842264768639 }, .{ 14527352785642408584, 1313451776415480399 },
991 .{ 13547504963625622826, 1641814720519350499 }, .{ 12322695186104640628, 2052268400649188124 },
992 .{ 16925056528170176201, 1282667750405742577 }, .{ 7321262604930556539, 1603334688007178222 },
993 .{ 18374950293017971482, 2004168360008972777 }, .{ 4566814905495150320, 1252605225005607986 },
994 .{ 14931890668723713708, 1565756531257009982 }, .{ 9441491299049866327, 1957195664071262478 },
995 .{ 1289246043478778550, 1223247290044539049 }, .{ 6223243572775861092, 1529059112555673811 },
996 .{ 3167368447542438461, 1911323890694592264 }, .{ 1979605279714024038, 1194577431684120165 },
997 .{ 7086192618069917952, 1493221789605150206 }, .{ 18081112809442173248, 1866527237006437757 },
998 .{ 13606538515115052232, 1166579523129023598 }, .{ 7784801107039039482, 1458224403911279498 },
999 .{ 507629346944023544, 1822780504889099373 }, .{ 5246222702107417334, 2278475631111374216 },
1000 .{ 3278889188817135834, 1424047269444608885 }, .{ 8710297504448807696, 1780059086805761106 }
1001};
1002
1003const FLOAT64_POW5_INV_SPLIT: [342][2]u64 = .{
1004 .{ 1, 2305843009213693952 }, .{ 11068046444225730970, 1844674407370955161 },
1005 .{ 5165088340638674453, 1475739525896764129 }, .{ 7821419487252849886, 1180591620717411303 },
1006 .{ 8824922364862649494, 1888946593147858085 }, .{ 7059937891890119595, 1511157274518286468 },
1007 .{ 13026647942995916322, 1208925819614629174 }, .{ 9774590264567735146, 1934281311383406679 },
1008 .{ 11509021026396098440, 1547425049106725343 }, .{ 16585914450600699399, 1237940039285380274 },
1009 .{ 15469416676735388068, 1980704062856608439 }, .{ 16064882156130220778, 1584563250285286751 },
1010 .{ 9162556910162266299, 1267650600228229401 }, .{ 7281393426775805432, 2028240960365167042 },
1011 .{ 16893161185646375315, 1622592768292133633 }, .{ 2446482504291369283, 1298074214633706907 },
1012 .{ 7603720821608101175, 2076918743413931051 }, .{ 2393627842544570617, 1661534994731144841 },
1013 .{ 16672297533003297786, 1329227995784915872 }, .{ 11918280793837635165, 2126764793255865396 },
1014 .{ 5845275820328197809, 1701411834604692317 }, .{ 15744267100488289217, 1361129467683753853 },
1015 .{ 3054734472329800808, 2177807148294006166 }, .{ 17201182836831481939, 1742245718635204932 },
1016 .{ 6382248639981364905, 1393796574908163946 }, .{ 2832900194486363201, 2230074519853062314 },
1017 .{ 5955668970331000884, 1784059615882449851 }, .{ 1075186361522890384, 1427247692705959881 },
1018 .{ 12788344622662355584, 2283596308329535809 }, .{ 13920024512871794791, 1826877046663628647 },
1019 .{ 3757321980813615186, 1461501637330902918 }, .{ 10384555214134712795, 1169201309864722334 },
1020 .{ 5547241898389809503, 1870722095783555735 }, .{ 4437793518711847602, 1496577676626844588 },
1021 .{ 10928932444453298728, 1197262141301475670 }, .{ 17486291911125277965, 1915619426082361072 },
1022 .{ 6610335899416401726, 1532495540865888858 }, .{ 12666966349016942027, 1225996432692711086 },
1023 .{ 12888448528943286597, 1961594292308337738 }, .{ 17689456452638449924, 1569275433846670190 },
1024 .{ 14151565162110759939, 1255420347077336152 }, .{ 7885109000409574610, 2008672555323737844 },
1025 .{ 9997436015069570011, 1606938044258990275 }, .{ 7997948812055656009, 1285550435407192220 },
1026 .{ 12796718099289049614, 2056880696651507552 }, .{ 2858676849947419045, 1645504557321206042 },
1027 .{ 13354987924183666206, 1316403645856964833 }, .{ 17678631863951955605, 2106245833371143733 },
1028 .{ 3074859046935833515, 1684996666696914987 }, .{ 13527933681774397782, 1347997333357531989 },
1029 .{ 10576647446613305481, 2156795733372051183 }, .{ 15840015586774465031, 1725436586697640946 },
1030 .{ 8982663654677661702, 1380349269358112757 }, .{ 18061610662226169046, 2208558830972980411 },
1031 .{ 10759939715039024913, 1766847064778384329 }, .{ 12297300586773130254, 1413477651822707463 },
1032 .{ 15986332124095098083, 2261564242916331941 }, .{ 9099716884534168143, 1809251394333065553 },
1033 .{ 14658471137111155161, 1447401115466452442 }, .{ 4348079280205103483, 1157920892373161954 },
1034 .{ 14335624477811986218, 1852673427797059126 }, .{ 7779150767507678651, 1482138742237647301 },
1035 .{ 2533971799264232598, 1185710993790117841 }, .{ 15122401323048503126, 1897137590064188545 },
1036 .{ 12097921058438802501, 1517710072051350836 }, .{ 5988988032009131678, 1214168057641080669 },
1037 .{ 16961078480698431330, 1942668892225729070 }, .{ 13568862784558745064, 1554135113780583256 },
1038 .{ 7165741412905085728, 1243308091024466605 }, .{ 11465186260648137165, 1989292945639146568 },
1039 .{ 16550846638002330379, 1591434356511317254 }, .{ 16930026125143774626, 1273147485209053803 },
1040 .{ 4951948911778577463, 2037035976334486086 }, .{ 272210314680951647, 1629628781067588869 },
1041 .{ 3907117066486671641, 1303703024854071095 }, .{ 6251387306378674625, 2085924839766513752 },
1042 .{ 16069156289328670670, 1668739871813211001 }, .{ 9165976216721026213, 1334991897450568801 },
1043 .{ 7286864317269821294, 2135987035920910082 }, .{ 16897537898041588005, 1708789628736728065 },
1044 .{ 13518030318433270404, 1367031702989382452 }, .{ 6871453250525591353, 2187250724783011924 },
1045 .{ 9186511415162383406, 1749800579826409539 }, .{ 11038557946871817048, 1399840463861127631 },
1046 .{ 10282995085511086630, 2239744742177804210 }, .{ 8226396068408869304, 1791795793742243368 },
1047 .{ 13959814484210916090, 1433436634993794694 }, .{ 11267656730511734774, 2293498615990071511 },
1048 .{ 5324776569667477496, 1834798892792057209 }, .{ 7949170070475892320, 1467839114233645767 },
1049 .{ 17427382500606444826, 1174271291386916613 }, .{ 5747719112518849781, 1878834066219066582 },
1050 .{ 15666221734240810795, 1503067252975253265 }, .{ 12532977387392648636, 1202453802380202612 },
1051 .{ 5295368560860596524, 1923926083808324180 }, .{ 4236294848688477220, 1539140867046659344 },
1052 .{ 7078384693692692099, 1231312693637327475 }, .{ 11325415509908307358, 1970100309819723960 },
1053 .{ 9060332407926645887, 1576080247855779168 }, .{ 14626963555825137356, 1260864198284623334 },
1054 .{ 12335095245094488799, 2017382717255397335 }, .{ 9868076196075591040, 1613906173804317868 },
1055 .{ 15273158586344293478, 1291124939043454294 }, .{ 13369007293925138595, 2065799902469526871 },
1056 .{ 7005857020398200553, 1652639921975621497 }, .{ 16672732060544291412, 1322111937580497197 },
1057 .{ 11918976037903224966, 2115379100128795516 }, .{ 5845832015580669650, 1692303280103036413 },
1058 .{ 12055363241948356366, 1353842624082429130 }, .{ 841837113407818570, 2166148198531886609 },
1059 .{ 4362818505468165179, 1732918558825509287 }, .{ 14558301248600263113, 1386334847060407429 },
1060 .{ 12225235553534690011, 2218135755296651887 }, .{ 2401490813343931363, 1774508604237321510 },
1061 .{ 1921192650675145090, 1419606883389857208 }, .{ 17831303500047873437, 2271371013423771532 },
1062 .{ 6886345170554478103, 1817096810739017226 }, .{ 1819727321701672159, 1453677448591213781 },
1063 .{ 16213177116328979020, 1162941958872971024 }, .{ 14873036941900635463, 1860707134196753639 },
1064 .{ 15587778368262418694, 1488565707357402911 }, .{ 8780873879868024632, 1190852565885922329 },
1065 .{ 2981351763563108441, 1905364105417475727 }, .{ 13453127855076217722, 1524291284333980581 },
1066 .{ 7073153469319063855, 1219433027467184465 }, .{ 11317045550910502167, 1951092843947495144 },
1067 .{ 12742985255470312057, 1560874275157996115 }, .{ 10194388204376249646, 1248699420126396892 },
1068 .{ 1553625868034358140, 1997919072202235028 }, .{ 8621598323911307159, 1598335257761788022 },
1069 .{ 17965325103354776697, 1278668206209430417 }, .{ 13987124906400001422, 2045869129935088668 },
1070 .{ 121653480894270168, 1636695303948070935 }, .{ 97322784715416134, 1309356243158456748 },
1071 .{ 14913111714512307107, 2094969989053530796 }, .{ 8241140556867935363, 1675975991242824637 },
1072 .{ 17660958889720079260, 1340780792994259709 }, .{ 17189487779326395846, 2145249268790815535 },
1073 .{ 13751590223461116677, 1716199415032652428 }, .{ 18379969808252713988, 1372959532026121942 },
1074 .{ 14650556434236701088, 2196735251241795108 }, .{ 652398703163629901, 1757388200993436087 },
1075 .{ 11589965406756634890, 1405910560794748869 }, .{ 7475898206584884855, 2249456897271598191 },
1076 .{ 2291369750525997561, 1799565517817278553 }, .{ 9211793429904618695, 1439652414253822842 },
1077 .{ 18428218302589300235, 2303443862806116547 }, .{ 7363877012587619542, 1842755090244893238 },
1078 .{ 13269799239553916280, 1474204072195914590 }, .{ 10615839391643133024, 1179363257756731672 },
1079 .{ 2227947767661371545, 1886981212410770676 }, .{ 16539753473096738529, 1509584969928616540 },
1080 .{ 13231802778477390823, 1207667975942893232 }, .{ 6413489186596184024, 1932268761508629172 },
1081 .{ 16198837793502678189, 1545815009206903337 }, .{ 5580372605318321905, 1236652007365522670 },
1082 .{ 8928596168509315048, 1978643211784836272 }, .{ 18210923379033183008, 1582914569427869017 },
1083 .{ 7190041073742725760, 1266331655542295214 }, .{ 436019273762630246, 2026130648867672343 },
1084 .{ 7727513048493924843, 1620904519094137874 }, .{ 9871359253537050198, 1296723615275310299 },
1085 .{ 4726128361433549347, 2074757784440496479 }, .{ 7470251503888749801, 1659806227552397183 },
1086 .{ 13354898832594820487, 1327844982041917746 }, .{ 13989140502667892133, 2124551971267068394 },
1087 .{ 14880661216876224029, 1699641577013654715 }, .{ 11904528973500979224, 1359713261610923772 },
1088 .{ 4289851098633925465, 2175541218577478036 }, .{ 18189276137874781665, 1740432974861982428 },
1089 .{ 3483374466074094362, 1392346379889585943 }, .{ 1884050330976640656, 2227754207823337509 },
1090 .{ 5196589079523222848, 1782203366258670007 }, .{ 15225317707844309248, 1425762693006936005 },
1091 .{ 5913764258841343181, 2281220308811097609 }, .{ 8420360221814984868, 1824976247048878087 },
1092 .{ 17804334621677718864, 1459980997639102469 }, .{ 17932816512084085415, 1167984798111281975 },
1093 .{ 10245762345624985047, 1868775676978051161 }, .{ 4507261061758077715, 1495020541582440929 },
1094 .{ 7295157664148372495, 1196016433265952743 }, .{ 7982903447895485668, 1913626293225524389 },
1095 .{ 10075671573058298858, 1530901034580419511 }, .{ 4371188443704728763, 1224720827664335609 },
1096 .{ 14372599139411386667, 1959553324262936974 }, .{ 15187428126271019657, 1567642659410349579 },
1097 .{ 15839291315758726049, 1254114127528279663 }, .{ 3206773216762499739, 2006582604045247462 },
1098 .{ 13633465017635730761, 1605266083236197969 }, .{ 14596120828850494932, 1284212866588958375 },
1099 .{ 4907049252451240275, 2054740586542333401 }, .{ 236290587219081897, 1643792469233866721 },
1100 .{ 14946427728742906810, 1315033975387093376 }, .{ 16535586736504830250, 2104054360619349402 },
1101 .{ 5849771759720043554, 1683243488495479522 }, .{ 15747863852001765813, 1346594790796383617 },
1102 .{ 10439186904235184007, 2154551665274213788 }, .{ 15730047152871967852, 1723641332219371030 },
1103 .{ 12584037722297574282, 1378913065775496824 }, .{ 9066413911450387881, 2206260905240794919 },
1104 .{ 10942479943902220628, 1765008724192635935 }, .{ 8753983955121776503, 1412006979354108748 },
1105 .{ 10317025513452932081, 2259211166966573997 }, .{ 874922781278525018, 1807368933573259198 },
1106 .{ 8078635854506640661, 1445895146858607358 }, .{ 13841606313089133175, 1156716117486885886 },
1107 .{ 14767872471458792434, 1850745787979017418 }, .{ 746251532941302978, 1480596630383213935 },
1108 .{ 597001226353042382, 1184477304306571148 }, .{ 15712597221132509104, 1895163686890513836 },
1109 .{ 8880728962164096960, 1516130949512411069 }, .{ 10793931984473187891, 1212904759609928855 },
1110 .{ 17270291175157100626, 1940647615375886168 }, .{ 2748186495899949531, 1552518092300708935 },
1111 .{ 2198549196719959625, 1242014473840567148 }, .{ 18275073973719576693, 1987223158144907436 },
1112 .{ 10930710364233751031, 1589778526515925949 }, .{ 12433917106128911148, 1271822821212740759 },
1113 .{ 8826220925580526867, 2034916513940385215 }, .{ 7060976740464421494, 1627933211152308172 },
1114 .{ 16716827836597268165, 1302346568921846537 }, .{ 11989529279587987770, 2083754510274954460 },
1115 .{ 9591623423670390216, 1667003608219963568 }, .{ 15051996368420132820, 1333602886575970854 },
1116 .{ 13015147745246481542, 2133764618521553367 }, .{ 3033420566713364587, 1707011694817242694 },
1117 .{ 6116085268112601993, 1365609355853794155 }, .{ 9785736428980163188, 2184974969366070648 },
1118 .{ 15207286772667951197, 1747979975492856518 }, .{ 1097782973908629988, 1398383980394285215 },
1119 .{ 1756452758253807981, 2237414368630856344 }, .{ 5094511021344956708, 1789931494904685075 },
1120 .{ 4075608817075965366, 1431945195923748060 }, .{ 6520974107321544586, 2291112313477996896 },
1121 .{ 1527430471115325346, 1832889850782397517 }, .{ 12289990821117991246, 1466311880625918013 },
1122 .{ 17210690286378213644, 1173049504500734410 }, .{ 9090360384495590213, 1876879207201175057 },
1123 .{ 18340334751822203140, 1501503365760940045 }, .{ 14672267801457762512, 1201202692608752036 },
1124 .{ 16096930852848599373, 1921924308174003258 }, .{ 1809498238053148529, 1537539446539202607 },
1125 .{ 12515645034668249793, 1230031557231362085 }, .{ 1578287981759648052, 1968050491570179337 },
1126 .{ 12330676829633449412, 1574440393256143469 }, .{ 13553890278448669853, 1259552314604914775 },
1127 .{ 3239480371808320148, 2015283703367863641 }, .{ 17348979556414297411, 1612226962694290912 },
1128 .{ 6500486015647617283, 1289781570155432730 }, .{ 10400777625036187652, 2063650512248692368 },
1129 .{ 15699319729512770768, 1650920409798953894 }, .{ 16248804598352126938, 1320736327839163115 },
1130 .{ 7551343283653851484, 2113178124542660985 }, .{ 6041074626923081187, 1690542499634128788 },
1131 .{ 12211557331022285596, 1352433999707303030 }, .{ 1091747655926105338, 2163894399531684849 },
1132 .{ 4562746939482794594, 1731115519625347879 }, .{ 7339546366328145998, 1384892415700278303 },
1133 .{ 8053925371383123274, 2215827865120445285 }, .{ 6443140297106498619, 1772662292096356228 },
1134 .{ 12533209867169019542, 1418129833677084982 }, .{ 5295740528502789974, 2269007733883335972 },
1135 .{ 15304638867027962949, 1815206187106668777 }, .{ 4865013464138549713, 1452164949685335022 },
1136 .{ 14960057215536570740, 1161731959748268017 }, .{ 9178696285890871890, 1858771135597228828 },
1137 .{ 14721654658196518159, 1487016908477783062 }, .{ 4398626097073393881, 1189613526782226450 },
1138 .{ 7037801755317430209, 1903381642851562320 }, .{ 5630241404253944167, 1522705314281249856 },
1139 .{ 814844308661245011, 1218164251424999885 }, .{ 1303750893857992017, 1949062802279999816 },
1140 .{ 15800395974054034906, 1559250241823999852 }, .{ 5261619149759407279, 1247400193459199882 },
1141 .{ 12107939454356961969, 1995840309534719811 }, .{ 5997002748743659252, 1596672247627775849 },
1142 .{ 8486951013736837725, 1277337798102220679 }, .{ 2511075177753209390, 2043740476963553087 },
1143 .{ 13076906586428298482, 1634992381570842469 }, .{ 14150874083884549109, 1307993905256673975 },
1144 .{ 4194654460505726958, 2092790248410678361 }, .{ 18113118827372222859, 1674232198728542688 },
1145 .{ 3422448617672047318, 1339385758982834151 }, .{ 16543964232501006678, 2143017214372534641 },
1146 .{ 9545822571258895019, 1714413771498027713 }, .{ 15015355686490936662, 1371531017198422170 },
1147 .{ 5577825024675947042, 2194449627517475473 }, .{ 11840957649224578280, 1755559702013980378 },
1148 .{ 16851463748863483271, 1404447761611184302 }, .{ 12204946739213931940, 2247116418577894884 },
1149 .{ 13453306206113055875, 1797693134862315907 }, .{ 3383947335406624054, 1438154507889852726 },
1150 .{ 16482362180876329456, 2301047212623764361 }, .{ 9496540929959153242, 1840837770099011489 },
1151 .{ 11286581558709232917, 1472670216079209191 }, .{ 5339916432225476010, 1178136172863367353 },
1152 .{ 4854517476818851293, 1885017876581387765 }, .{ 3883613981455081034, 1508014301265110212 },
1153 .{ 14174937629389795797, 1206411441012088169 }, .{ 11611853762797942306, 1930258305619341071 },
1154 .{ 5600134195496443521, 1544206644495472857 }, .{ 15548153800622885787, 1235365315596378285 },
1155 .{ 6430302007287065643, 1976584504954205257 }, .{ 16212288050055383484, 1581267603963364205 },
1156 .{ 12969830440044306787, 1265014083170691364 }, .{ 9683682259845159889, 2024022533073106183 },
1157 .{ 15125643437359948558, 1619218026458484946 }, .{ 8411165935146048523, 1295374421166787957 },
1158 .{ 17147214310975587960, 2072599073866860731 }, .{ 10028422634038560045, 1658079259093488585 },
1159 .{ 8022738107230848036, 1326463407274790868 }, .{ 9147032156827446534, 2122341451639665389 },
1160 .{ 11006974540203867551, 1697873161311732311 }, .{ 5116230817421183718, 1358298529049385849 },
1161 .{ 15564666937357714594, 2173277646479017358 }, .{ 1383687105660440706, 1738622117183213887 },
1162 .{ 12174996128754083534, 1390897693746571109 }, .{ 8411947361780802685, 2225436309994513775 },
1163 .{ 6729557889424642148, 1780349047995611020 }, .{ 5383646311539713719, 1424279238396488816 },
1164 .{ 1235136468979721303, 2278846781434382106 }, .{ 15745504434151418335, 1823077425147505684 },
1165 .{ 16285752362063044992, 1458461940118004547 }, .{ 5649904260166615347, 1166769552094403638 },
1166 .{ 5350498001524674232, 1866831283351045821 }, .{ 591049586477829062, 1493465026680836657 },
1167 .{ 11540886113407994219, 1194772021344669325 }, .{ 18673707743239135, 1911635234151470921 },
1168 .{ 14772334225162232601, 1529308187321176736 }, .{ 8128518565387875758, 1223446549856941389 },
1169 .{ 1937583260394870242, 1957514479771106223 }, .{ 8928764237799716840, 1566011583816884978 },
1170 .{ 14521709019723594119, 1252809267053507982 }, .{ 8477339172590109297, 2004494827285612772 },
1171 .{ 17849917782297818407, 1603595861828490217 }, .{ 6901236596354434079, 1282876689462792174 },
1172 .{ 18420676183650915173, 2052602703140467478 }, .{ 3668494502695001169, 1642082162512373983 },
1173 .{ 10313493231639821582, 1313665730009899186 }, .{ 9122891541139893884, 2101865168015838698 },
1174 .{ 14677010862395735754, 1681492134412670958 }, .{ 673562245690857633, 1345193707530136767 }
1175};
1176
1177// zig fmt: off
1178//
1179// f128 small tables: 9072 bytes
1180
1181const FLOAT128_POW5_INV_BITCOUNT = 249;
1182const FLOAT128_POW5_BITCOUNT = 249;
1183const FLOAT128_POW5_TABLE_SIZE: comptime_int = FLOAT128_POW5_TABLE.len;
1184
1185const FLOAT128_POW5_TABLE: [56][2]u64 = .{
1186 .{ 1, 0 },
1187 .{ 5, 0 },
1188 .{ 25, 0 },
1189 .{ 125, 0 },
1190 .{ 625, 0 },
1191 .{ 3125, 0 },
1192 .{ 15625, 0 },
1193 .{ 78125, 0 },
1194 .{ 390625, 0 },
1195 .{ 1953125, 0 },
1196 .{ 9765625, 0 },
1197 .{ 48828125, 0 },
1198 .{ 244140625, 0 },
1199 .{ 1220703125, 0 },
1200 .{ 6103515625, 0 },
1201 .{ 30517578125, 0 },
1202 .{ 152587890625, 0 },
1203 .{ 762939453125, 0 },
1204 .{ 3814697265625, 0 },
1205 .{ 19073486328125, 0 },
1206 .{ 95367431640625, 0 },
1207 .{ 476837158203125, 0 },
1208 .{ 2384185791015625, 0 },
1209 .{ 11920928955078125, 0 },
1210 .{ 59604644775390625, 0 },
1211 .{ 298023223876953125, 0 },
1212 .{ 1490116119384765625, 0 },
1213 .{ 7450580596923828125, 0 },
1214 .{ 359414837200037393, 2 },
1215 .{ 1797074186000186965, 10 },
1216 .{ 8985370930000934825, 50 },
1217 .{ 8033366502585570893, 252 },
1218 .{ 3273344365508751233, 1262 },
1219 .{ 16366721827543756165, 6310 },
1220 .{ 8046632842880574361, 31554 },
1221 .{ 3339676066983768573, 157772 },
1222 .{ 16698380334918842865, 788860 },
1223 .{ 9704925379756007861, 3944304 },
1224 .{ 11631138751360936073, 19721522 },
1225 .{ 2815461535676025517, 98607613 },
1226 .{ 14077307678380127585, 493038065 },
1227 .{ 15046306170771983077, 2465190328 },
1228 .{ 1444554559021708921, 12325951644 },
1229 .{ 7222772795108544605, 61629758220 },
1230 .{ 17667119901833171409, 308148791101 },
1231 .{ 14548623214327650581, 1540743955509 },
1232 .{ 17402883850509598057, 7703719777548 },
1233 .{ 13227442957709783821, 38518598887744 },
1234 .{ 10796982567420264257, 192592994438723 },
1235 .{ 17091424689682218053, 962964972193617 },
1236 .{ 11670147153572883801, 4814824860968089 },
1237 .{ 3010503546735764157, 24074124304840448 },
1238 .{ 15052517733678820785, 120370621524202240 },
1239 .{ 1475612373555897461, 601853107621011204 },
1240 .{ 7378061867779487305, 3009265538105056020 },
1241 .{ 18443565265187884909, 15046327690525280101 },
1242};
1243
1244const FLOAT128_POW5_SPLIT: [89][4]u64 = .{
1245 .{ 0, 0, 0, 72057594037927936 },
1246 .{ 0, 5206161169240293376, 4575641699882439235, 73468396926392969 },
1247 .{ 3360510775605221349, 6983200512169538081, 4325643253124434363, 74906821675075173 },
1248 .{ 11917660854915489451, 9652941469841108803, 946308467778435600, 76373409087490117 },
1249 .{ 1994853395185689235, 16102657350889591545, 6847013871814915412, 77868710555449746 },
1250 .{ 958415760277438274, 15059347134713823592, 7329070255463483331, 79393288266368765 },
1251 .{ 2065144883315240188, 7145278325844925976, 14718454754511147343, 80947715414629833 },
1252 .{ 8980391188862868935, 13709057401304208685, 8230434828742694591, 82532576417087045 },
1253 .{ 432148644612782575, 7960151582448466064, 12056089168559840552, 84148467132788711 },
1254 .{ 484109300864744403, 15010663910730448582, 16824949663447227068, 85795995087002057 },
1255 .{ 14793711725276144220, 16494403799991899904, 10145107106505865967, 87475779699624060 },
1256 .{ 15427548291869817042, 12330588654550505203, 13980791795114552342, 89188452518064298 },
1257 .{ 9979404135116626552, 13477446383271537499, 14459862802511591337, 90934657454687378 },
1258 .{ 12385121150303452775, 9097130814231585614, 6523855782339765207, 92715051028904201 },
1259 .{ 1822931022538209743, 16062974719797586441, 3619180286173516788, 94530302614003091 },
1260 .{ 12318611738248470829, 13330752208259324507, 10986694768744162601, 96381094688813589 },
1261 .{ 13684493829640282333, 7674802078297225834, 15208116197624593182, 98268123094297527 },
1262 .{ 5408877057066295332, 6470124174091971006, 15112713923117703147, 100192097295163851 },
1263 .{ 11407083166564425062, 18189998238742408185, 4337638702446708282, 102153740646605557 },
1264 .{ 4112405898036935485, 924624216579956435, 14251108172073737125, 104153790666259019 },
1265 .{ 16996739107011444789, 10015944118339042475, 2395188869672266257, 106192999311487969 },
1266 .{ 4588314690421337879, 5339991768263654604, 15441007590670620066, 108272133262096356 },
1267 .{ 2286159977890359825, 14329706763185060248, 5980012964059367667, 110391974208576409 },
1268 .{ 9654767503237031099, 11293544302844823188, 11739932712678287805, 112553319146000238 },
1269 .{ 11362964448496095896, 7990659682315657680, 251480263940996374, 114756980673665505 },
1270 .{ 1423410421096377129, 14274395557581462179, 16553482793602208894, 117003787300607788 },
1271 .{ 2070444190619093137, 11517140404712147401, 11657844572835578076, 119294583757094535 },
1272 .{ 7648316884775828921, 15264332483297977688, 247182277434709002, 121630231312217685 },
1273 .{ 17410896758132241352, 10923914482914417070, 13976383996795783649, 124011608097704390 },
1274 .{ 9542674537907272703, 3079432708831728956, 14235189590642919676, 126439609438067572 },
1275 .{ 10364666969937261816, 8464573184892924210, 12758646866025101190, 128915148187220428 },
1276 .{ 14720354822146013883, 11480204489231511423, 7449876034836187038, 131439155071681461 },
1277 .{ 1692907053653558553, 17835392458598425233, 1754856712536736598, 134012579040499057 },
1278 .{ 5620591334531458755, 11361776175667106627, 13350215315297937856, 136636387622027174 },
1279 .{ 17455759733928092601, 10362573084069962561, 11246018728801810510, 139311567287686283 },
1280 .{ 2465404073814044982, 17694822665274381860, 1509954037718722697, 142039123822846312 },
1281 .{ 2152236053329638369, 11202280800589637091, 16388426812920420176, 72410041352485523 },
1282 .{ 17319024055671609028, 10944982848661280484, 2457150158022562661, 73827744744583080 },
1283 .{ 17511219308535248024, 5122059497846768077, 2089605804219668451, 75273205100637900 },
1284 .{ 10082673333144031533, 14429008783411894887, 12842832230171903890, 76746965869337783 },
1285 .{ 16196653406315961184, 10260180891682904501, 10537411930446752461, 78249581139456266 },
1286 .{ 15084422041749743389, 234835370106753111, 16662517110286225617, 79781615848172976 },
1287 .{ 8199644021067702606, 3787318116274991885, 7438130039325743106, 81343645993472659 },
1288 .{ 12039493937039359765, 9773822153580393709, 5945428874398357806, 82936258850702722 },
1289 .{ 984543865091303961, 7975107621689454830, 6556665988501773347, 84560053193370726 },
1290 .{ 9633317878125234244, 16099592426808915028, 9706674539190598200, 86215639518264828 },
1291 .{ 6860695058870476186, 4471839111886709592, 7828342285492709568, 87903640274981819 },
1292 .{ 14583324717644598331, 4496120889473451238, 5290040788305728466, 89624690099949049 },
1293 .{ 18093669366515003715, 12879506572606942994, 18005739787089675377, 91379436055028227 },
1294 .{ 17997493966862379937, 14646222655265145582, 10265023312844161858, 93168537870790806 },
1295 .{ 12283848109039722318, 11290258077250314935, 9878160025624946825, 94992668194556404 },
1296 .{ 8087752761883078164, 5262596608437575693, 11093553063763274413, 96852512843287537 },
1297 .{ 15027787746776840781, 12250273651168257752, 9290470558712181914, 98748771061435726 },
1298 .{ 15003915578366724489, 2937334162439764327, 5404085603526796602, 100682155783835929 },
1299 .{ 5225610465224746757, 14932114897406142027, 2774647558180708010, 102653393903748137 },
1300 .{ 17112957703385190360, 12069082008339002412, 3901112447086388439, 104663226546146909 },
1301 .{ 4062324464323300238, 3992768146772240329, 15757196565593695724, 106712409346361594 },
1302 .{ 5525364615810306701, 11855206026704935156, 11344868740897365300, 108801712734172003 },
1303 .{ 9274143661888462646, 4478365862348432381, 18010077872551661771, 110931922223466333 },
1304 .{ 12604141221930060148, 8930937759942591500, 9382183116147201338, 113103838707570263 },
1305 .{ 14513929377491886653, 1410646149696279084, 587092196850797612, 115318278760358235 },
1306 .{ 2226851524999454362, 7717102471110805679, 7187441550995571734, 117576074943260147 },
1307 .{ 5527526061344932763, 2347100676188369132, 16976241418824030445, 119878076118278875 },
1308 .{ 6088479778147221611, 17669593130014777580, 10991124207197663546, 122225147767136307 },
1309 .{ 11107734086759692041, 3391795220306863431, 17233960908859089158, 124618172316667879 },
1310 .{ 7913172514655155198, 17726879005381242552, 641069866244011540, 127058049470587962 },
1311 .{ 12596991768458713949, 15714785522479904446, 6035972567136116512, 129545696547750811 },
1312 .{ 16901996933781815980, 4275085211437148707, 14091642539965169063, 132082048827034281 },
1313 .{ 7524574627987869240, 15661204384239316051, 2444526454225712267, 134668059898975949 },
1314 .{ 8199251625090479942, 6803282222165044067, 16064817666437851504, 137304702024293857 },
1315 .{ 4453256673338111920, 15269922543084434181, 3139961729834750852, 139992966499426682 },
1316 .{ 15841763546372731299, 3013174075437671812, 4383755396295695606, 142733864029230733 },
1317 .{ 9771896230907310329, 4900659362437687569, 12386126719044266361, 72764212553486967 },
1318 .{ 9420455527449565190, 1859606122611023693, 6555040298902684281, 74188850200884818 },
1319 .{ 5146105983135678095, 2287300449992174951, 4325371679080264751, 75641380576797959 },
1320 .{ 11019359372592553360, 8422686425957443718, 7175176077944048210, 77122349788024458 },
1321 .{ 11005742969399620716, 4132174559240043701, 9372258443096612118, 78632314633490790 },
1322 .{ 8887589641394725840, 8029899502466543662, 14582206497241572853, 80171842813591127 },
1323 .{ 360247523705545899, 12568341805293354211, 14653258284762517866, 81741513143625247 },
1324 .{ 12314272731984275834, 4740745023227177044, 6141631472368337539, 83341915771415304 },
1325 .{ 441052047733984759, 7940090120939869826, 11750200619921094248, 84973652399183278 },
1326 .{ 3436657868127012749, 9187006432149937667, 16389726097323041290, 86637336509772529 },
1327 .{ 13490220260784534044, 15339072891382896702, 8846102360835316895, 88333593597298497 },
1328 .{ 4125672032094859833, 158347675704003277, 10592598512749774447, 90063061402315272 },
1329 .{ 12189928252974395775, 2386931199439295891, 7009030566469913276, 91826390151586454 },
1330 .{ 9256479608339282969, 2844900158963599229, 11148388908923225596, 93624242802550437 },
1331 .{ 11584393507658707408, 2863659090805147914, 9873421561981063551, 95457295292572042 },
1332 .{ 13984297296943171390, 1931468383973130608, 12905719743235082319, 97326236793074198 },
1333 .{ 5837045222254987499, 10213498696735864176, 14893951506257020749, 99231769968645227 },
1334};
1335
1336// Unfortunately, the results are sometimes off by one or two. We use an additional
1337// lookup table to store those cases and adjust the result.
1338const FLOAT128_POW5_ERRORS: [156]u64 = .{
1339 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x9555596400000000,
1340 0x65a6569525565555, 0x4415551445449655, 0x5105015504144541, 0x65a69969a6965964,
1341 0x5054955969959656, 0x5105154515554145, 0x4055511051591555, 0x5500514455550115,
1342 0x0041140014145515, 0x1005440545511051, 0x0014405450411004, 0x0414440010500000,
1343 0x0044000440010040, 0x5551155000004001, 0x4554555454544114, 0x5150045544005441,
1344 0x0001111400054501, 0x6550955555554554, 0x1504159645559559, 0x4105055141454545,
1345 0x1411541410405454, 0x0415555044545555, 0x0014154115405550, 0x1540055040411445,
1346 0x0000000500000000, 0x5644000000000000, 0x1155555591596555, 0x0410440054569565,
1347 0x5145100010010005, 0x0555041405500150, 0x4141450455140450, 0x0000000144000140,
1348 0x5114004001105410, 0x4444100404005504, 0x0414014410001015, 0x5145055155555015,
1349 0x0141041444445540, 0x0000100451541414, 0x4105041104155550, 0x0500501150451145,
1350 0x1001050000004114, 0x5551504400141045, 0x5110545410151454, 0x0100001400004040,
1351 0x5040010111040000, 0x0140000150541100, 0x4400140400104110, 0x5011014405545004,
1352 0x0000000044155440, 0x0000000010000000, 0x1100401444440001, 0x0040401010055111,
1353 0x5155155551405454, 0x0444440015514411, 0x0054505054014101, 0x0451015441115511,
1354 0x1541411401140551, 0x4155104514445110, 0x4141145450145515, 0x5451445055155050,
1355 0x4400515554110054, 0x5111145104501151, 0x565a655455500501, 0x5565555555525955,
1356 0x0550511500405695, 0x4415504051054544, 0x6555595965555554, 0x0100915915555655,
1357 0x5540001510001001, 0x5450051414000544, 0x1405010555555551, 0x5555515555644155,
1358 0x5555055595496555, 0x5451045004415000, 0x5450510144040144, 0x5554155555556455,
1359 0x5051555495415555, 0x5555554555555545, 0x0000000010005455, 0x4000005000040000,
1360 0x5565555555555954, 0x5554559555555505, 0x9645545495552555, 0x4000400055955564,
1361 0x0040000000000001, 0x4004100100000000, 0x5540040440000411, 0x4565555955545644,
1362 0x1140659549651556, 0x0100000410010000, 0x5555515400004001, 0x5955545555155255,
1363 0x5151055545505556, 0x5051454510554515, 0x0501500050415554, 0x5044154005441005,
1364 0x1455445450550455, 0x0010144055144545, 0x0000401100000004, 0x1050145050000010,
1365 0x0415004554011540, 0x1000510100151150, 0x0100040400001144, 0x0000000000000000,
1366 0x0550004400000100, 0x0151145041451151, 0x0000400400005450, 0x0000100044010004,
1367 0x0100054100050040, 0x0504400005410010, 0x4011410445500105, 0x0000404000144411,
1368 0x0101504404500000, 0x0000005044400400, 0x0000000014000100, 0x0404440414000000,
1369 0x5554100410000140, 0x4555455544505555, 0x5454105055455455, 0x0115454155454015,
1370 0x4404110000045100, 0x4400001100101501, 0x6596955956966a94, 0x0040655955665965,
1371 0x5554144400100155, 0xa549495401011041, 0x5596555565955555, 0x5569965959549555,
1372 0x969565a655555456, 0x0000001000000000, 0x0000000040000140, 0x0000040100000000,
1373 0x1415454400000000, 0x5410415411454114, 0x0400040104000154, 0x0504045000000411,
1374 0x0000001000000010, 0x5554000000001040, 0x5549155551556595, 0x1455541055515555,
1375 0x0510555454554541, 0x9555555555540455, 0x6455456555556465, 0x4524565555654514,
1376 0x5554655255559545, 0x9555455441155556, 0x0000000051515555, 0x0010005040000550,
1377 0x5044044040000000, 0x1045040440010500, 0x0000400000040000, 0x0000000000000000,
1378};
1379
1380const FLOAT128_POW5_INV_SPLIT: [89][4]u64 = .{
1381 .{ 0, 0, 0, 144115188075855872 },
1382 .{ 1573859546583440065, 2691002611772552616, 6763753280790178510, 141347765182270746 },
1383 .{ 12960290449513840412, 12345512957918226762, 18057899791198622765, 138633484706040742 },
1384 .{ 7615871757716765416, 9507132263365501332, 4879801712092008245, 135971326161092377 },
1385 .{ 7869961150745287587, 5804035291554591636, 8883897266325833928, 133360288657597085 },
1386 .{ 2942118023529634767, 15128191429820565086, 10638459445243230718, 130799390525667397 },
1387 .{ 14188759758411913794, 5362791266439207815, 8068821289119264054, 128287668946279217 },
1388 .{ 7183196927902545212, 1952291723540117099, 12075928209936341512, 125824179589281448 },
1389 .{ 5672588001402349748, 17892323620748423487, 9874578446960390364, 123407996258356868 },
1390 .{ 4442590541217566325, 4558254706293456445, 10343828952663182727, 121038210542800766 },
1391 .{ 3005560928406962566, 2082271027139057888, 13961184524927245081, 118713931475986426 },
1392 .{ 13299058168408384786, 17834349496131278595, 9029906103900731664, 116434285200389047 },
1393 .{ 5414878118283973035, 13079825470227392078, 17897304791683760280, 114198414639042157 },
1394 .{ 14609755883382484834, 14991702445765844156, 3269802549772755411, 112005479173303009 },
1395 .{ 15967774957605076027, 2511532636717499923, 16221038267832563171, 109854654326805788 },
1396 .{ 9269330061621627145, 3332501053426257392, 16223281189403734630, 107745131455483836 },
1397 .{ 16739559299223642282, 1873986623300664530, 6546709159471442872, 105676117443544318 },
1398 .{ 17116435360051202055, 1359075105581853924, 2038341371621886470, 103646834405281051 },
1399 .{ 17144715798009627550, 3201623802661132408, 9757551605154622431, 101656519392613377 },
1400 .{ 17580479792687825857, 6546633380567327312, 15099972427870912398, 99704424108241124 },
1401 .{ 9726477118325522902, 14578369026754005435, 11728055595254428803, 97789814624307808 },
1402 .{ 134593949518343635, 5715151379816901985, 1660163707976377376, 95911971106466306 },
1403 .{ 5515914027713859358, 7124354893273815720, 5548463282858794077, 94070187543243255 },
1404 .{ 6188403395862945512, 5681264392632320838, 15417410852121406654, 92263771480600430 },
1405 .{ 15908890877468271457, 10398888261125597540, 4817794962769172309, 90492043761593298 },
1406 .{ 1413077535082201005, 12675058125384151580, 7731426132303759597, 88754338271028867 },
1407 .{ 1486733163972670293, 11369385300195092554, 11610016711694864110, 87050001685026843 },
1408 .{ 8788596583757589684, 3978580923851924802, 9255162428306775812, 85378393225389919 },
1409 .{ 7203518319660962120, 15044736224407683725, 2488132019818199792, 83738884418690858 },
1410 .{ 4004175967662388707, 18236988667757575407, 15613100370957482671, 82130858859985791 },
1411 .{ 18371903370586036463, 53497579022921640, 16465963977267203307, 80553711981064899 },
1412 .{ 10170778323887491315, 1999668801648976001, 10209763593579456445, 79006850823153334 },
1413 .{ 17108131712433974546, 16825784443029944237, 2078700786753338945, 77489693813976938 },
1414 .{ 17221789422665858532, 12145427517550446164, 5391414622238668005, 76001670549108934 },
1415 .{ 4859588996898795878, 1715798948121313204, 3950858167455137171, 74542221577515387 },
1416 .{ 13513469241795711526, 631367850494860526, 10517278915021816160, 73110798191218799 },
1417 .{ 11757513142672073111, 2581974932255022228, 17498959383193606459, 143413724438001539 },
1418 .{ 14524355192525042817, 5640643347559376447, 1309659274756813016, 140659771648132296 },
1419 .{ 2765095348461978538, 11021111021896007722, 3224303603779962366, 137958702611185230 },
1420 .{ 12373410389187981037, 13679193545685856195, 11644609038462631561, 135309501808182158 },
1421 .{ 12813176257562780151, 3754199046160268020, 9954691079802960722, 132711173221007413 },
1422 .{ 17557452279667723458, 3237799193992485824, 17893947919029030695, 130162739957935629 },
1423 .{ 14634200999559435155, 4123869946105211004, 6955301747350769239, 127663243886350468 },
1424 .{ 2185352760627740240, 2864813346878886844, 13049218671329690184, 125211745272516185 },
1425 .{ 6143438674322183002, 10464733336980678750, 6982925169933978309, 122807322428266620 },
1426 .{ 1099509117817174576, 10202656147550524081, 754997032816608484, 120449071364478757 },
1427 .{ 2410631293559367023, 17407273750261453804, 15307291918933463037, 118136105451200587 },
1428 .{ 12224968375134586697, 1664436604907828062, 11506086230137787358, 115867555084305488 },
1429 .{ 3495926216898000888, 18392536965197424288, 10992889188570643156, 113642567358547782 },
1430 .{ 8744506286256259680, 3966568369496879937, 18342264969761820037, 111460305746896569 },
1431 .{ 7689600520560455039, 5254331190877624630, 9628558080573245556, 109319949786027263 },
1432 .{ 11862637625618819436, 3456120362318976488, 14690471063106001082, 107220694767852583 },
1433 .{ 5697330450030126444, 12424082405392918899, 358204170751754904, 105161751436977040 },
1434 .{ 11257457505097373622, 15373192700214208870, 671619062372033814, 103142345693961148 },
1435 .{ 16850355018477166700, 1913910419361963966, 4550257919755970531, 101161718304283822 },
1436 .{ 9670835567561997011, 10584031339132130638, 3060560222974851757, 99219124612893520 },
1437 .{ 7698686577353054710, 11689292838639130817, 11806331021588878241, 97313834264240819 },
1438 .{ 12233569599615692137, 3347791226108469959, 10333904326094451110, 95445130927687169 },
1439 .{ 13049400362825383933, 17142621313007799680, 3790542585289224168, 93612312028186576 },
1440 .{ 12430457242474442072, 5625077542189557960, 14765055286236672238, 91814688482138969 },
1441 .{ 4759444137752473128, 2230562561567025078, 4954443037339580076, 90051584438315940 },
1442 .{ 7246913525170274758, 8910297835195760709, 4015904029508858381, 88322337023761438 },
1443 .{ 12854430245836432067, 8135139748065431455, 11548083631386317976, 86626296094571907 },
1444 .{ 4848827254502687803, 4789491250196085625, 3988192420450664125, 84962823991462151 },
1445 .{ 7435538409611286684, 904061756819742353, 14598026519493048444, 83331295300025028 },
1446 .{ 11042616160352530997, 8948390828345326218, 10052651191118271927, 81731096615594853 },
1447 .{ 11059348291563778943, 11696515766184685544, 3783210511290897367, 80161626312626082 },
1448 .{ 7020010856491885826, 5025093219346041680, 8960210401638911765, 78622294318500592 },
1449 .{ 17732844474490699984, 7820866704994446502, 6088373186798844243, 77112521891678506 },
1450 .{ 688278527545590501, 3045610706602776618, 8684243536999567610, 75631741404109150 },
1451 .{ 2734573255120657297, 3903146411440697663, 9470794821691856713, 74179396127820347 },
1452 .{ 15996457521023071259, 4776627823451271680, 12394856457265744744, 72754940025605801 },
1453 .{ 13492065758834518331, 7390517611012222399, 1630485387832860230, 142715675091463768 },
1454 .{ 13665021627282055864, 9897834675523659302, 17907668136755296849, 139975126841173266 },
1455 .{ 9603773719399446181, 10771916301484339398, 10672699855989487527, 137287204938390542 },
1456 .{ 3630218541553511265, 8139010004241080614, 2876479648932814543, 134650898807055963 },
1457 .{ 8318835909686377084, 9525369258927993371, 2796120270400437057, 132065217277054270 },
1458 .{ 11190003059043290163, 12424345635599592110, 12539346395388933763, 129529188211565064 },
1459 .{ 8701968833973242276, 820569587086330727, 2315591597351480110, 127041858141569228 },
1460 .{ 5115113890115690487, 16906305245394587826, 9899749468931071388, 124602291907373862 },
1461 .{ 15543535488939245974, 10945189844466391399, 3553863472349432246, 122209572307020975 },
1462 .{ 7709257252608325038, 1191832167690640880, 15077137020234258537, 119862799751447719 },
1463 .{ 7541333244210021737, 9790054727902174575, 5160944773155322014, 117561091926268545 },
1464 .{ 12297384708782857832, 1281328873123467374, 4827925254630475769, 115303583460052092 },
1465 .{ 13243237906232367265, 15873887428139547641, 3607993172301799599, 113089425598968120 },
1466 .{ 11384616453739611114, 15184114243769211033, 13148448124803481057, 110917785887682141 },
1467 .{ 17727970963596660683, 1196965221832671990, 14537830463956404138, 108787847856377790 },
1468 .{ 17241367586707330931, 8880584684128262874, 11173506540726547818, 106698810713789254 },
1469 .{ 7184427196661305643, 14332510582433188173, 14230167953789677901, 104649889046128358 },
1470};
1471
1472const FLOAT128_POW5_INV_ERRORS: [154]u64 = .{
1473 0x1144155514145504, 0x0000541555401141, 0x0000000000000000, 0x0154454000000000,
1474 0x4114105515544440, 0x0001001111500415, 0x4041411410011000, 0x5550114515155014,
1475 0x1404100041554551, 0x0515000450404410, 0x5054544401140004, 0x5155501005555105,
1476 0x1144141000105515, 0x0541500000500000, 0x1104105540444140, 0x4000015055514110,
1477 0x0054010450004005, 0x4155515404100005, 0x5155145045155555, 0x1511555515440558,
1478 0x5558544555515555, 0x0000000000000010, 0x5004000000000050, 0x1415510100000010,
1479 0x4545555444514500, 0x5155151555555551, 0x1441540144044554, 0x5150104045544400,
1480 0x5450545401444040, 0x5554455045501400, 0x4655155555555145, 0x1000010055455055,
1481 0x1000004000055004, 0x4455405104000005, 0x4500114504150545, 0x0000000014000000,
1482 0x5450000000000000, 0x5514551511445555, 0x4111501040555451, 0x4515445500054444,
1483 0x5101500104100441, 0x1545115155545055, 0x0000000000000000, 0x1554000000100000,
1484 0x5555545595551555, 0x5555051851455955, 0x5555555555555559, 0x0000400011001555,
1485 0x0000004400040000, 0x5455511555554554, 0x5614555544115445, 0x6455156145555155,
1486 0x5455855455415455, 0x5515555144555545, 0x0114400000145155, 0x0000051000450511,
1487 0x4455154554445100, 0x4554150141544455, 0x65955555559a5965, 0x5555555854559559,
1488 0x9569654559616595, 0x1040044040005565, 0x1010010500011044, 0x1554015545154540,
1489 0x4440555401545441, 0x1014441450550105, 0x4545400410504145, 0x5015111541040151,
1490 0x5145051154000410, 0x1040001044545044, 0x4001400000151410, 0x0540000044040000,
1491 0x0510555454411544, 0x0400054054141550, 0x1001041145001100, 0x0000000140000000,
1492 0x0000000014100000, 0x1544005454000140, 0x4050055505445145, 0x0011511104504155,
1493 0x5505544415045055, 0x1155154445515554, 0x0000000000004555, 0x0000000000000000,
1494 0x5101010510400004, 0x1514045044440400, 0x5515519555515555, 0x4554545441555545,
1495 0x1551055955551515, 0x0150000011505515, 0x0044005040400000, 0x0004001004010050,
1496 0x0000051004450414, 0x0114001101001144, 0x0401000001000001, 0x4500010001000401,
1497 0x0004100000005000, 0x0105000441101100, 0x0455455550454540, 0x5404050144105505,
1498 0x4101510540555455, 0x1055541411451555, 0x5451445110115505, 0x1154110010101545,
1499 0x1145140450054055, 0x5555565415551554, 0x1550559555555555, 0x5555541545045141,
1500 0x4555455450500100, 0x5510454545554555, 0x1510140115045455, 0x1001050040111510,
1501 0x5555454555555504, 0x9954155545515554, 0x6596656555555555, 0x0140410051555559,
1502 0x0011104010001544, 0x965669659a680501, 0x5655a55955556955, 0x4015111014404514,
1503 0x1414155554505145, 0x0540040011051404, 0x1010000000015005, 0x0010054050004410,
1504 0x5041104014000100, 0x4440010500100001, 0x1155510504545554, 0x0450151545115541,
1505 0x4000100400110440, 0x1004440010514440, 0x0000115050450000, 0x0545404455541500,
1506 0x1051051555505101, 0x5505144554544144, 0x4550545555515550, 0x0015400450045445,
1507 0x4514155400554415, 0x4555055051050151, 0x1511441450001014, 0x4544554510404414,
1508 0x4115115545545450, 0x5500541555551555, 0x5550010544155015, 0x0144414045545500,
1509 0x4154050001050150, 0x5550511111000145, 0x1114504055000151, 0x5104041101451040,
1510 0x0010501401051441, 0x0010501450504401, 0x4554585440044444, 0x5155555951450455,
1511 0x0040000400105555, 0x0000000000000001,
1512};
1513
1514// zig fmt: on
1515
1516const builtin = @import("builtin");
1517
1518fn check(comptime T: type, value: T, comptime expected: []const u8) !void {
1519 const I = @Type(.{ .int = .{ .signedness = .unsigned, .bits = @bitSizeOf(T) } });
1520
1521 var buf: [6000]u8 = undefined;
1522 const value_bits: I = @bitCast(value);
1523 const s = try formatFloat(&buf, value, .{});
1524 try std.testing.expectEqualStrings(expected, s);
1525
1526 if (T == f80 and builtin.target.os.tag == .windows and builtin.target.cpu.arch == .x86_64) return;
1527
1528 const o = try std.fmt.parseFloat(T, s);
1529 const o_bits: I = @bitCast(o);
1530
1531 if (std.math.isNan(value)) {
1532 try std.testing.expect(std.math.isNan(o));
1533 } else {
1534 try std.testing.expectEqual(value_bits, o_bits);
1535 }
1536}
1537
1538test "format f32" {
1539 try check(f32, 0.0, "0e0");
1540 try check(f32, -0.0, "-0e0");
1541 try check(f32, 1.0, "1e0");
1542 try check(f32, -1.0, "-1e0");
1543 try check(f32, std.math.nan(f32), "nan");
1544 try check(f32, std.math.inf(f32), "inf");
1545 try check(f32, -std.math.inf(f32), "-inf");
1546 try check(f32, 1.1754944e-38, "1.1754944e-38");
1547 try check(f32, @bitCast(@as(u32, 0x7f7fffff)), "3.4028235e38");
1548 try check(f32, @bitCast(@as(u32, 1)), "1e-45");
1549 try check(f32, 3.355445E7, "3.355445e7");
1550 try check(f32, 8.999999e9, "9e9");
1551 try check(f32, 3.4366717e10, "3.436672e10");
1552 try check(f32, 3.0540412e5, "3.0540412e5");
1553 try check(f32, 8.0990312e3, "8.0990312e3");
1554 try check(f32, 2.4414062e-4, "2.4414062e-4");
1555 try check(f32, 2.4414062e-3, "2.4414062e-3");
1556 try check(f32, 4.3945312e-3, "4.3945312e-3");
1557 try check(f32, 6.3476562e-3, "6.3476562e-3");
1558 try check(f32, 4.7223665e21, "4.7223665e21");
1559 try check(f32, 8388608.0, "8.388608e6");
1560 try check(f32, 1.6777216e7, "1.6777216e7");
1561 try check(f32, 3.3554436e7, "3.3554436e7");
1562 try check(f32, 6.7131496e7, "6.7131496e7");
1563 try check(f32, 1.9310392e-38, "1.9310392e-38");
1564 try check(f32, -2.47e-43, "-2.47e-43");
1565 try check(f32, 1.993244e-38, "1.993244e-38");
1566 try check(f32, 4103.9003, "4.1039004e3");
1567 try check(f32, 5.3399997e9, "5.3399997e9");
1568 try check(f32, 6.0898e-39, "6.0898e-39");
1569 try check(f32, 0.0010310042, "1.0310042e-3");
1570 try check(f32, 2.8823261e17, "2.882326e17");
1571 try check(f32, 7.038531e-26, "7.038531e-26");
1572 try check(f32, 9.2234038e17, "9.223404e17");
1573 try check(f32, 6.7108872e7, "6.710887e7");
1574 try check(f32, 1.0e-44, "1e-44");
1575 try check(f32, 2.816025e14, "2.816025e14");
1576 try check(f32, 9.223372e18, "9.223372e18");
1577 try check(f32, 1.5846085e29, "1.5846086e29");
1578 try check(f32, 1.1811161e19, "1.1811161e19");
1579 try check(f32, 5.368709e18, "5.368709e18");
1580 try check(f32, 4.6143165e18, "4.6143166e18");
1581 try check(f32, 0.007812537, "7.812537e-3");
1582 try check(f32, 1.4e-45, "1e-45");
1583 try check(f32, 1.18697724e20, "1.18697725e20");
1584 try check(f32, 1.00014165e-36, "1.00014165e-36");
1585 try check(f32, 200.0, "2e2");
1586 try check(f32, 3.3554432e7, "3.3554432e7");
1587
1588 try check(f32, 1.0, "1e0");
1589 try check(f32, 1.2, "1.2e0");
1590 try check(f32, 1.23, "1.23e0");
1591 try check(f32, 1.234, "1.234e0");
1592 try check(f32, 1.2345, "1.2345e0");
1593 try check(f32, 1.23456, "1.23456e0");
1594 try check(f32, 1.234567, "1.234567e0");
1595 try check(f32, 1.2345678, "1.2345678e0");
1596 try check(f32, 1.23456735e-36, "1.23456735e-36");
1597}
1598
1599test "format f64" {
1600 try check(f64, 0.0, "0e0");
1601 try check(f64, -0.0, "-0e0");
1602 try check(f64, 1.0, "1e0");
1603 try check(f64, -1.0, "-1e0");
1604 try check(f64, std.math.nan(f64), "nan");
1605 try check(f64, std.math.inf(f64), "inf");
1606 try check(f64, -std.math.inf(f64), "-inf");
1607 try check(f64, 2.2250738585072014e-308, "2.2250738585072014e-308");
1608 try check(f64, @bitCast(@as(u64, 0x7fefffffffffffff)), "1.7976931348623157e308");
1609 try check(f64, @bitCast(@as(u64, 1)), "5e-324");
1610 try check(f64, 2.98023223876953125e-8, "2.9802322387695312e-8");
1611 try check(f64, -2.109808898695963e16, "-2.109808898695963e16");
1612 try check(f64, 4.940656e-318, "4.940656e-318");
1613 try check(f64, 1.18575755e-316, "1.18575755e-316");
1614 try check(f64, 2.989102097996e-312, "2.989102097996e-312");
1615 try check(f64, 9.0608011534336e15, "9.0608011534336e15");
1616 try check(f64, 4.708356024711512e18, "4.708356024711512e18");
1617 try check(f64, 9.409340012568248e18, "9.409340012568248e18");
1618 try check(f64, 1.2345678, "1.2345678e0");
1619 try check(f64, @bitCast(@as(u64, 0x4830f0cf064dd592)), "5.764607523034235e39");
1620 try check(f64, @bitCast(@as(u64, 0x4840f0cf064dd592)), "1.152921504606847e40");
1621 try check(f64, @bitCast(@as(u64, 0x4850f0cf064dd592)), "2.305843009213694e40");
1622
1623 try check(f64, 1, "1e0");
1624 try check(f64, 1.2, "1.2e0");
1625 try check(f64, 1.23, "1.23e0");
1626 try check(f64, 1.234, "1.234e0");
1627 try check(f64, 1.2345, "1.2345e0");
1628 try check(f64, 1.23456, "1.23456e0");
1629 try check(f64, 1.234567, "1.234567e0");
1630 try check(f64, 1.2345678, "1.2345678e0");
1631 try check(f64, 1.23456789, "1.23456789e0");
1632 try check(f64, 1.234567895, "1.234567895e0");
1633 try check(f64, 1.2345678901, "1.2345678901e0");
1634 try check(f64, 1.23456789012, "1.23456789012e0");
1635 try check(f64, 1.234567890123, "1.234567890123e0");
1636 try check(f64, 1.2345678901234, "1.2345678901234e0");
1637 try check(f64, 1.23456789012345, "1.23456789012345e0");
1638 try check(f64, 1.234567890123456, "1.234567890123456e0");
1639 try check(f64, 1.2345678901234567, "1.2345678901234567e0");
1640
1641 try check(f64, 4.294967294, "4.294967294e0");
1642 try check(f64, 4.294967295, "4.294967295e0");
1643 try check(f64, 4.294967296, "4.294967296e0");
1644 try check(f64, 4.294967297, "4.294967297e0");
1645 try check(f64, 4.294967298, "4.294967298e0");
1646}
1647
1648test "format f80" {
1649 try check(f80, 0.0, "0e0");
1650 try check(f80, -0.0, "-0e0");
1651 try check(f80, 1.0, "1e0");
1652 try check(f80, -1.0, "-1e0");
1653 try check(f80, std.math.nan(f80), "nan");
1654 try check(f80, std.math.inf(f80), "inf");
1655 try check(f80, -std.math.inf(f80), "-inf");
1656
1657 try check(f80, 2.2250738585072014e-308, "2.2250738585072014e-308");
1658 try check(f80, 2.98023223876953125e-8, "2.98023223876953125e-8");
1659 try check(f80, -2.109808898695963e16, "-2.109808898695963e16");
1660 try check(f80, 4.940656e-318, "4.940656e-318");
1661 try check(f80, 1.18575755e-316, "1.18575755e-316");
1662 try check(f80, 2.989102097996e-312, "2.989102097996e-312");
1663 try check(f80, 9.0608011534336e15, "9.0608011534336e15");
1664 try check(f80, 4.708356024711512e18, "4.708356024711512e18");
1665 try check(f80, 9.409340012568248e18, "9.409340012568248e18");
1666 try check(f80, 1.2345678, "1.2345678e0");
1667}
1668
1669test "format f128" {
1670 try check(f128, 0.0, "0e0");
1671 try check(f128, -0.0, "-0e0");
1672 try check(f128, 1.0, "1e0");
1673 try check(f128, -1.0, "-1e0");
1674 try check(f128, std.math.nan(f128), "nan");
1675 try check(f128, std.math.inf(f128), "inf");
1676 try check(f128, -std.math.inf(f128), "-inf");
1677
1678 try check(f128, 2.2250738585072014e-308, "2.2250738585072014e-308");
1679 try check(f128, 2.98023223876953125e-8, "2.98023223876953125e-8");
1680 try check(f128, -2.109808898695963e16, "-2.109808898695963e16");
1681 try check(f128, 4.940656e-318, "4.940656e-318");
1682 try check(f128, 1.18575755e-316, "1.18575755e-316");
1683 try check(f128, 2.989102097996e-312, "2.989102097996e-312");
1684 try check(f128, 9.0608011534336e15, "9.0608011534336e15");
1685 try check(f128, 4.708356024711512e18, "4.708356024711512e18");
1686 try check(f128, 9.409340012568248e18, "9.409340012568248e18");
1687 try check(f128, 1.2345678, "1.2345678e0");
1688}
1689
1690test "format float to decimal with zero precision" {
1691 try expectFmt("5", "{d:.0}", .{5});
1692 try expectFmt("6", "{d:.0}", .{6});
1693 try expectFmt("7", "{d:.0}", .{7});
1694 try expectFmt("8", "{d:.0}", .{8});
1695}
lib/std/fs/File.zig+103-3
......@@ -1587,12 +1587,112 @@ pub fn reader(file: File) Reader {
15871587 return .{ .context = file };
15881588}
15891589
1590pub const Writer = io.Writer(File, WriteError, write);
1590pub fn writer(file: File) std.io.Writer {
1591 return .{
1592 .context = interface.handleToOpaque(file.handle),
1593 .vtable = &.{
1594 .writev = interface.writev,
1595 .writeFile = interface.writeFile,
1596 },
1597 };
1598}
15911599
1592pub fn writer(file: File) Writer {
1593 return .{ .context = file };
1600pub fn unbufferedWriter(file: File) std.io.BufferedWriter {
1601 return .{
1602 .buffer = &.{},
1603 .unbuffered_writer = writer(file),
1604 };
15941605}
15951606
1607const interface = struct {
1608 /// Number of slices to store on the stack, when trying to send as many byte
1609 /// vectors through the underlying write calls as possible.
1610 const max_buffers_len = 16;
1611
1612 fn writev(context: *anyopaque, data: []const []const u8) anyerror!usize {
1613 const file = opaqueToHandle(context);
1614
1615 if (is_windows) {
1616 // TODO improve this to use WriteFileScatter
1617 if (data.len == 0) return 0;
1618 const first = data[0];
1619 return windows.WriteFile(file, first.base[0..first.len], null);
1620 }
1621
1622 var iovecs_buffer: [max_buffers_len]std.posix.iovec_const = undefined;
1623 const iovecs = iovecs_buffer[0..@min(iovecs_buffer.len, data.len)];
1624 for (iovecs, data[0..iovecs.len]) |*v, d| v.* = .{ .base = d.ptr, .len = d.len };
1625 return std.posix.writev(file, iovecs);
1626 }
1627
1628 fn writeFile(
1629 context: *anyopaque,
1630 in_file: std.fs.File,
1631 in_offset: u64,
1632 in_len: std.io.Writer.VTable.FileLen,
1633 headers_and_trailers: []const []const u8,
1634 headers_len: usize,
1635 ) anyerror!usize {
1636 const out_fd = opaqueToHandle(context);
1637 const in_fd = in_file.handle;
1638 const len_int = switch (in_len) {
1639 .zero => return interface.writev(context, headers_and_trailers),
1640 .entire_file => 0,
1641 else => in_len.int(),
1642 };
1643 var iovecs_buffer: [max_buffers_len]std.posix.iovec_const = undefined;
1644 const iovecs = iovecs_buffer[0..@min(iovecs_buffer.len, headers_and_trailers.len)];
1645 for (iovecs, headers_and_trailers[0..iovecs.len]) |*v, d| v.* = .{ .base = d.ptr, .len = d.len };
1646 const headers = iovecs[0..@min(headers_len, iovecs.len)];
1647 const trailers = iovecs[headers.len..];
1648 const flags = 0;
1649 return posix.sendfile(out_fd, in_fd, in_offset, len_int, headers, trailers, flags) catch |err| switch (err) {
1650 error.Unseekable,
1651 error.FastOpenAlreadyInProgress,
1652 error.MessageTooBig,
1653 error.FileDescriptorNotASocket,
1654 error.NetworkUnreachable,
1655 error.NetworkSubsystemFailed,
1656 => return writeFileUnseekable(out_fd, in_fd, in_offset, in_len, headers_and_trailers, headers_len),
1657
1658 else => |e| return e,
1659 };
1660 }
1661
1662 fn writeFileUnseekable(
1663 out_fd: Handle,
1664 in_fd: Handle,
1665 in_offset: u64,
1666 in_len: std.io.Writer.VTable.FileLen,
1667 headers_and_trailers: []const []const u8,
1668 headers_len: usize,
1669 ) anyerror!usize {
1670 _ = out_fd;
1671 _ = in_fd;
1672 _ = in_offset;
1673 _ = in_len;
1674 _ = headers_and_trailers;
1675 _ = headers_len;
1676 @panic("TODO writeFileUnseekable");
1677 }
1678
1679 fn handleToOpaque(handle: File.Handle) *anyopaque {
1680 return switch (@typeInfo(Handle)) {
1681 .pointer => @ptrCast(handle),
1682 .int => @ptrFromInt(@as(u32, @bitCast(handle))),
1683 else => @compileError("unhandled"),
1684 };
1685 }
1686
1687 fn opaqueToHandle(userdata: *anyopaque) Handle {
1688 return switch (@typeInfo(Handle)) {
1689 .pointer => @ptrCast(userdata),
1690 .int => @intCast(@intFromPtr(userdata)),
1691 else => @compileError("unhandled"),
1692 };
1693 }
1694};
1695
15961696pub const SeekableStream = io.SeekableStream(
15971697 File,
15981698 SeekError,
lib/std/io.zig+42-22
......@@ -336,7 +336,7 @@ pub fn GenericWriter(
336336 return @errorCast(self.any().writeStructEndian(value, endian));
337337 }
338338
339 pub inline fn any(self: *const Self) AnyWriter {
339 pub inline fn any(self: *const Self) Writer {
340340 return .{
341341 .context = @ptrCast(&self.context),
342342 .writeFn = typeErasedWriteFn,
......@@ -351,26 +351,23 @@ pub fn GenericWriter(
351351}
352352
353353/// Deprecated; consider switching to `AnyReader` or use `GenericReader`
354/// to use previous API.
354/// to use previous API. To be removed after 0.14.0 is tagged.
355355pub const Reader = GenericReader;
356/// Deprecated; consider switching to `AnyWriter` or use `GenericWriter`
357/// to use previous API.
358pub const Writer = GenericWriter;
356pub const Writer = @import("io/Writer.zig");
359357
360358pub const AnyReader = @import("io/Reader.zig");
361pub const AnyWriter = @import("io/Writer.zig");
359/// Deprecated; to be removed after 0.14.0 is tagged.
360pub const AnyWriter = Writer;
362361
363362pub const SeekableStream = @import("io/seekable_stream.zig").SeekableStream;
364363
365pub const BufferedWriter = @import("io/buffered_writer.zig").BufferedWriter;
366pub const bufferedWriter = @import("io/buffered_writer.zig").bufferedWriter;
364pub const BufferedWriter = @import("io/BufferedWriter.zig");
367365
368366pub const BufferedReader = @import("io/buffered_reader.zig").BufferedReader;
369367pub const bufferedReader = @import("io/buffered_reader.zig").bufferedReader;
370368pub const bufferedReaderSize = @import("io/buffered_reader.zig").bufferedReaderSize;
371369
372pub const FixedBufferStream = @import("io/fixed_buffer_stream.zig").FixedBufferStream;
373pub const fixedBufferStream = @import("io/fixed_buffer_stream.zig").fixedBufferStream;
370pub const FixedBufferStream = @import("io/FixedBufferStream.zig");
374371
375372pub const CWriter = @import("io/c_writer.zig").CWriter;
376373pub const cWriter = @import("io/c_writer.zig").cWriter;
......@@ -378,8 +375,7 @@ pub const cWriter = @import("io/c_writer.zig").cWriter;
378375pub const LimitedReader = @import("io/limited_reader.zig").LimitedReader;
379376pub const limitedReader = @import("io/limited_reader.zig").limitedReader;
380377
381pub const CountingWriter = @import("io/counting_writer.zig").CountingWriter;
382pub const countingWriter = @import("io/counting_writer.zig").countingWriter;
378pub const CountingWriter = @import("io/CountingWriter.zig");
383379pub const CountingReader = @import("io/counting_reader.zig").CountingReader;
384380pub const countingReader = @import("io/counting_reader.zig").countingReader;
385381
......@@ -404,17 +400,42 @@ pub const StreamSource = @import("io/stream_source.zig").StreamSource;
404400
405401pub const tty = @import("io/tty.zig");
406402
407/// A Writer that doesn't write to anything.
408pub const null_writer: NullWriter = .{ .context = {} };
403/// A `Writer` that discards all data.
404pub const null_writer: Writer = .{
405 .context = undefined,
406 .vtable = &.{
407 .writev = null_writev,
408 .writeFile = null_writeFile,
409 },
410};
409411
410pub const NullWriter = Writer(void, error{}, dummyWrite);
411fn dummyWrite(context: void, data: []const u8) error{}!usize {
412fn null_writev(context: *anyopaque, data: []const []const u8) anyerror!usize {
412413 _ = context;
413 return data.len;
414 var n: usize = 0;
415 for (data) |bytes| n += bytes.len;
416 return n;
417}
418
419fn null_writeFile(
420 context: *anyopaque,
421 file: std.fs.File,
422 offset: u64,
423 len: Writer.VTable.FileLen,
424 headers_and_trailers: []const []const u8,
425 headers_len: usize,
426) anyerror!usize {
427 _ = context;
428 _ = offset;
429 _ = headers_len;
430 _ = file;
431 if (len == .entire_file) return error.Unimplemented;
432 var n: usize = 0;
433 for (headers_and_trailers) |bytes| n += bytes.len;
434 return len.int() + n;
414435}
415436
416437test null_writer {
417 null_writer.writeAll("yay" ** 10) catch |err| switch (err) {};
438 try null_writer.writeAll("yay");
418439}
419440
420441pub fn poll(
......@@ -820,16 +841,15 @@ pub fn PollFiles(comptime StreamEnum: type) type {
820841
821842test {
822843 _ = AnyReader;
823 _ = AnyWriter;
844 _ = Writer;
845 _ = CountingWriter;
846 _ = FixedBufferStream;
824847 _ = @import("io/bit_reader.zig");
825848 _ = @import("io/bit_writer.zig");
826849 _ = @import("io/buffered_atomic_file.zig");
827850 _ = @import("io/buffered_reader.zig");
828 _ = @import("io/buffered_writer.zig");
829851 _ = @import("io/c_writer.zig");
830 _ = @import("io/counting_writer.zig");
831852 _ = @import("io/counting_reader.zig");
832 _ = @import("io/fixed_buffer_stream.zig");
833853 _ = @import("io/seekable_stream.zig");
834854 _ = @import("io/stream_source.zig");
835855 _ = @import("io/test.zig");
lib/std/io/BufferedWriter.zig created+1494
......@@ -0,0 +1,1494 @@
1const std = @import("../std.zig");
2const BufferedWriter = @This();
3const assert = std.debug.assert;
4const native_endian = @import("builtin").target.cpu.arch.endian();
5const Writer = std.io.Writer;
6const testing = std.testing;
7
8/// Underlying stream to send bytes to.
9unbuffered_writer: Writer,
10/// User-provided storage that must outlive this `BufferedWriter`.
11///
12/// If this has length zero, the writer is unbuffered, and `flush` is a no-op.
13buffer: []u8,
14/// Marks the end of `buffer` - before this are buffered bytes, after this is
15/// undefined.
16end: usize = 0,
17
18/// Number of slices to store on the stack, when trying to send as many byte
19/// vectors through the underlying write calls as possible.
20pub const max_buffers_len = 8;
21
22const passthru_vtable: Writer.VTable = .{
23 .writev = passthru_writev,
24 .writeFile = passthru_writeFile,
25};
26
27const fixed_vtable: Writer.VTable = .{
28 .writev = fixed_writev,
29 .writeFile = fixed_writeFile,
30};
31
32pub fn writer(bw: *BufferedWriter) Writer {
33 return .{
34 .context = bw,
35 .vtable = &passthru_vtable,
36 };
37}
38
39/// Replaces the `BufferedWriter` with a new one that writes to `buffer` and
40/// returns `error.NoSpaceLeft` when it is full.
41pub fn initFixed(bw: *BufferedWriter, buffer: []u8) void {
42 bw.* = .{
43 .unbuffered_writer = .{
44 .context = bw,
45 .vtable = &fixed_vtable,
46 },
47 .buffer = buffer,
48 };
49}
50
51/// This function is available when using `initFixed`.
52pub fn getWritten(bw: *const BufferedWriter) []u8 {
53 assert(bw.unbuffered_writer.vtable == &fixed_vtable);
54 return bw.buffer[0..bw.end];
55}
56
57/// This function is available when using `initFixed`.
58pub fn reset(bw: *BufferedWriter) void {
59 assert(bw.unbuffered_writer.vtable == &fixed_vtable);
60 bw.end = 0;
61}
62
63pub fn flush(bw: *BufferedWriter) anyerror!void {
64 try bw.unbuffered_writer.writeAll(bw.buffer[0..bw.end]);
65 bw.end = 0;
66}
67
68/// The `data` parameter is mutable because this function needs to mutate the
69/// fields in order to handle partial writes from `Writer.VTable.writev`.
70pub fn writevAll(bw: *BufferedWriter, data: []const []const u8) anyerror!void {
71 var i: usize = 0;
72 while (true) {
73 var n = try writev(bw, data[i..]);
74 while (n >= data[i].len) {
75 n -= data[i].len;
76 i += 1;
77 if (i >= data.len) return;
78 }
79 data[i] = data[i][n..];
80 }
81}
82
83pub fn writev(bw: *BufferedWriter, data: []const []const u8) anyerror!usize {
84 return passthru_writev(bw, data);
85}
86
87fn passthru_writev(context: *anyopaque, data: []const []const u8) anyerror!usize {
88 const bw: *BufferedWriter = @alignCast(@ptrCast(context));
89 const buffer = bw.buffer;
90 const start_end = bw.end;
91 var end = bw.end;
92 for (data, 0..) |bytes, i| {
93 const new_end = end + bytes.len;
94 if (new_end <= buffer.len) {
95 @branchHint(.likely);
96 @memcpy(buffer[end..new_end], bytes);
97 end = new_end;
98 continue;
99 }
100 var buffers: [max_buffers_len][]const u8 = undefined;
101 buffers[0] = buffer[0..end];
102 const remaining_data = data[i..];
103 const remaining_buffers = buffers[1..];
104 const len: usize = @min(remaining_data.len, remaining_buffers.len);
105 @memcpy(remaining_buffers[0..len], remaining_data[0..len]);
106 const n = try bw.unbuffered_writer.writev(buffers[0 .. len + 1]);
107 if (n < end) {
108 @branchHint(.unlikely);
109 const remainder = buffer[n..end];
110 std.mem.copyForwards(u8, buffer[0..remainder.len], remainder);
111 bw.end = remainder.len;
112 return end - start_end;
113 }
114 bw.end = 0;
115 return n - start_end;
116 }
117 bw.end = end;
118 return end - start_end;
119}
120
121fn fixed_writev(context: *anyopaque, data: []const []const u8) anyerror!usize {
122 const bw: *BufferedWriter = @alignCast(@ptrCast(context));
123 // When this function is called it means the buffer got full, so it's time
124 // to return an error. However, we still need to make sure all of the
125 // available buffer has been used.
126 const first = data[0];
127 const dest = bw.buffer[bw.end..];
128 @memcpy(dest, first[0..dest.len]);
129 return error.NoSpaceLeft;
130}
131
132pub fn write(bw: *BufferedWriter, bytes: []const u8) anyerror!usize {
133 const buffer = bw.buffer;
134 const end = bw.end;
135 const new_end = end + bytes.len;
136 if (new_end > buffer.len) {
137 var data: [2][]const u8 = .{ buffer[0..end], bytes };
138 const n = try bw.unbuffered_writer.writev(&data);
139 if (n < end) {
140 @branchHint(.unlikely);
141 const remainder = buffer[n..end];
142 std.mem.copyForwards(u8, buffer[0..remainder.len], remainder);
143 bw.end = remainder.len;
144 return 0;
145 }
146 bw.end = 0;
147 return n - end;
148 }
149 @memcpy(buffer[end..new_end], bytes);
150 bw.end = new_end;
151 return bytes.len;
152}
153
154/// This function is provided by the `Writer`, however it is
155/// duplicated here so that `bw` can be passed to `std.fmt.format` directly,
156/// avoiding one indirect function call.
157pub fn writeAll(bw: *BufferedWriter, bytes: []const u8) anyerror!void {
158 var index: usize = 0;
159 while (index < bytes.len) index += try write(bw, bytes[index..]);
160}
161
162pub fn print(bw: *BufferedWriter, comptime format: []const u8, args: anytype) anyerror!void {
163 return std.fmt.format(bw, format, args);
164}
165
166pub fn writeByte(bw: *BufferedWriter, byte: u8) anyerror!void {
167 const buffer = bw.buffer;
168 const end = bw.end;
169 if (end == buffer.len) {
170 @branchHint(.unlikely);
171 var buffers: [2][]const u8 = .{ buffer, &.{byte} };
172 while (true) {
173 const n = try bw.unbuffered_writer.writev(&buffers);
174 if (n == 0) {
175 @branchHint(.unlikely);
176 continue;
177 } else if (n >= buffer.len) {
178 @branchHint(.likely);
179 if (n > buffer.len) {
180 @branchHint(.likely);
181 bw.end = 0;
182 return;
183 } else {
184 buffer[0] = byte;
185 bw.end = 1;
186 return;
187 }
188 }
189 const remainder = buffer[n..];
190 std.mem.copyForwards(u8, buffer[0..remainder.len], remainder);
191 buffer[remainder.len] = byte;
192 bw.end = remainder.len + 1;
193 return;
194 }
195 }
196 buffer[end] = byte;
197 bw.end = end + 1;
198}
199
200/// Writes the same byte many times, performing the underlying write call as
201/// many times as necessary.
202pub fn splatByteAll(bw: *BufferedWriter, byte: u8, n: usize) anyerror!void {
203 var remaining: usize = n;
204 while (remaining > 0) remaining -= try splatByte(bw, byte, remaining);
205}
206
207/// Writes the same byte many times, allowing short writes.
208///
209/// Does maximum of one underlying `Writer.VTable.writev`.
210pub fn splatByte(bw: *BufferedWriter, byte: u8, n: usize) anyerror!usize {
211 const buffer = bw.buffer;
212 const end = bw.end;
213
214 const new_end = end + n;
215 if (new_end <= buffer.len) {
216 @memset(buffer[end..][0..n], byte);
217 bw.end = new_end;
218 return n;
219 }
220
221 if (n <= buffer.len) {
222 const written = try bw.unbuffered_writer.write(buffer[0..end]);
223 if (written < end) {
224 @branchHint(.unlikely);
225 const remainder = buffer[written..end];
226 std.mem.copyForwards(u8, buffer[0..remainder.len], remainder);
227 bw.end = remainder.len;
228 return 0;
229 }
230 @memset(buffer[0..n], byte);
231 bw.end = n;
232 return n;
233 }
234
235 // First try to use only the unused buffer region, to make an attempt for a
236 // single `writev`.
237 const free_space = buffer[end..];
238 var remaining = n - free_space.len;
239 @memset(free_space, byte);
240 var buffers: [max_buffers_len][]const u8 = undefined;
241 buffers[0] = buffer;
242 var buffer_i: usize = 1;
243 while (remaining > free_space.len and buffer_i < buffers.len) {
244 buffers[buffer_i] = free_space;
245 buffer_i += 1;
246 remaining -= free_space.len;
247 }
248 if (remaining > 0 and buffer_i < buffers.len) {
249 buffers[buffer_i] = free_space[0..remaining];
250 buffer_i += 1;
251 const written = try bw.unbuffered_writer.writev(buffers[0..buffer_i]);
252 if (written < end) {
253 @branchHint(.unlikely);
254 const remainder = buffer[written..end];
255 std.mem.copyForwards(u8, buffer[0..remainder.len], remainder);
256 bw.end = remainder.len;
257 return 0;
258 }
259 bw.end = 0;
260 return written - end;
261 }
262
263 const written = try bw.unbuffered_writer.writev(buffers[0..buffer_i]);
264 if (written < end) {
265 @branchHint(.unlikely);
266 const remainder = buffer[written..end];
267 std.mem.copyForwards(u8, buffer[0..remainder.len], remainder);
268 bw.end = remainder.len;
269 return 0;
270 }
271
272 bw.end = 0;
273 return written - end;
274}
275
276/// Writes the same slice many times, performing the underlying write call as
277/// many times as necessary.
278pub fn splatBytesAll(bw: *BufferedWriter, bytes: []const u8, n: usize) anyerror!void {
279 var remaining: usize = n * bytes.len;
280 while (remaining > 0) remaining -= try splatBytes(bw, bytes, remaining);
281}
282
283/// Writes the same slice many times, allowing short writes.
284///
285/// Does maximum of one underlying `Writer.VTable.writev`.
286pub fn splatBytes(bw: *BufferedWriter, bytes: []const u8, n: usize) anyerror!usize {
287 const buffer = bw.buffer;
288 const start_end = bw.end;
289 var end = start_end;
290 var remaining = n;
291 while (remaining > 0 and end + bytes.len <= buffer.len) {
292 @memcpy(buffer[end..][0..bytes.len], bytes);
293 end += bytes.len;
294 remaining -= 1;
295 }
296
297 if (remaining == 0) {
298 bw.end = end;
299 return end - start_end;
300 }
301
302 var buffers: [max_buffers_len][]const u8 = undefined;
303 var buffer_i: usize = 1;
304 buffers[0] = buffer[0..end];
305 const remaining_buffers = buffers[1..];
306 const buffers_len: usize = @min(remaining, remaining_buffers.len);
307 @memset(remaining_buffers[0..buffers_len], bytes);
308 remaining -= buffers_len;
309 buffer_i += buffers_len;
310
311 const written = try bw.unbuffered_writer.writev(buffers[0..buffer_i]);
312 if (written < end) {
313 @branchHint(.unlikely);
314 const remainder = buffer[written..end];
315 std.mem.copyForwards(u8, buffer[0..remainder.len], remainder);
316 bw.end = remainder.len;
317 return end - start_end;
318 }
319 bw.end = 0;
320 return written - start_end;
321}
322
323/// Asserts the `buffer` was initialized with a capacity of at least `@sizeOf(T)` bytes.
324pub inline fn writeInt(bw: *BufferedWriter, comptime T: type, value: T, endian: std.builtin.Endian) anyerror!void {
325 var bytes: [@divExact(@typeInfo(T).int.bits, 8)]u8 = undefined;
326 std.mem.writeInt(std.math.ByteAlignedInt(@TypeOf(value)), &bytes, value, endian);
327 return bw.writeAll(&bytes);
328}
329
330pub fn writeStruct(bw: *BufferedWriter, value: anytype) anyerror!void {
331 // Only extern and packed structs have defined in-memory layout.
332 comptime assert(@typeInfo(@TypeOf(value)).@"struct".layout != .auto);
333 return bw.writeAll(std.mem.asBytes(&value));
334}
335
336pub fn writeStructEndian(bw: *BufferedWriter, value: anytype, endian: std.builtin.Endian) anyerror!void {
337 // TODO: make sure this value is not a reference type
338 if (native_endian == endian) {
339 return bw.writeStruct(value);
340 } else {
341 var copy = value;
342 std.mem.byteSwapAllFields(@TypeOf(value), &copy);
343 return bw.writeStruct(copy);
344 }
345}
346
347pub fn writeFile(
348 bw: *BufferedWriter,
349 file: std.fs.File,
350 offset: u64,
351 len: Writer.VTable.FileLen,
352 headers_and_trailers: []const []const u8,
353 headers_len: usize,
354) anyerror!usize {
355 return passthru_writeFile(bw, file, offset, len, headers_and_trailers, headers_len);
356}
357
358fn passthru_writeFile(
359 context: *anyopaque,
360 file: std.fs.File,
361 offset: u64,
362 len: Writer.VTable.FileLen,
363 headers_and_trailers: []const []const u8,
364 headers_len: usize,
365) anyerror!usize {
366 const bw: *BufferedWriter = @alignCast(@ptrCast(context));
367 const buffer = bw.buffer;
368 const start_end = bw.end;
369 const headers = headers_and_trailers[0..headers_len];
370 const trailers = headers_and_trailers[headers_len..];
371 var buffers: [max_buffers_len][]const u8 = undefined;
372 var end = start_end;
373 for (headers, 0..) |header, i| {
374 const new_end = end + header.len;
375 if (new_end <= buffer.len) {
376 @branchHint(.likely);
377 @memcpy(buffer[end..new_end], header);
378 end = new_end;
379 continue;
380 }
381 buffers[0] = buffer[0..end];
382 const remaining_headers = headers[i..];
383 const remaining_buffers = buffers[1..];
384 const buffers_len: usize = @min(remaining_headers.len, remaining_buffers.len);
385 @memcpy(remaining_buffers[0..buffers_len], remaining_headers[0..buffers_len]);
386 if (buffers_len >= remaining_headers.len) {
387 // Made it past the headers, so we can call `writeFile`.
388 const remaining_buffers_for_trailers = remaining_buffers[buffers_len..];
389 const send_trailers_len: usize = @min(trailers.len, remaining_buffers_for_trailers.len);
390 @memcpy(remaining_buffers_for_trailers[0..send_trailers_len], trailers[0..send_trailers_len]);
391 const send_headers_len = 1 + buffers_len;
392 const send_buffers = buffers[0 .. send_headers_len + send_trailers_len];
393 const n = try bw.unbuffered_writer.writeFile(file, offset, len, send_buffers, send_headers_len);
394 if (n < end) {
395 @branchHint(.unlikely);
396 const remainder = buffer[n..end];
397 std.mem.copyForwards(u8, buffer[0..remainder.len], remainder);
398 bw.end = remainder.len;
399 return end - start_end;
400 }
401 bw.end = 0;
402 return n - start_end;
403 }
404 // Have not made it past the headers yet; must call `writev`.
405 const n = try bw.unbuffered_writer.writev(buffers[0 .. buffers_len + 1]);
406 if (n < end) {
407 @branchHint(.unlikely);
408 const remainder = buffer[n..end];
409 std.mem.copyForwards(u8, buffer[0..remainder.len], remainder);
410 bw.end = remainder.len;
411 return end - start_end;
412 }
413 bw.end = 0;
414 return n - start_end;
415 }
416 // All headers written to buffer.
417 buffers[0] = buffer[0..end];
418 const remaining_buffers = buffers[1..];
419 const send_trailers_len: usize = @min(trailers.len, remaining_buffers.len);
420 @memcpy(remaining_buffers[0..send_trailers_len], trailers[0..send_trailers_len]);
421 const send_headers_len = 1;
422 const send_buffers = buffers[0 .. send_headers_len + send_trailers_len];
423 const n = try bw.unbuffered_writer.writeFile(file, offset, len, send_buffers, send_headers_len);
424 if (n < end) {
425 @branchHint(.unlikely);
426 const remainder = buffer[n..end];
427 std.mem.copyForwards(u8, buffer[0..remainder.len], remainder);
428 bw.end = remainder.len;
429 return end - start_end;
430 }
431 bw.end = 0;
432 return n - start_end;
433}
434
435pub const WriteFileOptions = struct {
436 offset: u64 = 0,
437 /// If the size of the source file is known, it is likely that passing the
438 /// size here will save one syscall.
439 len: Writer.VTable.FileLen = .entire_file,
440 /// Headers and trailers must be passed together so that in case `len` is
441 /// zero, they can be forwarded directly to `Writer.VTable.writev`.
442 ///
443 /// The parameter is mutable because this function needs to mutate the
444 /// fields in order to handle partial writes from `Writer.VTable.writeFile`.
445 headers_and_trailers: [][]const u8 = &.{},
446 /// The number of trailers is inferred from `headers_and_trailers.len -
447 /// headers_len`.
448 headers_len: usize = 0,
449};
450
451pub fn writeFileAll(bw: *BufferedWriter, file: std.fs.File, options: WriteFileOptions) anyerror!void {
452 const headers_and_trailers = options.headers_and_trailers;
453 const headers = headers_and_trailers[0..options.headers_len];
454 var len = options.len;
455 var i: usize = 0;
456 var offset = options.offset;
457 if (len == .zero) return writevAll(bw, headers_and_trailers[i..]);
458 while (i < headers_and_trailers.len) {
459 var n = try writeFile(bw, file, offset, len, headers_and_trailers[i..], headers.len - i);
460 while (i < headers.len and n >= headers[i].len) {
461 n -= headers[i].len;
462 i += 1;
463 }
464 if (i < headers.len) {
465 headers[i] = headers[i][n..];
466 continue;
467 }
468 if (n >= len.int()) {
469 n -= len.int();
470 while (n >= headers_and_trailers[i].len) {
471 n -= headers_and_trailers[i].len;
472 i += 1;
473 if (i >= headers_and_trailers.len) return;
474 }
475 headers_and_trailers[i] = headers_and_trailers[i][n..];
476 return writevAll(bw, headers_and_trailers[i..]);
477 }
478 offset += n;
479 len = if (len == .entire_file) .entire_file else .init(len.int() - n);
480 }
481}
482
483fn fixed_writeFile(
484 context: *anyopaque,
485 file: std.fs.File,
486 offset: u64,
487 len: Writer.VTable.FileLen,
488 headers_and_trailers: []const []const u8,
489 headers_len: usize,
490) anyerror!usize {
491 _ = context;
492 _ = file;
493 _ = offset;
494 _ = len;
495 _ = headers_and_trailers;
496 _ = headers_len;
497 return error.Unimplemented;
498}
499
500pub fn alignBuffer(
501 bw: *BufferedWriter,
502 buffer: []const u8,
503 width: usize,
504 alignment: std.fmt.Alignment,
505 fill: u8,
506) anyerror!void {
507 const padding = if (buffer.len < width) width - buffer.len else 0;
508 if (padding == 0) {
509 @branchHint(.likely);
510 return bw.writeAll(buffer);
511 }
512 switch (alignment) {
513 .left => {
514 try bw.writeAll(buffer);
515 try bw.splatByteAll(fill, padding);
516 },
517 .center => {
518 const left_padding = padding / 2;
519 const right_padding = (padding + 1) / 2;
520 try bw.splatByteAll(fill, left_padding);
521 try bw.writeAll(buffer);
522 try bw.splatByteAll(fill, right_padding);
523 },
524 .right => {
525 try bw.splatByteAll(fill, padding);
526 try bw.writeAll(buffer);
527 },
528 }
529}
530
531pub fn alignBufferOptions(bw: *BufferedWriter, buffer: []const u8, options: std.fmt.Options) anyerror!void {
532 return alignBuffer(bw, buffer, options.width orelse buffer.len, options.alignment, options.fill);
533}
534
535pub fn printAddress(bw: *BufferedWriter, value: anytype) anyerror!void {
536 const T = @TypeOf(value);
537
538 switch (@typeInfo(T)) {
539 .pointer => |info| {
540 try bw.writeAll(@typeName(info.child) ++ "@");
541 if (info.size == .slice)
542 try printIntOptions(bw, @intFromPtr(value.ptr), 16, .lower, .{})
543 else
544 try printIntOptions(bw, @intFromPtr(value), 16, .lower, .{});
545 return;
546 },
547 .optional => |info| {
548 if (@typeInfo(info.child) == .pointer) {
549 try bw.writeAll(@typeName(info.child) ++ "@");
550 try printIntOptions(bw, @intFromPtr(value), 16, .lower, .{});
551 return;
552 }
553 },
554 else => {},
555 }
556
557 @compileError("cannot format non-pointer type " ++ @typeName(T) ++ " with * specifier");
558}
559
560pub fn printValue(
561 bw: *BufferedWriter,
562 comptime fmt: []const u8,
563 options: std.fmt.Options,
564 value: anytype,
565 max_depth: usize,
566) anyerror!void {
567 const T = @TypeOf(value);
568 const actual_fmt = comptime if (std.mem.eql(u8, fmt, ANY))
569 defaultFormatString(T)
570 else if (fmt.len != 0 and (fmt[0] == '?' or fmt[0] == '!')) switch (@typeInfo(T)) {
571 .optional, .error_union => fmt,
572 else => stripOptionalOrErrorUnionSpec(fmt),
573 } else fmt;
574
575 if (comptime std.mem.eql(u8, actual_fmt, "*")) {
576 return printAddress(bw, value);
577 }
578
579 if (std.meta.hasMethod(T, "format")) {
580 if (fmt.len == 0) {
581 // @deprecated()
582 // After 0.14.0 is tagged, uncomment this next line:
583 //@compileError("ambiguous format string; specify {f} to call print method, or {any} to skip it");
584 return value.format(fmt, options, bw);
585 } else if (fmt[0] == 'f') {
586 return value.format(fmt[1..], options, bw);
587 }
588 }
589
590 switch (@typeInfo(T)) {
591 .float, .comptime_float => return printFloat(bw, actual_fmt, options, value),
592 .int, .comptime_int => return printInt(bw, actual_fmt, options, value),
593 .bool => {
594 if (actual_fmt.len != 0) invalidFmtError(fmt, value);
595 return alignBufferOptions(bw, if (value) "true" else "false", options);
596 },
597 .void => {
598 if (actual_fmt.len != 0) invalidFmtError(fmt, value);
599 return alignBufferOptions(bw, "void", options);
600 },
601 .optional => {
602 if (actual_fmt.len == 0 or actual_fmt[0] != '?')
603 @compileError("cannot print optional without a specifier (i.e. {?} or {any})");
604 const remaining_fmt = comptime stripOptionalOrErrorUnionSpec(actual_fmt);
605 if (value) |payload| {
606 return printValue(bw, remaining_fmt, options, payload, max_depth);
607 } else {
608 return alignBufferOptions(bw, "null", options);
609 }
610 },
611 .error_union => {
612 if (actual_fmt.len == 0 or actual_fmt[0] != '!')
613 @compileError("cannot format error union without a specifier (i.e. {!} or {any})");
614 const remaining_fmt = comptime stripOptionalOrErrorUnionSpec(actual_fmt);
615 if (value) |payload| {
616 return printValue(bw, remaining_fmt, options, payload, max_depth);
617 } else |err| {
618 return printValue(bw, "", options, err, max_depth);
619 }
620 },
621 .error_set => {
622 if (actual_fmt.len != 0) invalidFmtError(fmt, value);
623 try bw.writeAll("error.");
624 return bw.writeAll(@errorName(value));
625 },
626 .@"enum" => |enumInfo| {
627 try bw.writeAll(@typeName(T));
628 if (enumInfo.is_exhaustive) {
629 if (actual_fmt.len != 0) invalidFmtError(fmt, value);
630 try bw.writeAll(".");
631 try bw.writeAll(@tagName(value));
632 return;
633 }
634
635 // Use @tagName only if value is one of known fields
636 @setEvalBranchQuota(3 * enumInfo.fields.len);
637 inline for (enumInfo.fields) |enumField| {
638 if (@intFromEnum(value) == enumField.value) {
639 try bw.writeAll(".");
640 try bw.writeAll(@tagName(value));
641 return;
642 }
643 }
644
645 try bw.writeByte('(');
646 try printValue(bw, actual_fmt, options, @intFromEnum(value), max_depth);
647 try bw.writeByte(')');
648 },
649 .@"union" => |info| {
650 if (actual_fmt.len != 0) invalidFmtError(fmt, value);
651 try bw.writeAll(@typeName(T));
652 if (max_depth == 0) {
653 return bw.writeAll("{ ... }");
654 }
655 if (info.tag_type) |UnionTagType| {
656 try bw.writeAll("{ .");
657 try bw.writeAll(@tagName(@as(UnionTagType, value)));
658 try bw.writeAll(" = ");
659 inline for (info.fields) |u_field| {
660 if (value == @field(UnionTagType, u_field.name)) {
661 try printValue(bw, ANY, options, @field(value, u_field.name), max_depth - 1);
662 }
663 }
664 try bw.writeAll(" }");
665 } else {
666 try bw.writeByte('@');
667 try bw.printIntOptions(@intFromPtr(&value), 16, .lower);
668 }
669 },
670 .@"struct" => |info| {
671 if (actual_fmt.len != 0) invalidFmtError(fmt, value);
672 if (info.is_tuple) {
673 // Skip the type and field names when formatting tuples.
674 if (max_depth == 0) {
675 return bw.writeAll("{ ... }");
676 }
677 try bw.writeAll("{");
678 inline for (info.fields, 0..) |f, i| {
679 if (i == 0) {
680 try bw.writeAll(" ");
681 } else {
682 try bw.writeAll(", ");
683 }
684 try printValue(bw, ANY, options, @field(value, f.name), max_depth - 1);
685 }
686 return bw.writeAll(" }");
687 }
688 try bw.writeAll(@typeName(T));
689 if (max_depth == 0) {
690 return bw.writeAll("{ ... }");
691 }
692 try bw.writeAll("{");
693 inline for (info.fields, 0..) |f, i| {
694 if (i == 0) {
695 try bw.writeAll(" .");
696 } else {
697 try bw.writeAll(", .");
698 }
699 try bw.writeAll(f.name);
700 try bw.writeAll(" = ");
701 try printValue(bw, ANY, options, @field(value, f.name), max_depth - 1);
702 }
703 try bw.writeAll(" }");
704 },
705 .pointer => |ptr_info| switch (ptr_info.size) {
706 .one => switch (@typeInfo(ptr_info.child)) {
707 .array, .@"enum", .@"union", .@"struct" => {
708 return printValue(bw, actual_fmt, options, value.*, max_depth);
709 },
710 else => {
711 const buffers: [2][]const u8 = .{ @typeName(ptr_info.child), "@" };
712 try writevAll(bw, &buffers);
713 try printIntOptions(bw, @intFromPtr(value), 16, .lower);
714 },
715 },
716 .many, .c => {
717 if (actual_fmt.len == 0)
718 @compileError("cannot format pointer without a specifier (i.e. {s} or {*})");
719 if (ptr_info.sentinel() != null) {
720 return printValue(bw, actual_fmt, options, std.mem.span(value), max_depth);
721 }
722 if (actual_fmt[0] == 's' and ptr_info.child == u8) {
723 return alignBufferOptions(bw, std.mem.span(value), options);
724 }
725 invalidFmtError(fmt, value);
726 },
727 .slice => {
728 if (actual_fmt.len == 0)
729 @compileError("cannot format slice without a specifier (i.e. {s} or {any})");
730 if (max_depth == 0) {
731 return bw.writeAll("{ ... }");
732 }
733 if (actual_fmt[0] == 's' and ptr_info.child == u8) {
734 return alignBufferOptions(bw, value, options);
735 }
736 try bw.writeAll("{ ");
737 for (value, 0..) |elem, i| {
738 try printValue(bw, actual_fmt, options, elem, max_depth - 1);
739 if (i != value.len - 1) {
740 try bw.writeAll(", ");
741 }
742 }
743 try bw.writeAll(" }");
744 },
745 },
746 .array => |info| {
747 if (actual_fmt.len == 0)
748 @compileError("cannot format array without a specifier (i.e. {s} or {any})");
749 if (max_depth == 0) {
750 return bw.writeAll("{ ... }");
751 }
752 if (actual_fmt[0] == 's' and info.child == u8) {
753 return alignBufferOptions(bw, &value, options);
754 }
755 try bw.writeAll("{ ");
756 for (value, 0..) |elem, i| {
757 try printValue(bw, actual_fmt, options, elem, max_depth - 1);
758 if (i < value.len - 1) {
759 try bw.writeAll(", ");
760 }
761 }
762 try bw.writeAll(" }");
763 },
764 .vector => |info| {
765 if (max_depth == 0) {
766 return bw.writeAll("{ ... }");
767 }
768 try bw.writeAll("{ ");
769 var i: usize = 0;
770 while (i < info.len) : (i += 1) {
771 try printValue(bw, actual_fmt, options, value[i], max_depth - 1);
772 if (i < info.len - 1) {
773 try bw.writeAll(", ");
774 }
775 }
776 try bw.writeAll(" }");
777 },
778 .@"fn" => @compileError("unable to format function body type, use '*const " ++ @typeName(T) ++ "' for a function pointer type"),
779 .type => {
780 if (actual_fmt.len != 0) invalidFmtError(fmt, value);
781 return alignBufferOptions(bw, @typeName(value), options);
782 },
783 .enum_literal => {
784 if (actual_fmt.len != 0) invalidFmtError(fmt, value);
785 const buffer = [_]u8{'.'} ++ @tagName(value);
786 return alignBufferOptions(bw, buffer, options);
787 },
788 .null => {
789 if (actual_fmt.len != 0) invalidFmtError(fmt, value);
790 return alignBufferOptions(bw, "null", options);
791 },
792 else => @compileError("unable to format type '" ++ @typeName(T) ++ "'"),
793 }
794}
795
796pub fn printInt(
797 bw: *BufferedWriter,
798 comptime fmt: []const u8,
799 options: std.fmt.Options,
800 value: anytype,
801) anyerror!void {
802 comptime var base = 10;
803 comptime var case: std.fmt.Case = .lower;
804
805 const int_value = if (@TypeOf(value) == comptime_int) blk: {
806 const Int = std.math.IntFittingRange(value, value);
807 break :blk @as(Int, value);
808 } else value;
809
810 if (fmt.len == 0 or comptime std.mem.eql(u8, fmt, "d")) {
811 base = 10;
812 case = .lower;
813 } else if (comptime std.mem.eql(u8, fmt, "c")) {
814 if (@typeInfo(@TypeOf(int_value)).int.bits <= 8) {
815 return printAsciiChar(bw, @as(u8, int_value), options);
816 } else {
817 @compileError("cannot print integer that is larger than 8 bits as an ASCII character");
818 }
819 } else if (comptime std.mem.eql(u8, fmt, "u")) {
820 if (@typeInfo(@TypeOf(int_value)).int.bits <= 21) {
821 return printUnicodeCodepoint(bw, @as(u21, int_value), options);
822 } else {
823 @compileError("cannot print integer that is larger than 21 bits as an UTF-8 sequence");
824 }
825 } else if (comptime std.mem.eql(u8, fmt, "b")) {
826 base = 2;
827 case = .lower;
828 } else if (comptime std.mem.eql(u8, fmt, "x")) {
829 base = 16;
830 case = .lower;
831 } else if (comptime std.mem.eql(u8, fmt, "X")) {
832 base = 16;
833 case = .upper;
834 } else if (comptime std.mem.eql(u8, fmt, "o")) {
835 base = 8;
836 case = .lower;
837 } else {
838 invalidFmtError(fmt, value);
839 }
840
841 return printIntOptions(bw, int_value, base, case, options);
842}
843
844pub fn printAsciiChar(bw: *BufferedWriter, c: u8, options: std.fmt.Options) anyerror!void {
845 return alignBufferOptions(bw, @as(*const [1]u8, &c), options);
846}
847
848pub fn printAscii(bw: *BufferedWriter, bytes: []const u8, options: std.fmt.Options) anyerror!void {
849 return alignBufferOptions(bw, bytes, options);
850}
851
852pub fn printUnicodeCodepoint(bw: *BufferedWriter, c: u21, options: std.fmt.Options) anyerror!void {
853 var buf: [4]u8 = undefined;
854 const len = try std.unicode.utf8Encode(c, &buf);
855 return alignBufferOptions(bw, buf[0..len], options);
856}
857
858pub fn printIntOptions(
859 bw: *BufferedWriter,
860 value: anytype,
861 base: u8,
862 case: std.fmt.Case,
863 options: std.fmt.Options,
864) anyerror!void {
865 assert(base >= 2);
866
867 const int_value = if (@TypeOf(value) == comptime_int) blk: {
868 const Int = std.math.IntFittingRange(value, value);
869 break :blk @as(Int, value);
870 } else value;
871
872 const value_info = @typeInfo(@TypeOf(int_value)).int;
873
874 // The type must have the same size as `base` or be wider in order for the
875 // division to work
876 const min_int_bits = comptime @max(value_info.bits, 8);
877 const MinInt = std.meta.Int(.unsigned, min_int_bits);
878
879 const abs_value = @abs(int_value);
880 // The worst case in terms of space needed is base 2, plus 1 for the sign
881 var buf: [1 + @max(@as(comptime_int, value_info.bits), 1)]u8 = undefined;
882
883 var a: MinInt = abs_value;
884 var index: usize = buf.len;
885
886 if (base == 10) {
887 while (a >= 100) : (a = @divTrunc(a, 100)) {
888 index -= 2;
889 buf[index..][0..2].* = std.fmt.digits2(@intCast(a % 100));
890 }
891
892 if (a < 10) {
893 index -= 1;
894 buf[index] = '0' + @as(u8, @intCast(a));
895 } else {
896 index -= 2;
897 buf[index..][0..2].* = std.fmt.digits2(@intCast(a));
898 }
899 } else {
900 while (true) {
901 const digit = a % base;
902 index -= 1;
903 buf[index] = std.fmt.digitToChar(@intCast(digit), case);
904 a /= base;
905 if (a == 0) break;
906 }
907 }
908
909 if (value_info.signedness == .signed) {
910 if (value < 0) {
911 // Negative integer
912 index -= 1;
913 buf[index] = '-';
914 } else if (options.width == null or options.width.? == 0) {
915 // Positive integer, omit the plus sign
916 } else {
917 // Positive integer
918 index -= 1;
919 buf[index] = '+';
920 }
921 }
922
923 return alignBufferOptions(bw, buf[index..], options);
924}
925
926pub fn printFloat(
927 bw: *BufferedWriter,
928 comptime fmt: []const u8,
929 options: std.fmt.Options,
930 value: anytype,
931) anyerror!void {
932 var buf: [std.fmt.float.bufferSize(.decimal, f64)]u8 = undefined;
933
934 if (fmt.len > 1) invalidFmtError(fmt, value);
935 switch (if (fmt.len == 0) 'e' else fmt[0]) {
936 'e' => {
937 const s = std.fmt.float.render(&buf, value, .{ .mode = .scientific, .precision = options.precision }) catch |err| switch (err) {
938 error.BufferTooSmall => "(float)",
939 };
940 return alignBufferOptions(bw, s, options);
941 },
942 'd' => {
943 const s = std.fmt.float.render(&buf, value, .{ .mode = .decimal, .precision = options.precision }) catch |err| switch (err) {
944 error.BufferTooSmall => "(float)",
945 };
946 return alignBufferOptions(bw, s, options);
947 },
948 'x' => {
949 var sub_bw: BufferedWriter = undefined;
950 sub_bw.initFixed(&buf);
951 sub_bw.printFloatHexadecimal(value, options) catch unreachable;
952 return alignBufferOptions(bw, sub_bw.getWritten(), options);
953 },
954 else => invalidFmtError(fmt, value),
955 }
956}
957
958pub fn printFloatHexadecimal(bw: *BufferedWriter, value: anytype, opt_precision: ?usize) anyerror!void {
959 if (std.math.signbit(value)) try bw.writeByte('-');
960 if (std.math.isNan(value)) return bw.writeAll("nan");
961 if (std.math.isInf(value)) return bw.writeAll("inf");
962
963 const T = @TypeOf(value);
964 const TU = std.meta.Int(.unsigned, @bitSizeOf(T));
965
966 const mantissa_bits = std.math.floatMantissaBits(T);
967 const fractional_bits = std.math.floatFractionalBits(T);
968 const exponent_bits = std.math.floatExponentBits(T);
969 const mantissa_mask = (1 << mantissa_bits) - 1;
970 const exponent_mask = (1 << exponent_bits) - 1;
971 const exponent_bias = (1 << (exponent_bits - 1)) - 1;
972
973 const as_bits: TU = @bitCast(value);
974 var mantissa = as_bits & mantissa_mask;
975 var exponent: i32 = @as(u16, @truncate((as_bits >> mantissa_bits) & exponent_mask));
976
977 const is_denormal = exponent == 0 and mantissa != 0;
978 const is_zero = exponent == 0 and mantissa == 0;
979
980 if (is_zero) {
981 // Handle this case here to simplify the logic below.
982 try bw.writeAll("0x0");
983 if (opt_precision) |precision| {
984 if (precision > 0) {
985 try bw.writeAll(".");
986 try bw.splatByteAll('0', precision);
987 }
988 } else {
989 try bw.writeAll(".0");
990 }
991 try bw.writeAll("p0");
992 return;
993 }
994
995 if (is_denormal) {
996 // Adjust the exponent for printing.
997 exponent += 1;
998 } else {
999 if (fractional_bits == mantissa_bits)
1000 mantissa |= 1 << fractional_bits; // Add the implicit integer bit.
1001 }
1002
1003 const mantissa_digits = (fractional_bits + 3) / 4;
1004 // Fill in zeroes to round the fraction width to a multiple of 4.
1005 mantissa <<= mantissa_digits * 4 - fractional_bits;
1006
1007 if (opt_precision) |precision| {
1008 // Round if needed.
1009 if (precision < mantissa_digits) {
1010 // We always have at least 4 extra bits.
1011 var extra_bits = (mantissa_digits - precision) * 4;
1012 // The result LSB is the Guard bit, we need two more (Round and
1013 // Sticky) to round the value.
1014 while (extra_bits > 2) {
1015 mantissa = (mantissa >> 1) | (mantissa & 1);
1016 extra_bits -= 1;
1017 }
1018 // Round to nearest, tie to even.
1019 mantissa |= @intFromBool(mantissa & 0b100 != 0);
1020 mantissa += 1;
1021 // Drop the excess bits.
1022 mantissa >>= 2;
1023 // Restore the alignment.
1024 mantissa <<= @as(std.math.Log2Int(TU), @intCast((mantissa_digits - precision) * 4));
1025
1026 const overflow = mantissa & (1 << 1 + mantissa_digits * 4) != 0;
1027 // Prefer a normalized result in case of overflow.
1028 if (overflow) {
1029 mantissa >>= 1;
1030 exponent += 1;
1031 }
1032 }
1033 }
1034
1035 // +1 for the decimal part.
1036 var buf: [1 + mantissa_digits]u8 = undefined;
1037 assert(std.fmt.printInt(&buf, mantissa, 16, .lower, .{ .fill = '0', .width = 1 + mantissa_digits }) == buf.len);
1038
1039 try bw.writeAll("0x");
1040 try bw.writeByte(buf[0]);
1041 const trimmed = std.mem.trimRight(u8, buf[1..], "0");
1042 if (opt_precision) |precision| {
1043 if (precision > 0) try bw.writeAll(".");
1044 } else if (trimmed.len > 0) {
1045 try bw.writeAll(".");
1046 }
1047 try bw.writeAll(trimmed);
1048 // Add trailing zeros if explicitly requested.
1049 if (opt_precision) |precision| if (precision > 0) {
1050 if (precision > trimmed.len)
1051 try bw.writeByteNTimes('0', precision - trimmed.len);
1052 };
1053 try bw.writeAll("p");
1054 try printIntOptions(bw, exponent - exponent_bias, 10, .lower, .{});
1055}
1056
1057pub const ByteSizeUnits = enum {
1058 /// This formatter represents the number as multiple of 1000 and uses the SI
1059 /// measurement units (kB, MB, GB, ...).
1060 decimal,
1061 /// This formatter represents the number as multiple of 1024 and uses the IEC
1062 /// measurement units (KiB, MiB, GiB, ...).
1063 binary,
1064};
1065
1066/// Format option `precision` is ignored when `value` is less than 1kB
1067pub fn printByteSize(
1068 bw: *std.io.BufferedWriter,
1069 value: u64,
1070 units: ByteSizeUnits,
1071 options: std.fmt.Options,
1072) anyerror!void {
1073 if (value == 0) return alignBufferOptions(bw, "0B", options);
1074 // The worst case in terms of space needed is 32 bytes + 3 for the suffix.
1075 var buf: [std.fmt.float.min_buffer_size + 3]u8 = undefined;
1076
1077 const mags_si = " kMGTPEZY";
1078 const mags_iec = " KMGTPEZY";
1079
1080 const log2 = std.math.log2(value);
1081 const base = switch (units) {
1082 .decimal => 1000,
1083 .binary => 1024,
1084 };
1085 const magnitude = switch (units) {
1086 .decimal => @min(log2 / comptime std.math.log2(1000), mags_si.len - 1),
1087 .binary => @min(log2 / 10, mags_iec.len - 1),
1088 else => unreachable,
1089 };
1090 const new_value = std.math.lossyCast(f64, value) / std.math.pow(f64, std.math.lossyCast(f64, base), std.math.lossyCast(f64, magnitude));
1091 const suffix = switch (units) {
1092 .decimal => mags_si[magnitude],
1093 .binary => mags_iec[magnitude],
1094 else => unreachable,
1095 };
1096
1097 const s = switch (magnitude) {
1098 0 => buf[0..std.fmt.printInt(&buf, value, 10, .lower, .{})],
1099 else => std.fmt.float.render(&buf, new_value, .{ .mode = .decimal, .precision = options.precision }) catch |err| switch (err) {
1100 error.BufferTooSmall => unreachable,
1101 },
1102 };
1103
1104 var i: usize = s.len;
1105 if (suffix == ' ') {
1106 buf[i] = 'B';
1107 i += 1;
1108 } else switch (units) {
1109 .decimal => {
1110 buf[i..][0..2].* = [_]u8{ suffix, 'B' };
1111 i += 2;
1112 },
1113 .binary => {
1114 buf[i..][0..3].* = [_]u8{ suffix, 'i', 'B' };
1115 i += 3;
1116 },
1117 else => unreachable,
1118 }
1119
1120 return alignBufferOptions(buf[0..i], options, bw);
1121}
1122
1123// This ANY const is a workaround for: https://github.com/ziglang/zig/issues/7948
1124const ANY = "any";
1125
1126fn defaultFormatString(comptime T: type) [:0]const u8 {
1127 switch (@typeInfo(T)) {
1128 .array, .vector => return ANY,
1129 .pointer => |ptr_info| switch (ptr_info.size) {
1130 .one => switch (@typeInfo(ptr_info.child)) {
1131 .array => return ANY,
1132 else => {},
1133 },
1134 .many, .c => return "*",
1135 .slice => return ANY,
1136 },
1137 .optional => |info| return "?" ++ defaultFormatString(info.child),
1138 .error_union => |info| return "!" ++ defaultFormatString(info.payload),
1139 else => {},
1140 }
1141 return "";
1142}
1143
1144fn stripOptionalOrErrorUnionSpec(comptime fmt: []const u8) []const u8 {
1145 return if (std.mem.eql(u8, fmt[1..], ANY))
1146 ANY
1147 else
1148 fmt[1..];
1149}
1150
1151pub fn invalidFmtError(comptime fmt: []const u8, value: anytype) noreturn {
1152 @compileError("invalid format string '" ++ fmt ++ "' for type '" ++ @typeName(@TypeOf(value)) ++ "'");
1153}
1154
1155pub fn printDurationSigned(bw: *BufferedWriter, ns: i64) anyerror!void {
1156 if (ns < 0) try bw.writeByte('-');
1157 return printDurationUnsigned(bw, @abs(ns));
1158}
1159
1160pub fn printDurationUnsigned(bw: *BufferedWriter, ns: u64) anyerror!void {
1161 var ns_remaining = ns;
1162 inline for (.{
1163 .{ .ns = 365 * std.time.ns_per_day, .sep = 'y' },
1164 .{ .ns = std.time.ns_per_week, .sep = 'w' },
1165 .{ .ns = std.time.ns_per_day, .sep = 'd' },
1166 .{ .ns = std.time.ns_per_hour, .sep = 'h' },
1167 .{ .ns = std.time.ns_per_min, .sep = 'm' },
1168 }) |unit| {
1169 if (ns_remaining >= unit.ns) {
1170 const units = ns_remaining / unit.ns;
1171 try bw.printIntOptions(units, 10, .lower, .{});
1172 try bw.writeByte(unit.sep);
1173 ns_remaining -= units * unit.ns;
1174 if (ns_remaining == 0) return;
1175 }
1176 }
1177
1178 inline for (.{
1179 .{ .ns = std.time.ns_per_s, .sep = "s" },
1180 .{ .ns = std.time.ns_per_ms, .sep = "ms" },
1181 .{ .ns = std.time.ns_per_us, .sep = "us" },
1182 }) |unit| {
1183 const kunits = ns_remaining * 1000 / unit.ns;
1184 if (kunits >= 1000) {
1185 try bw.printIntOptions(kunits / 1000, 10, .lower, .{});
1186 const frac = kunits % 1000;
1187 if (frac > 0) {
1188 // Write up to 3 decimal places
1189 var decimal_buf = [_]u8{ '.', 0, 0, 0 };
1190 assert(printInt(decimal_buf[1..], frac, 10, .lower, .{ .fill = '0', .width = 3 }) == 3);
1191 var end: usize = 4;
1192 while (end > 1) : (end -= 1) {
1193 if (decimal_buf[end - 1] != '0') break;
1194 }
1195 try bw.writeAll(decimal_buf[0..end]);
1196 }
1197 return bw.writeAll(unit.sep);
1198 }
1199 }
1200
1201 try printIntOptions(bw, ns_remaining, 10, .lower, .{});
1202 try bw.writeAll("ns");
1203}
1204
1205/// Writes number of nanoseconds according to its signed magnitude:
1206/// `[#y][#w][#d][#h][#m]#[.###][n|u|m]s`
1207/// `nanoseconds` must be an integer that coerces into `u64` or `i64`.
1208pub fn printDuration(bw: *BufferedWriter, nanoseconds: anytype, options: std.fmt.Options) anyerror!void {
1209 // worst case: "-XXXyXXwXXdXXhXXmXX.XXXs".len = 24
1210 var buf: [24]u8 = undefined;
1211 var sub_bw: BufferedWriter = undefined;
1212 sub_bw.initFixed(&buf);
1213 switch (@typeInfo(@TypeOf(nanoseconds)).int.signedness) {
1214 .signed => sub_bw.printDurationSigned(nanoseconds, options) catch unreachable,
1215 .unsigned => sub_bw.printDurationUnsigned(nanoseconds, options) catch unreachable,
1216 }
1217 return alignBufferOptions(bw, sub_bw.getWritten(), options);
1218}
1219
1220pub fn printHex(bw: *BufferedWriter, bytes: []const u8, case: std.fmt.Case) anyerror!void {
1221 const charset = switch (case) {
1222 .upper => "0123456789ABCDEF",
1223 .lower => "0123456789abcdef",
1224 };
1225 for (bytes) |c| {
1226 try writeByte(bw, charset[c >> 4]);
1227 try writeByte(bw, charset[c & 15]);
1228 }
1229}
1230
1231test "formatValue max_depth" {
1232 const Vec2 = struct {
1233 const SelfType = @This();
1234 x: f32,
1235 y: f32,
1236
1237 pub fn format(
1238 self: SelfType,
1239 comptime fmt: []const u8,
1240 options: std.fmt.Options,
1241 bw: *BufferedWriter,
1242 ) anyerror!void {
1243 _ = options;
1244 if (fmt.len == 0) {
1245 return bw.print("({d:.3},{d:.3})", .{ self.x, self.y });
1246 } else {
1247 @compileError("unknown format string: '" ++ fmt ++ "'");
1248 }
1249 }
1250 };
1251 const E = enum {
1252 One,
1253 Two,
1254 Three,
1255 };
1256 const TU = union(enum) {
1257 const SelfType = @This();
1258 float: f32,
1259 int: u32,
1260 ptr: ?*SelfType,
1261 };
1262 const S = struct {
1263 const SelfType = @This();
1264 a: ?*SelfType,
1265 tu: TU,
1266 e: E,
1267 vec: Vec2,
1268 };
1269
1270 var inst = S{
1271 .a = null,
1272 .tu = TU{ .ptr = null },
1273 .e = E.Two,
1274 .vec = Vec2{ .x = 10.2, .y = 2.22 },
1275 };
1276 inst.a = &inst;
1277 inst.tu.ptr = &inst.tu;
1278
1279 var buf: [1000]u8 = undefined;
1280 var bw: BufferedWriter = undefined;
1281 bw.initFixed(&buf);
1282 try bw.printValue("", .{}, inst, 0);
1283 try testing.expectEqualStrings("io.BufferedWriter.test.printValue max_depth.S{ ... }", bw.getWritten());
1284
1285 bw.reset();
1286 try bw.printValue("", .{}, inst, 1);
1287 try testing.expectEqualStrings("io.BufferedWriter.test.printValue max_depth.S{ .a = io.BufferedWriter.test.printValue max_depth.S{ ... }, .tu = io.BufferedWriter.test.printValue max_depth.TU{ ... }, .e = io.BufferedWriter.test.printValue max_depth.E.Two, .vec = (10.200,2.220) }", bw.getWritten());
1288
1289 bw.reset();
1290 try bw.printValue("", .{}, inst, 2);
1291 try testing.expectEqualStrings("io.BufferedWriter.test.printValue max_depth.S{ .a = io.BufferedWriter.test.printValue max_depth.S{ .a = io.BufferedWriter.test.printValue max_depth.S{ ... }, .tu = io.BufferedWriter.test.printValue max_depth.TU{ ... }, .e = io.BufferedWriter.test.printValue max_depth.E.Two, .vec = (10.200,2.220) }, .tu = io.BufferedWriter.test.printValue max_depth.TU{ .ptr = io.BufferedWriter.test.printValue max_depth.TU{ ... } }, .e = io.BufferedWriter.test.printValue max_depth.E.Two, .vec = (10.200,2.220) }", bw.getWritten());
1292
1293 bw.reset();
1294 try bw.printValue("", .{}, inst, 3);
1295 try testing.expectEqualStrings("io.BufferedWriter.test.printValue max_depth.S{ .a = io.BufferedWriter.test.printValue max_depth.S{ .a = io.BufferedWriter.test.printValue max_depth.S{ .a = io.BufferedWriter.test.printValue max_depth.S{ ... }, .tu = io.BufferedWriter.test.printValue max_depth.TU{ ... }, .e = io.BufferedWriter.test.printValue max_depth.E.Two, .vec = (10.200,2.220) }, .tu = io.BufferedWriter.test.printValue max_depth.TU{ .ptr = io.BufferedWriter.test.printValue max_depth.TU{ ... } }, .e = io.BufferedWriter.test.printValue max_depth.E.Two, .vec = (10.200,2.220) }, .tu = io.BufferedWriter.test.printValue max_depth.TU{ .ptr = io.BufferedWriter.test.printValue max_depth.TU{ .ptr = io.BufferedWriter.test.printValue max_depth.TU{ ... } } }, .e = io.BufferedWriter.test.printValue max_depth.E.Two, .vec = (10.200,2.220) }", bw.getWritten());
1296
1297 const vec: @Vector(4, i32) = .{ 1, 2, 3, 4 };
1298 bw.reset();
1299 try bw.printValue("", .{}, vec, 0);
1300 try testing.expectEqualStrings("{ ... }", bw.getWritten());
1301
1302 bw.reset();
1303 try bw.printValue("", .{}, vec, 1);
1304 try testing.expectEqualStrings("{ 1, 2, 3, 4 }", bw.getWritten());
1305}
1306
1307test printDuration {
1308 testDurationCase("0ns", 0);
1309 testDurationCase("1ns", 1);
1310 testDurationCase("999ns", std.time.ns_per_us - 1);
1311 testDurationCase("1us", std.time.ns_per_us);
1312 testDurationCase("1.45us", 1450);
1313 testDurationCase("1.5us", 3 * std.time.ns_per_us / 2);
1314 testDurationCase("14.5us", 14500);
1315 testDurationCase("145us", 145000);
1316 testDurationCase("999.999us", std.time.ns_per_ms - 1);
1317 testDurationCase("1ms", std.time.ns_per_ms + 1);
1318 testDurationCase("1.5ms", 3 * std.time.ns_per_ms / 2);
1319 testDurationCase("1.11ms", 1110000);
1320 testDurationCase("1.111ms", 1111000);
1321 testDurationCase("1.111ms", 1111100);
1322 testDurationCase("999.999ms", std.time.ns_per_s - 1);
1323 testDurationCase("1s", std.time.ns_per_s);
1324 testDurationCase("59.999s", std.time.ns_per_min - 1);
1325 testDurationCase("1m", std.time.ns_per_min);
1326 testDurationCase("1h", std.time.ns_per_hour);
1327 testDurationCase("1d", std.time.ns_per_day);
1328 testDurationCase("1w", std.time.ns_per_week);
1329 testDurationCase("1y", 365 * std.time.ns_per_day);
1330 testDurationCase("1y52w23h59m59.999s", 730 * std.time.ns_per_day - 1); // 365d = 52w1
1331 testDurationCase("1y1h1.001s", 365 * std.time.ns_per_day + std.time.ns_per_hour + std.time.ns_per_s + std.time.ns_per_ms);
1332 testDurationCase("1y1h1s", 365 * std.time.ns_per_day + std.time.ns_per_hour + std.time.ns_per_s + 999 * std.time.ns_per_us);
1333 testDurationCase("1y1h999.999us", 365 * std.time.ns_per_day + std.time.ns_per_hour + std.time.ns_per_ms - 1);
1334 testDurationCase("1y1h1ms", 365 * std.time.ns_per_day + std.time.ns_per_hour + std.time.ns_per_ms);
1335 testDurationCase("1y1h1ms", 365 * std.time.ns_per_day + std.time.ns_per_hour + std.time.ns_per_ms + 1);
1336 testDurationCase("1y1m999ns", 365 * std.time.ns_per_day + std.time.ns_per_min + 999);
1337 testDurationCase("584y49w23h34m33.709s", std.math.maxInt(u64));
1338
1339 testing.expectFmt("=======0ns", "{D:=>10}", .{0});
1340 testing.expectFmt("1ns=======", "{D:=<10}", .{1});
1341 testing.expectFmt(" 999ns ", "{D:^10}", .{std.time.ns_per_us - 1});
1342}
1343
1344test printDurationSigned {
1345 testDurationCaseSigned("0ns", 0);
1346 testDurationCaseSigned("1ns", 1);
1347 testDurationCaseSigned("-1ns", -(1));
1348 testDurationCaseSigned("999ns", std.time.ns_per_us - 1);
1349 testDurationCaseSigned("-999ns", -(std.time.ns_per_us - 1));
1350 testDurationCaseSigned("1us", std.time.ns_per_us);
1351 testDurationCaseSigned("-1us", -(std.time.ns_per_us));
1352 testDurationCaseSigned("1.45us", 1450);
1353 testDurationCaseSigned("-1.45us", -(1450));
1354 testDurationCaseSigned("1.5us", 3 * std.time.ns_per_us / 2);
1355 testDurationCaseSigned("-1.5us", -(3 * std.time.ns_per_us / 2));
1356 testDurationCaseSigned("14.5us", 14500);
1357 testDurationCaseSigned("-14.5us", -(14500));
1358 testDurationCaseSigned("145us", 145000);
1359 testDurationCaseSigned("-145us", -(145000));
1360 testDurationCaseSigned("999.999us", std.time.ns_per_ms - 1);
1361 testDurationCaseSigned("-999.999us", -(std.time.ns_per_ms - 1));
1362 testDurationCaseSigned("1ms", std.time.ns_per_ms + 1);
1363 testDurationCaseSigned("-1ms", -(std.time.ns_per_ms + 1));
1364 testDurationCaseSigned("1.5ms", 3 * std.time.ns_per_ms / 2);
1365 testDurationCaseSigned("-1.5ms", -(3 * std.time.ns_per_ms / 2));
1366 testDurationCaseSigned("1.11ms", 1110000);
1367 testDurationCaseSigned("-1.11ms", -(1110000));
1368 testDurationCaseSigned("1.111ms", 1111000);
1369 testDurationCaseSigned("-1.111ms", -(1111000));
1370 testDurationCaseSigned("1.111ms", 1111100);
1371 testDurationCaseSigned("-1.111ms", -(1111100));
1372 testDurationCaseSigned("999.999ms", std.time.ns_per_s - 1);
1373 testDurationCaseSigned("-999.999ms", -(std.time.ns_per_s - 1));
1374 testDurationCaseSigned("1s", std.time.ns_per_s);
1375 testDurationCaseSigned("-1s", -(std.time.ns_per_s));
1376 testDurationCaseSigned("59.999s", std.time.ns_per_min - 1);
1377 testDurationCaseSigned("-59.999s", -(std.time.ns_per_min - 1));
1378 testDurationCaseSigned("1m", std.time.ns_per_min);
1379 testDurationCaseSigned("-1m", -(std.time.ns_per_min));
1380 testDurationCaseSigned("1h", std.time.ns_per_hour);
1381 testDurationCaseSigned("-1h", -(std.time.ns_per_hour));
1382 testDurationCaseSigned("1d", std.time.ns_per_day);
1383 testDurationCaseSigned("-1d", -(std.time.ns_per_day));
1384 testDurationCaseSigned("1w", std.time.ns_per_week);
1385 testDurationCaseSigned("-1w", -(std.time.ns_per_week));
1386 testDurationCaseSigned("1y", 365 * std.time.ns_per_day);
1387 testDurationCaseSigned("-1y", -(365 * std.time.ns_per_day));
1388 testDurationCaseSigned("1y52w23h59m59.999s", 730 * std.time.ns_per_day - 1); // 365d = 52w1d
1389 testDurationCaseSigned("-1y52w23h59m59.999s", -(730 * std.time.ns_per_day - 1)); // 365d = 52w1d
1390 testDurationCaseSigned("1y1h1.001s", 365 * std.time.ns_per_day + std.time.ns_per_hour + std.time.ns_per_s + std.time.ns_per_ms);
1391 testDurationCaseSigned("-1y1h1.001s", -(365 * std.time.ns_per_day + std.time.ns_per_hour + std.time.ns_per_s + std.time.ns_per_ms));
1392 testDurationCaseSigned("1y1h1s", 365 * std.time.ns_per_day + std.time.ns_per_hour + std.time.ns_per_s + 999 * std.time.ns_per_us);
1393 testDurationCaseSigned("-1y1h1s", -(365 * std.time.ns_per_day + std.time.ns_per_hour + std.time.ns_per_s + 999 * std.time.ns_per_us));
1394 testDurationCaseSigned("1y1h999.999us", 365 * std.time.ns_per_day + std.time.ns_per_hour + std.time.ns_per_ms - 1);
1395 testDurationCaseSigned("-1y1h999.999us", -(365 * std.time.ns_per_day + std.time.ns_per_hour + std.time.ns_per_ms - 1));
1396 testDurationCaseSigned("1y1h1ms", 365 * std.time.ns_per_day + std.time.ns_per_hour + std.time.ns_per_ms);
1397 testDurationCaseSigned("-1y1h1ms", -(365 * std.time.ns_per_day + std.time.ns_per_hour + std.time.ns_per_ms));
1398 testDurationCaseSigned("1y1h1ms", 365 * std.time.ns_per_day + std.time.ns_per_hour + std.time.ns_per_ms + 1);
1399 testDurationCaseSigned("-1y1h1ms", -(365 * std.time.ns_per_day + std.time.ns_per_hour + std.time.ns_per_ms + 1));
1400 testDurationCaseSigned("1y1m999ns", 365 * std.time.ns_per_day + std.time.ns_per_min + 999);
1401 testDurationCaseSigned("-1y1m999ns", -(365 * std.time.ns_per_day + std.time.ns_per_min + 999));
1402 testDurationCaseSigned("292y24w3d23h47m16.854s", std.math.maxInt(i64));
1403 testDurationCaseSigned("-292y24w3d23h47m16.854s", std.math.minInt(i64) + 1);
1404 testDurationCaseSigned("-292y24w3d23h47m16.854s", std.math.minInt(i64));
1405
1406 testing.expectFmt("=======0ns", "{s:=>10}", .{0});
1407 testing.expectFmt("1ns=======", "{s:=<10}", .{1});
1408 testing.expectFmt("-1ns======", "{s:=<10}", .{-(1)});
1409 testing.expectFmt(" -999ns ", "{s:^10}", .{-(std.time.ns_per_us - 1)});
1410}
1411
1412fn testDurationCase(expected: []const u8, input: u64) !void {
1413 var buf: [24]u8 = undefined;
1414 var bw: BufferedWriter = undefined;
1415 bw.initFixed(&buf);
1416 try bw.printDurationUnsigned(input);
1417 try testing.expectEqualStrings(expected, bw.getWritten());
1418}
1419
1420fn testDurationCaseSigned(expected: []const u8, input: i64) !void {
1421 var buf: [24]u8 = undefined;
1422 var bw: BufferedWriter = undefined;
1423 bw.initFixed(&buf);
1424 try bw.printDurationSigned(input);
1425 try testing.expectEqualStrings(expected, bw.getWritten());
1426}
1427
1428test printIntOptions {
1429 try testPrintIntCase("-1", @as(i1, -1), 10, .lower, .{});
1430
1431 try testPrintIntCase("-101111000110000101001110", @as(i32, -12345678), 2, .lower, .{});
1432 try testPrintIntCase("-12345678", @as(i32, -12345678), 10, .lower, .{});
1433 try testPrintIntCase("-bc614e", @as(i32, -12345678), 16, .lower, .{});
1434 try testPrintIntCase("-BC614E", @as(i32, -12345678), 16, .upper, .{});
1435
1436 try testPrintIntCase("12345678", @as(u32, 12345678), 10, .upper, .{});
1437
1438 try testPrintIntCase(" 666", @as(u32, 666), 10, .lower, .{ .width = 6 });
1439 try testPrintIntCase(" 1234", @as(u32, 0x1234), 16, .lower, .{ .width = 6 });
1440 try testPrintIntCase("1234", @as(u32, 0x1234), 16, .lower, .{ .width = 1 });
1441
1442 try testPrintIntCase("+42", @as(i32, 42), 10, .lower, .{ .width = 3 });
1443 try testPrintIntCase("-42", @as(i32, -42), 10, .lower, .{ .width = 3 });
1444}
1445
1446test "printInt with comptime_int" {
1447 var buf: [20]u8 = undefined;
1448 var bw: BufferedWriter = undefined;
1449 bw.initFixed(&buf);
1450 try bw.printInt(@as(comptime_int, 123456789123456789), "", .{});
1451 try std.testing.expectEqualStrings("123456789123456789", bw.getWritten());
1452}
1453
1454test "printFloat with comptime_float" {
1455 var buf: [20]u8 = undefined;
1456 var bw: BufferedWriter = undefined;
1457 bw.initFixed(&buf);
1458 try bw.printFloat("", .{}, @as(comptime_float, 1.0));
1459 try std.testing.expectEqualStrings(bw.getWritten(), "1e0");
1460 try std.testing.expectFmt("1e0", "{}", .{1.0});
1461}
1462
1463fn testPrintIntCase(expected: []const u8, value: anytype, base: u8, case: std.fmt.Case, options: std.fmt.Options) !void {
1464 var buffer: [100]u8 = undefined;
1465 var bw: BufferedWriter = undefined;
1466 bw.initFixed(&buffer);
1467 bw.printIntOptions(value, base, case, options);
1468 try testing.expectEqualStrings(expected, bw.getWritten());
1469}
1470
1471test printByteSize {
1472 try testing.expectFmt("file size: 42B\n", "file size: {B}\n", .{42});
1473 try testing.expectFmt("file size: 42B\n", "file size: {Bi}\n", .{42});
1474 try testing.expectFmt("file size: 63MB\n", "file size: {B}\n", .{63 * 1000 * 1000});
1475 try testing.expectFmt("file size: 63MiB\n", "file size: {Bi}\n", .{63 * 1024 * 1024});
1476 try testing.expectFmt("file size: 42B\n", "file size: {B:.2}\n", .{42});
1477 try testing.expectFmt("file size: 42B\n", "file size: {B:>9.2}\n", .{42});
1478 try testing.expectFmt("file size: 66.06MB\n", "file size: {B:.2}\n", .{63 * 1024 * 1024});
1479 try testing.expectFmt("file size: 60.08MiB\n", "file size: {Bi:.2}\n", .{63 * 1000 * 1000});
1480 try testing.expectFmt("file size: =66.06MB=\n", "file size: {B:=^9.2}\n", .{63 * 1024 * 1024});
1481 try testing.expectFmt("file size: 66.06MB\n", "file size: {B: >9.2}\n", .{63 * 1024 * 1024});
1482 try testing.expectFmt("file size: 66.06MB \n", "file size: {B: <9.2}\n", .{63 * 1024 * 1024});
1483 try testing.expectFmt("file size: 0.01844674407370955ZB\n", "file size: {B}\n", .{std.math.maxInt(u64)});
1484}
1485
1486test "bytes.hex" {
1487 const some_bytes = "\xCA\xFE\xBA\xBE";
1488 try std.testing.expectFmt("lowercase: cafebabe\n", "lowercase: {x}\n", .{some_bytes});
1489 try std.testing.expectFmt("uppercase: CAFEBABE\n", "uppercase: {X}\n", .{some_bytes});
1490 try std.testing.expectFmt("uppercase: CAFE\n", "uppercase: {X}\n", .{some_bytes[0..2]});
1491 try std.testing.expectFmt("lowercase: babe\n", "lowercase: {x}\n", .{some_bytes[2..]});
1492 const bytes_with_zeros = "\x00\x0E\xBA\xBE";
1493 try std.testing.expectFmt("lowercase: 000ebabe\n", "lowercase: {x}\n", .{bytes_with_zeros});
1494}
lib/std/io/CountingWriter.zig created+56
......@@ -0,0 +1,56 @@
1const std = @import("../std.zig");
2const CountingWriter = @This();
3const assert = std.debug.assert;
4const native_endian = @import("builtin").target.cpu.arch.endian();
5const Writer = std.io.Writer;
6const testing = std.testing;
7
8/// Underlying stream to passthrough bytes to.
9child_writer: Writer,
10bytes_written: u64 = 0,
11
12pub fn writer(cw: *CountingWriter) Writer {
13 return .{
14 .context = cw,
15 .vtable = &.{
16 .writev = passthru_writev,
17 .writeFile = passthru_writeFile,
18 },
19 };
20}
21
22pub fn unbufferedWriter(cw: *CountingWriter) std.io.BufferedWriter {
23 return .{
24 .buffer = &.{},
25 .unbuffered_writer = writer(cw),
26 };
27}
28
29fn passthru_writev(context: *anyopaque, data: []const []const u8) anyerror!usize {
30 const cw: *CountingWriter = @alignCast(@ptrCast(context));
31 const n = try cw.child_writer.writev(data);
32 cw.bytes_written += n;
33 return n;
34}
35
36fn passthru_writeFile(
37 context: *anyopaque,
38 file: std.fs.File,
39 offset: u64,
40 len: Writer.VTable.FileLen,
41 headers_and_trailers: []const []const u8,
42 headers_len: usize,
43) anyerror!usize {
44 const cw: *CountingWriter = @alignCast(@ptrCast(context));
45 const n = try cw.child_writer.writeFile(file, offset, len, headers_and_trailers, headers_len);
46 cw.bytes_written += n;
47 return n;
48}
49
50test CountingWriter {
51 var cw: CountingWriter = .{ .child_writer = std.io.null_writer };
52 var bw = cw.unbufferedWriter();
53 const bytes = "yay";
54 try bw.writeAll(bytes);
55 try testing.expect(cw.bytes_written == bytes.len);
56}
lib/std/io/FixedBufferStream.zig created+148
......@@ -0,0 +1,148 @@
1//! This turns a const byte buffer into an `io.Reader`, or `io.SeekableStream`.
2
3const std = @import("../std.zig");
4const io = std.io;
5const testing = std.testing;
6const mem = std.mem;
7const assert = std.debug.assert;
8const FixedBufferStream = @This();
9
10buffer: []const u8,
11pos: usize = 0,
12
13pub const ReadError = error{};
14pub const SeekError = error{};
15pub const GetSeekPosError = error{};
16
17pub const Reader = io.Reader(*Self, ReadError, read);
18
19pub const SeekableStream = io.SeekableStream(
20 *Self,
21 SeekError,
22 GetSeekPosError,
23 seekTo,
24 seekBy,
25 getPos,
26 getEndPos,
27);
28
29const Self = @This();
30
31pub fn reader(self: *Self) Reader {
32 return .{ .context = self };
33}
34
35pub fn seekableStream(self: *Self) SeekableStream {
36 return .{ .context = self };
37}
38
39pub fn read(self: *Self, dest: []u8) ReadError!usize {
40 const size = @min(dest.len, self.buffer.len - self.pos);
41 const end = self.pos + size;
42
43 @memcpy(dest[0..size], self.buffer[self.pos..end]);
44 self.pos = end;
45
46 return size;
47}
48
49pub fn seekTo(self: *Self, pos: u64) SeekError!void {
50 self.pos = @min(std.math.lossyCast(usize, pos), self.buffer.len);
51}
52
53pub fn seekBy(self: *Self, amt: i64) SeekError!void {
54 if (amt < 0) {
55 const abs_amt = @abs(amt);
56 const abs_amt_usize = std.math.cast(usize, abs_amt) orelse std.math.maxInt(usize);
57 if (abs_amt_usize > self.pos) {
58 self.pos = 0;
59 } else {
60 self.pos -= abs_amt_usize;
61 }
62 } else {
63 const amt_usize = std.math.cast(usize, amt) orelse std.math.maxInt(usize);
64 const new_pos = std.math.add(usize, self.pos, amt_usize) catch std.math.maxInt(usize);
65 self.pos = @min(self.buffer.len, new_pos);
66 }
67}
68
69pub fn getEndPos(self: *Self) GetSeekPosError!u64 {
70 return self.buffer.len;
71}
72
73pub fn getPos(self: *Self) GetSeekPosError!u64 {
74 return self.pos;
75}
76
77pub fn getWritten(self: Self) []const u8 {
78 return self.buffer[0..self.pos];
79}
80
81pub fn reset(self: *Self) void {
82 self.pos = 0;
83}
84
85test "output" {
86 var buf: [255]u8 = undefined;
87 var fbs: FixedBufferStream = .{ .buffer = &buf };
88 const stream = fbs.writer();
89
90 try stream.print("{s}{s}!", .{ "Hello", "World" });
91 try testing.expectEqualSlices(u8, "HelloWorld!", fbs.getWritten());
92}
93
94test "output at comptime" {
95 comptime {
96 var buf: [255]u8 = undefined;
97 var fbs: FixedBufferStream = .{ .buffer = &buf };
98 const stream = fbs.writer();
99
100 try stream.print("{s}{s}!", .{ "Hello", "World" });
101 try testing.expectEqualSlices(u8, "HelloWorld!", fbs.getWritten());
102 }
103}
104
105test "output 2" {
106 var buffer: [10]u8 = undefined;
107 var fbs: FixedBufferStream = .{ .buffer = &buffer };
108
109 try fbs.writer().writeAll("Hello");
110 try testing.expect(mem.eql(u8, fbs.getWritten(), "Hello"));
111
112 try fbs.writer().writeAll("world");
113 try testing.expect(mem.eql(u8, fbs.getWritten(), "Helloworld"));
114
115 try testing.expectError(error.NoSpaceLeft, fbs.writer().writeAll("!"));
116 try testing.expect(mem.eql(u8, fbs.getWritten(), "Helloworld"));
117
118 fbs.reset();
119 try testing.expect(fbs.getWritten().len == 0);
120
121 try testing.expectError(error.NoSpaceLeft, fbs.writer().writeAll("Hello world!"));
122 try testing.expect(mem.eql(u8, fbs.getWritten(), "Hello worl"));
123
124 try fbs.seekTo((try fbs.getEndPos()) + 1);
125 try testing.expectError(error.NoSpaceLeft, fbs.writer().writeAll("H"));
126}
127
128test "input" {
129 const bytes = [_]u8{ 1, 2, 3, 4, 5, 6, 7 };
130 var fbs: FixedBufferStream = .{ .buffer = &bytes };
131
132 var dest: [4]u8 = undefined;
133
134 var amt_read = try fbs.reader().read(&dest);
135 try testing.expect(amt_read == 4);
136 try testing.expect(mem.eql(u8, dest[0..4], bytes[0..4]));
137
138 amt_read = try fbs.reader().read(&dest);
139 try testing.expect(amt_read == 3);
140 try testing.expect(mem.eql(u8, dest[0..3], bytes[4..7]));
141
142 amt_read = try fbs.reader().read(&dest);
143 try testing.expect(amt_read == 0);
144
145 try fbs.seekTo((try fbs.getEndPos()) + 1);
146 amt_read = try fbs.reader().read(&dest);
147 try testing.expect(amt_read == 0);
148}
lib/std/io/Writer.zig+79-62
......@@ -1,83 +1,100 @@
11const std = @import("../std.zig");
22const assert = std.debug.assert;
3const mem = std.mem;
4const native_endian = @import("builtin").target.cpu.arch.endian();
3const Writer = @This();
54
6context: *const anyopaque,
7writeFn: *const fn (context: *const anyopaque, bytes: []const u8) anyerror!usize,
5context: *anyopaque,
6vtable: *const VTable,
87
9const Self = @This();
10pub const Error = anyerror;
8pub const VTable = struct {
9 /// Each slice in `data` is written in order.
10 ///
11 /// Number of bytes actually written is returned.
12 ///
13 /// Number of bytes returned may be zero, which does not mean
14 /// end-of-stream. A subsequent call may return nonzero, or may signal end
15 /// of stream via an error.
16 writev: *const fn (context: *anyopaque, data: []const []const u8) anyerror!usize,
1117
12pub fn write(self: Self, bytes: []const u8) anyerror!usize {
13 return self.writeFn(self.context, bytes);
14}
18 /// Writes contents from an open file. `headers` are written first, then `len`
19 /// bytes of `file` starting from `offset`, then `trailers`.
20 ///
21 /// Number of bytes actually written is returned, which may lie within
22 /// headers, the file, trailers, or anywhere in between.
23 ///
24 /// Number of bytes returned may be zero, which does not mean
25 /// end-of-stream. A subsequent call may return nonzero, or may signal end
26 /// of stream via an error.
27 writeFile: *const fn (
28 context: *anyopaque,
29 file: std.fs.File,
30 offset: u64,
31 /// When zero, it means copy until the end of the file is reached.
32 len: FileLen,
33 /// Headers and trailers must be passed together so that in case `len` is
34 /// zero, they can be forwarded directly to `VTable.writev`.
35 headers_and_trailers: []const []const u8,
36 headers_len: usize,
37 ) anyerror!usize,
1538
16pub fn writeAll(self: Self, bytes: []const u8) anyerror!void {
17 var index: usize = 0;
18 while (index != bytes.len) {
19 index += try self.write(bytes[index..]);
20 }
21}
39 pub const FileLen = enum(u64) {
40 zero = 0,
41 entire_file = std.math.maxInt(u64),
42 _,
2243
23pub fn print(self: Self, comptime format: []const u8, args: anytype) anyerror!void {
24 return std.fmt.format(self, format, args);
25}
26
27pub fn writeByte(self: Self, byte: u8) anyerror!void {
28 const array = [1]u8{byte};
29 return self.writeAll(&array);
30}
44 pub fn init(integer: u64) FileLen {
45 const result: FileLen = @enumFromInt(integer);
46 assert(result != .none);
47 return result;
48 }
3149
32pub fn writeByteNTimes(self: Self, byte: u8, n: usize) anyerror!void {
33 var bytes: [256]u8 = undefined;
34 @memset(bytes[0..], byte);
50 pub fn int(len: FileLen) u64 {
51 return @intFromEnum(len);
52 }
53 };
54};
3555
36 var remaining: usize = n;
37 while (remaining > 0) {
38 const to_write = @min(remaining, bytes.len);
39 try self.writeAll(bytes[0..to_write]);
40 remaining -= to_write;
41 }
56pub fn writev(w: Writer, data: []const []const u8) anyerror!usize {
57 return w.vtable.writev(w.context, data);
4258}
4359
44pub fn writeBytesNTimes(self: Self, bytes: []const u8, n: usize) anyerror!void {
45 var i: usize = 0;
46 while (i < n) : (i += 1) {
47 try self.writeAll(bytes);
48 }
60pub fn writeFile(
61 w: Writer,
62 file: std.fs.File,
63 offset: u64,
64 len: VTable.FileLen,
65 headers_and_trailers: []const []const u8,
66 headers_len: usize,
67) anyerror!usize {
68 return w.vtable.writeFile(w.context, file, offset, len, headers_and_trailers, headers_len);
4969}
5070
51pub inline fn writeInt(self: Self, comptime T: type, value: T, endian: std.builtin.Endian) anyerror!void {
52 var bytes: [@divExact(@typeInfo(T).int.bits, 8)]u8 = undefined;
53 mem.writeInt(std.math.ByteAlignedInt(@TypeOf(value)), &bytes, value, endian);
54 return self.writeAll(&bytes);
71pub fn write(w: Writer, bytes: []const u8) anyerror!usize {
72 const single: [1][]const u8 = .{bytes};
73 return w.vtable.writev(w.context, &single);
5574}
5675
57pub fn writeStruct(self: Self, value: anytype) anyerror!void {
58 // Only extern and packed structs have defined in-memory layout.
59 comptime assert(@typeInfo(@TypeOf(value)).@"struct".layout != .auto);
60 return self.writeAll(mem.asBytes(&value));
76pub fn writeAll(w: Writer, bytes: []const u8) anyerror!void {
77 var index: usize = 0;
78 while (index < bytes.len) index += try write(w, bytes[index..]);
6179}
6280
63pub fn writeStructEndian(self: Self, value: anytype, endian: std.builtin.Endian) anyerror!void {
64 // TODO: make sure this value is not a reference type
65 if (native_endian == endian) {
66 return self.writeStruct(value);
67 } else {
68 var copy = value;
69 mem.byteSwapAllFields(@TypeOf(value), &copy);
70 return self.writeStruct(copy);
71 }
72}
81///// Directly calls `writeAll` many times to render the formatted text. To
82///// enable buffering, call `std.io.BufferedWriter.print` instead.
83//pub fn unbufferedPrint(w: Writer, comptime format: []const u8, args: anytype) anyerror!void {
84// return std.fmt.format(w, format, args);
85//}
7386
74pub fn writeFile(self: Self, file: std.fs.File) anyerror!void {
75 // TODO: figure out how to adjust std lib abstractions so that this ends up
76 // doing sendfile or maybe even copy_file_range under the right conditions.
77 var buf: [4000]u8 = undefined;
87/// The `data` parameter is mutable because this function needs to mutate the
88/// fields in order to handle partial writes from `VTable.writev`.
89pub fn writevAll(w: Writer, data: [][]const u8) anyerror!void {
90 var i: usize = 0;
7891 while (true) {
79 const n = try file.readAll(&buf);
80 try self.writeAll(buf[0..n]);
81 if (n < buf.len) return;
92 var n = try w.vtable.writev(w.context, data[i..]);
93 while (n >= data[i].len) {
94 n -= data[i].len;
95 i += 1;
96 if (i >= data.len) return;
97 }
98 data[i] = data[i][n..];
8299 }
83100}
lib/std/io/buffered_writer.zig deleted-43
......@@ -1,43 +0,0 @@
1const std = @import("../std.zig");
2
3const io = std.io;
4const mem = std.mem;
5
6pub fn BufferedWriter(comptime buffer_size: usize, comptime WriterType: type) type {
7 return struct {
8 unbuffered_writer: WriterType,
9 buf: [buffer_size]u8 = undefined,
10 end: usize = 0,
11
12 pub const Error = WriterType.Error;
13 pub const Writer = io.Writer(*Self, Error, write);
14
15 const Self = @This();
16
17 pub fn flush(self: *Self) !void {
18 try self.unbuffered_writer.writeAll(self.buf[0..self.end]);
19 self.end = 0;
20 }
21
22 pub fn writer(self: *Self) Writer {
23 return .{ .context = self };
24 }
25
26 pub fn write(self: *Self, bytes: []const u8) Error!usize {
27 if (self.end + bytes.len > self.buf.len) {
28 try self.flush();
29 if (bytes.len > self.buf.len)
30 return self.unbuffered_writer.write(bytes);
31 }
32
33 const new_end = self.end + bytes.len;
34 @memcpy(self.buf[self.end..new_end], bytes);
35 self.end = new_end;
36 return bytes.len;
37 }
38 };
39}
40
41pub fn bufferedWriter(underlying_stream: anytype) BufferedWriter(4096, @TypeOf(underlying_stream)) {
42 return .{ .unbuffered_writer = underlying_stream };
43}
lib/std/io/counting_writer.zig deleted-39
......@@ -1,39 +0,0 @@
1const std = @import("../std.zig");
2const io = std.io;
3const testing = std.testing;
4
5/// A Writer that counts how many bytes has been written to it.
6pub fn CountingWriter(comptime WriterType: type) type {
7 return struct {
8 bytes_written: u64,
9 child_stream: WriterType,
10
11 pub const Error = WriterType.Error;
12 pub const Writer = io.Writer(*Self, Error, write);
13
14 const Self = @This();
15
16 pub fn write(self: *Self, bytes: []const u8) Error!usize {
17 const amt = try self.child_stream.write(bytes);
18 self.bytes_written += amt;
19 return amt;
20 }
21
22 pub fn writer(self: *Self) Writer {
23 return .{ .context = self };
24 }
25 };
26}
27
28pub fn countingWriter(child_stream: anytype) CountingWriter(@TypeOf(child_stream)) {
29 return .{ .bytes_written = 0, .child_stream = child_stream };
30}
31
32test CountingWriter {
33 var counting_stream = countingWriter(std.io.null_writer);
34 const stream = counting_stream.writer();
35
36 const bytes = "yay" ** 100;
37 stream.writeAll(bytes) catch unreachable;
38 try testing.expect(counting_stream.bytes_written == bytes.len);
39}
lib/std/io/fixed_buffer_stream.zig deleted-198
......@@ -1,198 +0,0 @@
1const std = @import("../std.zig");
2const io = std.io;
3const testing = std.testing;
4const mem = std.mem;
5const assert = std.debug.assert;
6
7/// This turns a byte buffer into an `io.Writer`, `io.Reader`, or `io.SeekableStream`.
8/// If the supplied byte buffer is const, then `io.Writer` is not available.
9pub fn FixedBufferStream(comptime Buffer: type) type {
10 return struct {
11 /// `Buffer` is either a `[]u8` or `[]const u8`.
12 buffer: Buffer,
13 pos: usize,
14
15 pub const ReadError = error{};
16 pub const WriteError = error{NoSpaceLeft};
17 pub const SeekError = error{};
18 pub const GetSeekPosError = error{};
19
20 pub const Reader = io.Reader(*Self, ReadError, read);
21 pub const Writer = io.Writer(*Self, WriteError, write);
22
23 pub const SeekableStream = io.SeekableStream(
24 *Self,
25 SeekError,
26 GetSeekPosError,
27 seekTo,
28 seekBy,
29 getPos,
30 getEndPos,
31 );
32
33 const Self = @This();
34
35 pub fn reader(self: *Self) Reader {
36 return .{ .context = self };
37 }
38
39 pub fn writer(self: *Self) Writer {
40 return .{ .context = self };
41 }
42
43 pub fn seekableStream(self: *Self) SeekableStream {
44 return .{ .context = self };
45 }
46
47 pub fn read(self: *Self, dest: []u8) ReadError!usize {
48 const size = @min(dest.len, self.buffer.len - self.pos);
49 const end = self.pos + size;
50
51 @memcpy(dest[0..size], self.buffer[self.pos..end]);
52 self.pos = end;
53
54 return size;
55 }
56
57 /// If the returned number of bytes written is less than requested, the
58 /// buffer is full. Returns `error.NoSpaceLeft` when no bytes would be written.
59 /// Note: `error.NoSpaceLeft` matches the corresponding error from
60 /// `std.fs.File.WriteError`.
61 pub fn write(self: *Self, bytes: []const u8) WriteError!usize {
62 if (bytes.len == 0) return 0;
63 if (self.pos >= self.buffer.len) return error.NoSpaceLeft;
64
65 const n = @min(self.buffer.len - self.pos, bytes.len);
66 @memcpy(self.buffer[self.pos..][0..n], bytes[0..n]);
67 self.pos += n;
68
69 if (n == 0) return error.NoSpaceLeft;
70
71 return n;
72 }
73
74 pub fn seekTo(self: *Self, pos: u64) SeekError!void {
75 self.pos = @min(std.math.lossyCast(usize, pos), self.buffer.len);
76 }
77
78 pub fn seekBy(self: *Self, amt: i64) SeekError!void {
79 if (amt < 0) {
80 const abs_amt = @abs(amt);
81 const abs_amt_usize = std.math.cast(usize, abs_amt) orelse std.math.maxInt(usize);
82 if (abs_amt_usize > self.pos) {
83 self.pos = 0;
84 } else {
85 self.pos -= abs_amt_usize;
86 }
87 } else {
88 const amt_usize = std.math.cast(usize, amt) orelse std.math.maxInt(usize);
89 const new_pos = std.math.add(usize, self.pos, amt_usize) catch std.math.maxInt(usize);
90 self.pos = @min(self.buffer.len, new_pos);
91 }
92 }
93
94 pub fn getEndPos(self: *Self) GetSeekPosError!u64 {
95 return self.buffer.len;
96 }
97
98 pub fn getPos(self: *Self) GetSeekPosError!u64 {
99 return self.pos;
100 }
101
102 pub fn getWritten(self: Self) Buffer {
103 return self.buffer[0..self.pos];
104 }
105
106 pub fn reset(self: *Self) void {
107 self.pos = 0;
108 }
109 };
110}
111
112pub fn fixedBufferStream(buffer: anytype) FixedBufferStream(Slice(@TypeOf(buffer))) {
113 return .{ .buffer = buffer, .pos = 0 };
114}
115
116fn Slice(comptime T: type) type {
117 switch (@typeInfo(T)) {
118 .pointer => |ptr_info| {
119 var new_ptr_info = ptr_info;
120 switch (ptr_info.size) {
121 .slice => {},
122 .one => switch (@typeInfo(ptr_info.child)) {
123 .array => |info| new_ptr_info.child = info.child,
124 else => @compileError("invalid type given to fixedBufferStream"),
125 },
126 else => @compileError("invalid type given to fixedBufferStream"),
127 }
128 new_ptr_info.size = .slice;
129 return @Type(.{ .pointer = new_ptr_info });
130 },
131 else => @compileError("invalid type given to fixedBufferStream"),
132 }
133}
134
135test "output" {
136 var buf: [255]u8 = undefined;
137 var fbs = fixedBufferStream(&buf);
138 const stream = fbs.writer();
139
140 try stream.print("{s}{s}!", .{ "Hello", "World" });
141 try testing.expectEqualSlices(u8, "HelloWorld!", fbs.getWritten());
142}
143
144test "output at comptime" {
145 comptime {
146 var buf: [255]u8 = undefined;
147 var fbs = fixedBufferStream(&buf);
148 const stream = fbs.writer();
149
150 try stream.print("{s}{s}!", .{ "Hello", "World" });
151 try testing.expectEqualSlices(u8, "HelloWorld!", fbs.getWritten());
152 }
153}
154
155test "output 2" {
156 var buffer: [10]u8 = undefined;
157 var fbs = fixedBufferStream(&buffer);
158
159 try fbs.writer().writeAll("Hello");
160 try testing.expect(mem.eql(u8, fbs.getWritten(), "Hello"));
161
162 try fbs.writer().writeAll("world");
163 try testing.expect(mem.eql(u8, fbs.getWritten(), "Helloworld"));
164
165 try testing.expectError(error.NoSpaceLeft, fbs.writer().writeAll("!"));
166 try testing.expect(mem.eql(u8, fbs.getWritten(), "Helloworld"));
167
168 fbs.reset();
169 try testing.expect(fbs.getWritten().len == 0);
170
171 try testing.expectError(error.NoSpaceLeft, fbs.writer().writeAll("Hello world!"));
172 try testing.expect(mem.eql(u8, fbs.getWritten(), "Hello worl"));
173
174 try fbs.seekTo((try fbs.getEndPos()) + 1);
175 try testing.expectError(error.NoSpaceLeft, fbs.writer().writeAll("H"));
176}
177
178test "input" {
179 const bytes = [_]u8{ 1, 2, 3, 4, 5, 6, 7 };
180 var fbs = fixedBufferStream(&bytes);
181
182 var dest: [4]u8 = undefined;
183
184 var read = try fbs.reader().read(&dest);
185 try testing.expect(read == 4);
186 try testing.expect(mem.eql(u8, dest[0..4], bytes[0..4]));
187
188 read = try fbs.reader().read(&dest);
189 try testing.expect(read == 3);
190 try testing.expect(mem.eql(u8, dest[0..3], bytes[4..7]));
191
192 read = try fbs.reader().read(&dest);
193 try testing.expect(read == 0);
194
195 try fbs.seekTo((try fbs.getEndPos()) + 1);
196 read = try fbs.reader().read(&dest);
197 try testing.expect(read == 0);
198}
lib/std/log.zig+6-5
......@@ -148,14 +148,15 @@ pub fn defaultLog(
148148) void {
149149 const level_txt = comptime message_level.asText();
150150 const prefix2 = if (scope == .default) ": " else "(" ++ @tagName(scope) ++ "): ";
151 const stderr = std.io.getStdErr().writer();
152 var bw = std.io.bufferedWriter(stderr);
153 const writer = bw.writer();
154
151 var buffer: [1024]u8 = undefined;
152 var bw: std.io.BufferedWriter = .{
153 .unbuffered_writer = std.io.getStdErr().writer(),
154 .buffer = &buffer,
155 };
155156 std.debug.lockStdErr();
156157 defer std.debug.unlockStdErr();
157158 nosuspend {
158 writer.print(level_txt ++ prefix2 ++ format ++ "\n", args) catch return;
159 bw.print(level_txt ++ prefix2 ++ format ++ "\n", args) catch return;
159160 bw.flush() catch return;
160161 }
161162}
lib/std/os/uefi.zig+7-9
......@@ -67,19 +67,17 @@ pub const Guid = extern struct {
6767 ) !void {
6868 _ = options;
6969 if (f.len == 0) {
70 const fmt = std.fmt.fmtSliceHexLower;
71
7270 const time_low = @byteSwap(self.time_low);
7371 const time_mid = @byteSwap(self.time_mid);
7472 const time_high_and_version = @byteSwap(self.time_high_and_version);
7573
76 return std.fmt.format(writer, "{:0>8}-{:0>4}-{:0>4}-{:0>2}{:0>2}-{:0>12}", .{
77 fmt(std.mem.asBytes(&time_low)),
78 fmt(std.mem.asBytes(&time_mid)),
79 fmt(std.mem.asBytes(&time_high_and_version)),
80 fmt(std.mem.asBytes(&self.clock_seq_high_and_reserved)),
81 fmt(std.mem.asBytes(&self.clock_seq_low)),
82 fmt(std.mem.asBytes(&self.node)),
74 return std.fmt.format(writer, "{x:0>8}-{x:0>4}-{x:0>4}-{x:0>2}{x:0>2}-{x:0>12}", .{
75 std.mem.asBytes(&time_low),
76 std.mem.asBytes(&time_mid),
77 std.mem.asBytes(&time_high_and_version),
78 std.mem.asBytes(&self.clock_seq_high_and_reserved),
79 std.mem.asBytes(&self.clock_seq_low),
80 std.mem.asBytes(&self.node),
8381 });
8482 } else {
8583 std.fmt.invalidFmtError(f, self);