| author | |
| committer | |
| log | 00c6c836a66db0bc08309534a49d4c5941a416aa |
| tree | cccb3d0fe18fc72e48bb4e369348d504ce00f873 |
| parent | ee6d19480da53b3a351749e2a7b18c45ad072018 |
hello world is compiling32 files changed, 3894 insertions(+), 3413 deletions(-)
CMakeLists.txt-4| ... | @@ -436,7 +436,6 @@ set(ZIG_STAGE2_SOURCES | ... | @@ -436,7 +436,6 @@ set(ZIG_STAGE2_SOURCES |
| 436 | lib/std/elf.zig | 436 | lib/std/elf.zig |
| 437 | lib/std/fifo.zig | 437 | lib/std/fifo.zig |
| 438 | lib/std/fmt.zig | 438 | lib/std/fmt.zig |
| 439 | lib/std/fmt/format_float.zig | ||
| 440 | lib/std/fmt/parse_float.zig | 439 | lib/std/fmt/parse_float.zig |
| 441 | lib/std/fs.zig | 440 | lib/std/fs.zig |
| 442 | lib/std/fs/AtomicFile.zig | 441 | lib/std/fs/AtomicFile.zig |
| ... | @@ -454,12 +453,9 @@ set(ZIG_STAGE2_SOURCES | ... | @@ -454,12 +453,9 @@ set(ZIG_STAGE2_SOURCES |
| 454 | lib/std/io/Reader.zig | 453 | lib/std/io/Reader.zig |
| 455 | lib/std/io/Writer.zig | 454 | lib/std/io/Writer.zig |
| 456 | lib/std/io/buffered_atomic_file.zig | 455 | lib/std/io/buffered_atomic_file.zig |
| 457 | lib/std/io/buffered_writer.zig | ||
| 458 | lib/std/io/change_detection_stream.zig | 456 | lib/std/io/change_detection_stream.zig |
| 459 | lib/std/io/counting_reader.zig | 457 | lib/std/io/counting_reader.zig |
| 460 | lib/std/io/counting_writer.zig | ||
| 461 | lib/std/io/find_byte_writer.zig | 458 | lib/std/io/find_byte_writer.zig |
| 462 | lib/std/io/fixed_buffer_stream.zig | ||
| 463 | lib/std/io/limited_reader.zig | 459 | lib/std/io/limited_reader.zig |
| 464 | lib/std/io/seekable_stream.zig | 460 | lib/std/io/seekable_stream.zig |
| 465 | lib/std/json.zig | 461 | lib/std/json.zig |
lib/std/Build/Cache.zig+5-7| ... | @@ -286,11 +286,9 @@ pub const HashHelper = struct { | ... | @@ -286,11 +286,9 @@ pub const HashHelper = struct { |
| 286 | 286 | ||
| 287 | pub fn binToHex(bin_digest: BinDigest) HexDigest { | 287 | pub fn binToHex(bin_digest: BinDigest) HexDigest { |
| 288 | var out_digest: HexDigest = undefined; | 288 | var out_digest: HexDigest = undefined; |
| 289 | _ = fmt.bufPrint( | 289 | var bw: std.io.BufferedWriter = undefined; |
| 290 | &out_digest, | 290 | bw.initFixed(&out_digest); |
| 291 | "{s}", | 291 | bw.printHex(&bin_digest, .lower) catch unreachable; |
| 292 | .{fmt.fmtSliceHexLower(&bin_digest)}, | ||
| 293 | ) catch unreachable; | ||
| 294 | return out_digest; | 292 | return out_digest; |
| 295 | } | 293 | } |
| 296 | 294 | ||
| ... | @@ -1133,11 +1131,11 @@ pub const Manifest = struct { | ... | @@ -1133,11 +1131,11 @@ pub const Manifest = struct { |
| 1133 | const writer = contents.writer(); | 1131 | const writer = contents.writer(); |
| 1134 | try writer.writeAll(manifest_header ++ "\n"); | 1132 | try writer.writeAll(manifest_header ++ "\n"); |
| 1135 | for (self.files.keys()) |file| { | 1133 | 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", .{ |
| 1137 | file.stat.size, | 1135 | file.stat.size, |
| 1138 | file.stat.inode, | 1136 | file.stat.inode, |
| 1139 | file.stat.mtime, | 1137 | file.stat.mtime, |
| 1140 | fmt.fmtSliceHexLower(&file.bin_digest), | 1138 | &file.bin_digest, |
| 1141 | file.prefixed_path.prefix, | 1139 | file.prefixed_path.prefix, |
| 1142 | file.prefixed_path.sub_path, | 1140 | file.prefixed_path.sub_path, |
| 1143 | }); | 1141 | }); |
lib/std/Build/Step/CheckObject.zig+1-1| ... | @@ -963,7 +963,7 @@ const MachODumper = struct { | ... | @@ -963,7 +963,7 @@ const MachODumper = struct { |
| 963 | .UUID => { | 963 | .UUID => { |
| 964 | const uuid = lc.cast(macho.uuid_command).?; | 964 | const uuid = lc.cast(macho.uuid_command).?; |
| 965 | try writer.writeByte('\n'); | 965 | try writer.writeByte('\n'); |
| 966 | try writer.print("uuid {x}", .{std.fmt.fmtSliceHexLower(&uuid.uuid)}); | 966 | try writer.print("uuid {x}", .{&uuid.uuid}); |
| 967 | }, | 967 | }, |
| 968 | 968 | ||
| 969 | .DATA_IN_CODE, | 969 | .DATA_IN_CODE, |
lib/std/Build/Step/Compile.zig+2-8| ... | @@ -1696,9 +1696,7 @@ fn getZigArgs(compile: *Compile, fuzz: bool) ![][]const u8 { | ... | @@ -1696,9 +1696,7 @@ fn getZigArgs(compile: *Compile, fuzz: bool) ![][]const u8 { |
| 1696 | 1696 | ||
| 1697 | if (compile.build_id orelse b.build_id) |build_id| { | 1697 | if (compile.build_id orelse b.build_id) |build_id| { |
| 1698 | try zig_args.append(switch (build_id) { | 1698 | try zig_args.append(switch (build_id) { |
| 1699 | .hexstring => |hs| b.fmt("--build-id=0x{s}", .{ | 1699 | .hexstring => |hs| b.fmt("--build-id=0x{x}", .{hs.toSlice()}), |
| 1700 | std.fmt.fmtSliceHexLower(hs.toSlice()), | ||
| 1701 | }), | ||
| 1702 | .none, .fast, .uuid, .sha1, .md5 => b.fmt("--build-id={s}", .{@tagName(build_id)}), | 1700 | .none, .fast, .uuid, .sha1, .md5 => b.fmt("--build-id={s}", .{@tagName(build_id)}), |
| 1703 | }); | 1701 | }); |
| 1704 | } | 1702 | } |
| ... | @@ -1793,11 +1791,7 @@ fn getZigArgs(compile: *Compile, fuzz: bool) ![][]const u8 { | ... | @@ -1793,11 +1791,7 @@ fn getZigArgs(compile: *Compile, fuzz: bool) ![][]const u8 { |
| 1793 | var args_hash: [Sha256.digest_length]u8 = undefined; | 1791 | var args_hash: [Sha256.digest_length]u8 = undefined; |
| 1794 | Sha256.hash(args, &args_hash, .{}); | 1792 | Sha256.hash(args, &args_hash, .{}); |
| 1795 | var args_hex_hash: [Sha256.digest_length * 2]u8 = undefined; | 1793 | var args_hex_hash: [Sha256.digest_length * 2]u8 = undefined; |
| 1796 | _ = try std.fmt.bufPrint( | 1794 | _ = try std.fmt.bufPrint(&args_hex_hash, "{x}", .{&args_hash}); |
| 1797 | &args_hex_hash, | ||
| 1798 | "{s}", | ||
| 1799 | .{std.fmt.fmtSliceHexLower(&args_hash)}, | ||
| 1800 | ); | ||
| 1801 | 1795 | ||
| 1802 | const args_file = "args" ++ fs.path.sep_str ++ args_hex_hash; | 1796 | const args_file = "args" ++ fs.path.sep_str ++ args_hex_hash; |
| 1803 | try b.cache_root.handle.writeFile(.{ .sub_path = args_file, .data = args }); | 1797 | 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 | ... | @@ -338,23 +338,66 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?mem.Alignment) ty |
| 338 | @memcpy(self.items[old_len..][0..items.len], items); | 338 | @memcpy(self.items[old_len..][0..items.len], items); |
| 339 | } | 339 | } |
| 340 | 340 | ||
| 341 | pub const Writer = if (T != u8) | 341 | /// Initializes a `std.io.Writer` which will append to the list. |
| 342 | @compileError("The Writer interface is only defined for ArrayList(u8) " ++ | 342 | pub fn writer(self: *Self) std.io.Writer { |
| 343 | "but the given type is ArrayList(" ++ @typeName(T) ++ ")") | 343 | comptime assert(T == u8); |
| 344 | else | 344 | return .{ |
| 345 | std.io.Writer(*Self, Allocator.Error, appendWrite); | 345 | .context = self, |
| 346 | 346 | .vtable = &.{ | |
| 347 | /// Initializes a Writer which will append to the list. | 347 | .writev = expanding_writev, |
| 348 | pub fn writer(self: *Self) Writer { | 348 | .writeFile = expanding_writeFile, |
| 349 | return .{ .context = self }; | 349 | }, |
| 350 | }; | ||
| 350 | } | 351 | } |
| 351 | 352 | ||
| 352 | /// Same as `append` except it returns the number of bytes written, which is always the same | 353 | fn expanding_writev(context: *anyopaque, data: []const []const u8) anyerror!usize { |
| 353 | /// as `m.len`. The purpose of this function existing is to match `std.io.Writer` API. | 354 | const self: *Self = @alignCast(@ptrCast(context)); |
| 354 | /// Invalidates element pointers if additional memory is needed. | 355 | const original_len = self.items.len; |
| 355 | fn appendWrite(self: *Self, m: []const u8) Allocator.Error!usize { | 356 | var new_capacity: usize = self.capacity; |
| 356 | try self.appendSlice(m); | 357 | for (data) |bytes| new_capacity += bytes.len; |
| 357 | return m.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; | ||
| 358 | } | 401 | } |
| 359 | 402 | ||
| 360 | pub const FixedWriter = std.io.Writer(*Self, Allocator.Error, appendWriteFixed); | 403 | pub const FixedWriter = std.io.Writer(*Self, Allocator.Error, appendWriteFixed); |
lib/std/crypto/25519/curve25519.zig+2-2| ... | @@ -124,9 +124,9 @@ test "curve25519" { | ... | @@ -124,9 +124,9 @@ test "curve25519" { |
| 124 | const p = try Curve25519.basePoint.clampedMul(s); | 124 | const p = try Curve25519.basePoint.clampedMul(s); |
| 125 | try p.rejectIdentity(); | 125 | try p.rejectIdentity(); |
| 126 | var buf: [128]u8 = undefined; | 126 | 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"); |
| 128 | const q = try p.clampedMul(s); | 128 | 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"); |
| 130 | 130 | ||
| 131 | try Curve25519.rejectNonCanonical(s); | 131 | try Curve25519.rejectNonCanonical(s); |
| 132 | s[31] |= 0x80; | 132 | s[31] |= 0x80; |
lib/std/crypto/25519/ed25519.zig+3-3| ... | @@ -509,8 +509,8 @@ test "key pair creation" { | ... | @@ -509,8 +509,8 @@ test "key pair creation" { |
| 509 | _ = try fmt.hexToBytes(seed[0..], "8052030376d47112be7f73ed7a019293dd12ad910b654455798b4667d73de166"); | 509 | _ = try fmt.hexToBytes(seed[0..], "8052030376d47112be7f73ed7a019293dd12ad910b654455798b4667d73de166"); |
| 510 | const key_pair = try Ed25519.KeyPair.generateDeterministic(seed); | 510 | const key_pair = try Ed25519.KeyPair.generateDeterministic(seed); |
| 511 | var buf: [256]u8 = undefined; | 511 | 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"); | 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, "{s}", .{std.fmt.fmtSliceHexUpper(&key_pair.public_key.toBytes())}), "2D6F7455D97B4A3A10D7293909D1A4F2058CB9A370E43FA8154BB280DB839083"); | 513 | try std.testing.expectEqualStrings(try std.fmt.bufPrint(&buf, "{X}", .{&key_pair.public_key.toBytes()}), "2D6F7455D97B4A3A10D7293909D1A4F2058CB9A370E43FA8154BB280DB839083"); |
| 514 | } | 514 | } |
| 515 | 515 | ||
| 516 | test "signature" { | 516 | test "signature" { |
| ... | @@ -520,7 +520,7 @@ test "signature" { | ... | @@ -520,7 +520,7 @@ test "signature" { |
| 520 | 520 | ||
| 521 | const sig = try key_pair.sign("test", null); | 521 | const sig = try key_pair.sign("test", null); |
| 522 | var buf: [128]u8 = undefined; | 522 | 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"); |
| 524 | try sig.verify("test", key_pair.public_key); | 524 | try sig.verify("test", key_pair.public_key); |
| 525 | try std.testing.expectError(error.SignatureVerificationFailed, sig.verify("TEST", key_pair.public_key)); | 525 | try std.testing.expectError(error.SignatureVerificationFailed, sig.verify("TEST", key_pair.public_key)); |
| 526 | } | 526 | } |
lib/std/crypto/25519/edwards25519.zig+1-1| ... | @@ -546,7 +546,7 @@ test "packing/unpacking" { | ... | @@ -546,7 +546,7 @@ test "packing/unpacking" { |
| 546 | var b = Edwards25519.basePoint; | 546 | var b = Edwards25519.basePoint; |
| 547 | const pk = try b.mul(s); | 547 | const pk = try b.mul(s); |
| 548 | var buf: [128]u8 = undefined; | 548 | 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"); |
| 550 | 550 | ||
| 551 | const small_order_ss: [7][32]u8 = .{ | 551 | const small_order_ss: [7][32]u8 = .{ |
| 552 | .{ | 552 | .{ |
lib/std/crypto/25519/ristretto255.zig+4-4| ... | @@ -175,21 +175,21 @@ pub const Ristretto255 = struct { | ... | @@ -175,21 +175,21 @@ pub const Ristretto255 = struct { |
| 175 | test "ristretto255" { | 175 | test "ristretto255" { |
| 176 | const p = Ristretto255.basePoint; | 176 | const p = Ristretto255.basePoint; |
| 177 | var buf: [256]u8 = undefined; | 177 | 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"); |
| 179 | 179 | ||
| 180 | var r: [Ristretto255.encoded_length]u8 = undefined; | 180 | var r: [Ristretto255.encoded_length]u8 = undefined; |
| 181 | _ = try fmt.hexToBytes(r[0..], "6a493210f7499cd17fecb510ae0cea23a110e8d5b901f8acadd3095c73a3b919"); | 181 | _ = try fmt.hexToBytes(r[0..], "6a493210f7499cd17fecb510ae0cea23a110e8d5b901f8acadd3095c73a3b919"); |
| 182 | var q = try Ristretto255.fromBytes(r); | 182 | var q = try Ristretto255.fromBytes(r); |
| 183 | q = q.dbl().add(p); | 183 | 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"); |
| 185 | 185 | ||
| 186 | const s = [_]u8{15} ++ [_]u8{0} ** 31; | 186 | const s = [_]u8{15} ++ [_]u8{0} ** 31; |
| 187 | const w = try p.mul(s); | 187 | 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"); |
| 189 | 189 | ||
| 190 | try std.testing.expect(p.dbl().dbl().dbl().dbl().equivalent(w.add(p))); | 190 | try std.testing.expect(p.dbl().dbl().dbl().dbl().equivalent(w.add(p))); |
| 191 | 191 | ||
| 192 | const h = [_]u8{69} ** 32 ++ [_]u8{42} ** 32; | 192 | const h = [_]u8{69} ** 32 ++ [_]u8{42} ** 32; |
| 193 | const ph = Ristretto255.fromUniform(h); | 193 | 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"); |
| 195 | } | 195 | } |
lib/std/crypto/25519/scalar.zig+3-3| ... | @@ -850,10 +850,10 @@ test "scalar25519" { | ... | @@ -850,10 +850,10 @@ test "scalar25519" { |
| 850 | var y = x.toBytes(); | 850 | var y = x.toBytes(); |
| 851 | try rejectNonCanonical(y); | 851 | try rejectNonCanonical(y); |
| 852 | var buf: [128]u8 = undefined; | 852 | 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"); |
| 854 | 854 | ||
| 855 | const reduced = reduce(field_order_s); | 855 | 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"); |
| 857 | } | 857 | } |
| 858 | 858 | ||
| 859 | test "non-canonical scalar25519" { | 859 | test "non-canonical scalar25519" { |
| ... | @@ -867,7 +867,7 @@ test "mulAdd overflow check" { | ... | @@ -867,7 +867,7 @@ test "mulAdd overflow check" { |
| 867 | const c: [32]u8 = [_]u8{0xff} ** 32; | 867 | const c: [32]u8 = [_]u8{0xff} ** 32; |
| 868 | const x = mulAdd(a, b, c); | 868 | const x = mulAdd(a, b, c); |
| 869 | var buf: [128]u8 = undefined; | 869 | 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"); |
| 871 | } | 871 | } |
| 872 | 872 | ||
| 873 | test "scalar field inversion" { | 873 | test "scalar field inversion" { |
lib/std/crypto/chacha20.zig+2-2| ... | @@ -1145,7 +1145,7 @@ test "xchacha20" { | ... | @@ -1145,7 +1145,7 @@ test "xchacha20" { |
| 1145 | var c: [m.len]u8 = undefined; | 1145 | var c: [m.len]u8 = undefined; |
| 1146 | XChaCha20IETF.xor(c[0..], m[0..], 0, key, nonce); | 1146 | XChaCha20IETF.xor(c[0..], m[0..], 0, key, nonce); |
| 1147 | var buf: [2 * c.len]u8 = undefined; | 1147 | 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"); |
| 1149 | } | 1149 | } |
| 1150 | { | 1150 | { |
| 1151 | const ad = "Additional data"; | 1151 | const ad = "Additional data"; |
| ... | @@ -1154,7 +1154,7 @@ test "xchacha20" { | ... | @@ -1154,7 +1154,7 @@ test "xchacha20" { |
| 1154 | var out: [m.len]u8 = undefined; | 1154 | var out: [m.len]u8 = undefined; |
| 1155 | try XChaCha20Poly1305.decrypt(out[0..], c[0..m.len], c[m.len..].*, ad, nonce, key); | 1155 | try XChaCha20Poly1305.decrypt(out[0..], c[0..m.len], c[m.len..].*, ad, nonce, key); |
| 1156 | var buf: [2 * c.len]u8 = undefined; | 1156 | 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"); |
| 1158 | try testing.expectEqualSlices(u8, out[0..], m); | 1158 | try testing.expectEqualSlices(u8, out[0..], m); |
| 1159 | c[0] +%= 1; | 1159 | c[0] +%= 1; |
| 1160 | try testing.expectError(error.AuthenticationFailed, XChaCha20Poly1305.decrypt(out[0..], c[0..m.len], c[m.len..].*, ad, nonce, key)); | 1160 | 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" { | ... | @@ -1741,7 +1741,7 @@ test "NIST KAT test" { |
| 1741 | for (0..100) |i| { | 1741 | for (0..100) |i| { |
| 1742 | g.fill(&seed); | 1742 | g.fill(&seed); |
| 1743 | try std.fmt.format(fw, "count = {}\n", .{i}); | 1743 | 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}); |
| 1745 | var g2 = NistDRBG.init(seed); | 1745 | var g2 = NistDRBG.init(seed); |
| 1746 | 1746 | ||
| 1747 | // This is not equivalent to g2.fill(kseed[:]). As the reference | 1747 | // This is not equivalent to g2.fill(kseed[:]). As the reference |
| ... | @@ -1756,16 +1756,16 @@ test "NIST KAT test" { | ... | @@ -1756,16 +1756,16 @@ test "NIST KAT test" { |
| 1756 | const e = kp.public_key.encaps(eseed); | 1756 | const e = kp.public_key.encaps(eseed); |
| 1757 | const ss2 = try kp.secret_key.decaps(&e.ciphertext); | 1757 | const ss2 = try kp.secret_key.decaps(&e.ciphertext); |
| 1758 | try testing.expectEqual(ss2, e.shared_secret); | 1758 | try testing.expectEqual(ss2, e.shared_secret); |
| 1759 | try std.fmt.format(fw, "pk = {s}\n", .{std.fmt.fmtSliceHexUpper(&kp.public_key.toBytes())}); | 1759 | try std.fmt.format(fw, "pk = {X}\n", .{&kp.public_key.toBytes()}); |
| 1760 | try std.fmt.format(fw, "sk = {s}\n", .{std.fmt.fmtSliceHexUpper(&kp.secret_key.toBytes())}); | 1760 | try std.fmt.format(fw, "sk = {X}\n", .{&kp.secret_key.toBytes()}); |
| 1761 | try std.fmt.format(fw, "ct = {s}\n", .{std.fmt.fmtSliceHexUpper(&e.ciphertext)}); | 1761 | try std.fmt.format(fw, "ct = {X}\n", .{&e.ciphertext}); |
| 1762 | try std.fmt.format(fw, "ss = {s}\n\n", .{std.fmt.fmtSliceHexUpper(&e.shared_secret)}); | 1762 | try std.fmt.format(fw, "ss = {X}\n\n", .{&e.shared_secret}); |
| 1763 | } | 1763 | } |
| 1764 | 1764 | ||
| 1765 | var out: [32]u8 = undefined; | 1765 | var out: [32]u8 = undefined; |
| 1766 | f.final(&out); | 1766 | f.final(&out); |
| 1767 | var outHex: [64]u8 = undefined; | 1767 | var outHex: [64]u8 = undefined; |
| 1768 | _ = try std.fmt.bufPrint(&outHex, "{s}", .{std.fmt.fmtSliceHexLower(&out)}); | 1768 | _ = try std.fmt.bufPrint(&outHex, "{x}", .{&out}); |
| 1769 | try testing.expectEqual(outHex, modeHash[1].*); | 1769 | try testing.expectEqual(outHex, modeHash[1].*); |
| 1770 | } | 1770 | } |
| 1771 | } | 1771 | } |
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 | ... | @@ -1513,10 +1513,10 @@ fn logSecrets(key_log_file: std.fs.File, context: anytype, secrets: anytype) voi |
| 1513 | defer if (locked) key_log_file.unlock(); | 1513 | defer if (locked) key_log_file.unlock(); |
| 1514 | key_log_file.seekFromEnd(0) catch {}; | 1514 | key_log_file.seekFromEnd(0) catch {}; |
| 1515 | inline for (@typeInfo(@TypeOf(secrets)).@"struct".fields) |field| key_log_file.writer().print("{s}" ++ | 1515 | 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} ++ |
| 1517 | (if (@hasField(@TypeOf(context), "counter")) .{context.counter} else .{}) ++ .{ | 1517 | (if (@hasField(@TypeOf(context), "counter")) .{context.counter} else .{}) ++ .{ |
| 1518 | std.fmt.fmtSliceHexLower(context.client_random), | 1518 | context.client_random, |
| 1519 | std.fmt.fmtSliceHexLower(@field(secrets, field.name)), | 1519 | @field(secrets, field.name), |
| 1520 | }) catch {}; | 1520 | }) catch {}; |
| 1521 | } | 1521 | } |
| 1522 | 1522 |
lib/std/debug.zig+110-99| ... | @@ -204,13 +204,23 @@ pub fn unlockStdErr() void { | ... | @@ -204,13 +204,23 @@ pub fn unlockStdErr() void { |
| 204 | std.Progress.unlockStdErr(); | 204 | std.Progress.unlockStdErr(); |
| 205 | } | 205 | } |
| 206 | 206 | ||
| 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. | ||
| 213 | pub fn lockStdErr2() std.io.BufferedWriter { | ||
| 214 | std.Progress.lockStdErr(); | ||
| 215 | return io.getStdErr().unbufferedWriter(); | ||
| 216 | } | ||
| 217 | |||
| 207 | /// Print to stderr, unbuffered, and silently returning on failure. Intended | 218 | /// Print to stderr, unbuffered, and silently returning on failure. Intended |
| 208 | /// for use in "printf debugging." Use `std.log` functions for proper logging. | 219 | /// for use in "printf debugging." Use `std.log` functions for proper logging. |
| 209 | pub fn print(comptime fmt: []const u8, args: anytype) void { | 220 | pub fn print(comptime fmt: []const u8, args: anytype) void { |
| 210 | lockStdErr(); | 221 | var bw = lockStdErr2(); |
| 211 | defer unlockStdErr(); | 222 | defer unlockStdErr(); |
| 212 | const stderr = io.getStdErr().writer(); | 223 | nosuspend bw.print(fmt, args) catch return; |
| 213 | nosuspend stderr.print(fmt, args) catch return; | ||
| 214 | } | 224 | } |
| 215 | 225 | ||
| 216 | pub fn getStderrMutex() *std.Thread.Mutex { | 226 | pub fn getStderrMutex() *std.Thread.Mutex { |
| ... | @@ -265,7 +275,7 @@ fn dumpHexInternal(bytes: []const u8, ttyconf: std.io.tty.Config, writer: anytyp | ... | @@ -265,7 +275,7 @@ fn dumpHexInternal(bytes: []const u8, ttyconf: std.io.tty.Config, writer: anytyp |
| 265 | if (window.len < 16) { | 275 | if (window.len < 16) { |
| 266 | var missing_columns = (16 - window.len) * 3; | 276 | var missing_columns = (16 - window.len) * 3; |
| 267 | if (window.len < 8) missing_columns += 1; | 277 | if (window.len < 8) missing_columns += 1; |
| 268 | try writer.writeByteNTimes(' ', missing_columns); | 278 | try writer.splatByteAll(' ', missing_columns); |
| 269 | } | 279 | } |
| 270 | 280 | ||
| 271 | // 3. Print the characters. | 281 | // 3. Print the characters. |
| ... | @@ -313,30 +323,32 @@ test dumpHexInternal { | ... | @@ -313,30 +323,32 @@ test dumpHexInternal { |
| 313 | } | 323 | } |
| 314 | 324 | ||
| 315 | /// Tries to print the current stack trace to stderr, unbuffered, and ignores any error returned. | 325 | /// Tries to print the current stack trace to stderr, unbuffered, and ignores any error returned. |
| 316 | /// TODO multithreaded awareness | ||
| 317 | pub fn dumpCurrentStackTrace(start_addr: ?usize) void { | 326 | pub fn dumpCurrentStackTrace(start_addr: ?usize) void { |
| 318 | nosuspend { | 327 | var stderr = lockStdErr2(); |
| 319 | if (builtin.target.cpu.arch.isWasm()) { | 328 | defer unlockStdErr(); |
| 320 | if (native_os == .wasi) { | 329 | nosuspend dumpCurrentStackTraceToWriter(start_addr, &stderr) catch return; |
| 321 | const stderr = io.getStdErr().writer(); | 330 | } |
| 322 | stderr.print("Unable to dump stack trace: not implemented for Wasm\n", .{}) catch return; | 331 | |
| 323 | } | 332 | /// Prints the current stack trace to the provided writer. |
| 324 | return; | 333 | pub fn dumpCurrentStackTraceToWriter(start_addr: ?usize, writer: *std.io.BufferedWriter) !void { |
| 325 | } | 334 | if (builtin.target.cpu.arch.isWasm()) { |
| 326 | const stderr = io.getStdErr().writer(); | 335 | if (native_os == .wasi) { |
| 327 | if (builtin.strip_debug_info) { | 336 | try writer.writeAll("Unable to dump stack trace: not implemented for Wasm\n"); |
| 328 | stderr.print("Unable to dump stack trace: debug info stripped\n", .{}) catch return; | ||
| 329 | return; | ||
| 330 | } | 337 | } |
| 331 | const debug_info = getSelfDebugInfo() catch |err| { | 338 | return; |
| 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 | }; | ||
| 339 | } | 339 | } |
| 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 | }; | ||
| 340 | } | 352 | } |
| 341 | 353 | ||
| 342 | pub const have_ucontext = posix.ucontext_t != void; | 354 | pub const have_ucontext = posix.ucontext_t != void; |
| ... | @@ -402,16 +414,14 @@ pub inline fn getContext(context: *ThreadContext) bool { | ... | @@ -402,16 +414,14 @@ pub inline fn getContext(context: *ThreadContext) bool { |
| 402 | /// Tries to print the stack trace starting from the supplied base pointer to stderr, | 414 | /// Tries to print the stack trace starting from the supplied base pointer to stderr, |
| 403 | /// unbuffered, and ignores any error returned. | 415 | /// unbuffered, and ignores any error returned. |
| 404 | /// TODO multithreaded awareness | 416 | /// TODO multithreaded awareness |
| 405 | pub fn dumpStackTraceFromBase(context: *ThreadContext) void { | 417 | pub fn dumpStackTraceFromBase(context: *ThreadContext, stderr: *std.io.BufferedWriter) void { |
| 406 | nosuspend { | 418 | nosuspend { |
| 407 | if (builtin.target.cpu.arch.isWasm()) { | 419 | if (builtin.target.cpu.arch.isWasm()) { |
| 408 | if (native_os == .wasi) { | 420 | if (native_os == .wasi) { |
| 409 | const stderr = io.getStdErr().writer(); | ||
| 410 | stderr.print("Unable to dump stack trace: not implemented for Wasm\n", .{}) catch return; | 421 | stderr.print("Unable to dump stack trace: not implemented for Wasm\n", .{}) catch return; |
| 411 | } | 422 | } |
| 412 | return; | 423 | return; |
| 413 | } | 424 | } |
| 414 | const stderr = io.getStdErr().writer(); | ||
| 415 | if (builtin.strip_debug_info) { | 425 | if (builtin.strip_debug_info) { |
| 416 | stderr.print("Unable to dump stack trace: debug info stripped\n", .{}) catch return; | 426 | stderr.print("Unable to dump stack trace: debug info stripped\n", .{}) catch return; |
| 417 | return; | 427 | return; |
| ... | @@ -510,21 +520,23 @@ pub fn dumpStackTrace(stack_trace: std.builtin.StackTrace) void { | ... | @@ -510,21 +520,23 @@ pub fn dumpStackTrace(stack_trace: std.builtin.StackTrace) void { |
| 510 | nosuspend { | 520 | nosuspend { |
| 511 | if (builtin.target.cpu.arch.isWasm()) { | 521 | if (builtin.target.cpu.arch.isWasm()) { |
| 512 | if (native_os == .wasi) { | 522 | if (native_os == .wasi) { |
| 513 | const stderr = io.getStdErr().writer(); | 523 | var stderr = lockStdErr2(); |
| 514 | stderr.print("Unable to dump stack trace: not implemented for Wasm\n", .{}) catch return; | 524 | defer unlockStdErr(); |
| 525 | stderr.writeAll("Unable to dump stack trace: not implemented for Wasm\n") catch return; | ||
| 515 | } | 526 | } |
| 516 | return; | 527 | return; |
| 517 | } | 528 | } |
| 518 | const stderr = io.getStdErr().writer(); | 529 | var stderr = lockStdErr2(); |
| 530 | defer unlockStdErr(); | ||
| 519 | if (builtin.strip_debug_info) { | 531 | 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; |
| 521 | return; | 533 | return; |
| 522 | } | 534 | } |
| 523 | const debug_info = getSelfDebugInfo() catch |err| { | 535 | const debug_info = getSelfDebugInfo() catch |err| { |
| 524 | stderr.print("Unable to dump stack trace: Unable to open debug info: {s}\n", .{@errorName(err)}) catch return; | 536 | stderr.print("Unable to dump stack trace: Unable to open debug info: {s}\n", .{@errorName(err)}) catch return; |
| 525 | return; | 537 | return; |
| 526 | }; | 538 | }; |
| 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| { |
| 528 | stderr.print("Unable to dump stack trace: {s}\n", .{@errorName(err)}) catch return; | 540 | stderr.print("Unable to dump stack trace: {s}\n", .{@errorName(err)}) catch return; |
| 529 | return; | 541 | return; |
| 530 | }; | 542 | }; |
| ... | @@ -573,14 +585,14 @@ pub fn panicExtra( | ... | @@ -573,14 +585,14 @@ pub fn panicExtra( |
| 573 | const size = 0x1000; | 585 | const size = 0x1000; |
| 574 | const trunc_msg = "(msg truncated)"; | 586 | const trunc_msg = "(msg truncated)"; |
| 575 | var buf: [size + trunc_msg.len]u8 = undefined; | 587 | var buf: [size + trunc_msg.len]u8 = undefined; |
| 588 | var bw: std.io.BufferedWriter = undefined; | ||
| 589 | bw.initFixed(buf[0..size]); | ||
| 576 | // a minor annoyance with this is that it will result in the NoSpaceLeft | 590 | // a minor annoyance with this is that it will result in the NoSpaceLeft |
| 577 | // error being part of the @panic stack trace (but that error should | 591 | // error being part of the @panic stack trace (but that error should |
| 578 | // only happen rarely) | 592 | // only happen rarely) |
| 579 | const msg = std.fmt.bufPrint(buf[0..size], format, args) catch |err| switch (err) { | 593 | const msg = if (bw.print(format, args)) |_| bw.getWritten() else |_| blk: { |
| 580 | error.NoSpaceLeft => blk: { | 594 | @memcpy(buf[size..], trunc_msg); |
| 581 | @memcpy(buf[size..], trunc_msg); | 595 | break :blk &buf; |
| 582 | break :blk &buf; | ||
| 583 | }, | ||
| 584 | }; | 596 | }; |
| 585 | std.builtin.panic.call(msg, ret_addr); | 597 | std.builtin.panic.call(msg, ret_addr); |
| 586 | } | 598 | } |
| ... | @@ -675,10 +687,9 @@ pub fn defaultPanic( | ... | @@ -675,10 +687,9 @@ pub fn defaultPanic( |
| 675 | _ = panicking.fetchAdd(1, .seq_cst); | 687 | _ = panicking.fetchAdd(1, .seq_cst); |
| 676 | 688 | ||
| 677 | { | 689 | { |
| 678 | lockStdErr(); | 690 | var stderr = lockStdErr2(); |
| 679 | defer unlockStdErr(); | 691 | defer unlockStdErr(); |
| 680 | 692 | ||
| 681 | const stderr = io.getStdErr().writer(); | ||
| 682 | if (builtin.single_threaded) { | 693 | if (builtin.single_threaded) { |
| 683 | stderr.print("panic: ", .{}) catch posix.abort(); | 694 | stderr.print("panic: ", .{}) catch posix.abort(); |
| 684 | } else { | 695 | } else { |
| ... | @@ -688,7 +699,7 @@ pub fn defaultPanic( | ... | @@ -688,7 +699,7 @@ pub fn defaultPanic( |
| 688 | stderr.print("{s}\n", .{msg}) catch posix.abort(); | 699 | stderr.print("{s}\n", .{msg}) catch posix.abort(); |
| 689 | 700 | ||
| 690 | if (@errorReturnTrace()) |t| dumpStackTrace(t.*); | 701 | if (@errorReturnTrace()) |t| dumpStackTrace(t.*); |
| 691 | dumpCurrentStackTrace(first_trace_addr orelse @returnAddress()); | 702 | dumpCurrentStackTraceToWriter(first_trace_addr orelse @returnAddress(), &stderr) catch {}; |
| 692 | } | 703 | } |
| 693 | 704 | ||
| 694 | waitForOtherThreadToFinishPanicking(); | 705 | waitForOtherThreadToFinishPanicking(); |
| ... | @@ -723,7 +734,7 @@ fn waitForOtherThreadToFinishPanicking() void { | ... | @@ -723,7 +734,7 @@ fn waitForOtherThreadToFinishPanicking() void { |
| 723 | 734 | ||
| 724 | pub fn writeStackTrace( | 735 | pub fn writeStackTrace( |
| 725 | stack_trace: std.builtin.StackTrace, | 736 | stack_trace: std.builtin.StackTrace, |
| 726 | out_stream: anytype, | 737 | writer: *std.io.BufferedWriter, |
| 727 | debug_info: *SelfInfo, | 738 | debug_info: *SelfInfo, |
| 728 | tty_config: io.tty.Config, | 739 | tty_config: io.tty.Config, |
| 729 | ) !void { | 740 | ) !void { |
| ... | @@ -736,15 +747,15 @@ pub fn writeStackTrace( | ... | @@ -736,15 +747,15 @@ pub fn writeStackTrace( |
| 736 | frame_index = (frame_index + 1) % stack_trace.instruction_addresses.len; | 747 | frame_index = (frame_index + 1) % stack_trace.instruction_addresses.len; |
| 737 | }) { | 748 | }) { |
| 738 | const return_address = stack_trace.instruction_addresses[frame_index]; | 749 | 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); |
| 740 | } | 751 | } |
| 741 | 752 | ||
| 742 | if (stack_trace.index > stack_trace.instruction_addresses.len) { | 753 | if (stack_trace.index > stack_trace.instruction_addresses.len) { |
| 743 | const dropped_frames = stack_trace.index - stack_trace.instruction_addresses.len; | 754 | const dropped_frames = stack_trace.index - stack_trace.instruction_addresses.len; |
| 744 | 755 | ||
| 745 | tty_config.setColor(out_stream, .bold) catch {}; | 756 | tty_config.setColor(writer, .bold) catch {}; |
| 746 | try out_stream.print("({d} additional stack frames skipped...)\n", .{dropped_frames}); | 757 | try writer.print("({d} additional stack frames skipped...)\n", .{dropped_frames}); |
| 747 | tty_config.setColor(out_stream, .reset) catch {}; | 758 | tty_config.setColor(writer, .reset) catch {}; |
| 748 | } | 759 | } |
| 749 | } | 760 | } |
| 750 | 761 | ||
| ... | @@ -954,7 +965,7 @@ pub const StackIterator = struct { | ... | @@ -954,7 +965,7 @@ pub const StackIterator = struct { |
| 954 | }; | 965 | }; |
| 955 | 966 | ||
| 956 | pub fn writeCurrentStackTrace( | 967 | pub fn writeCurrentStackTrace( |
| 957 | out_stream: anytype, | 968 | writer: *std.io.BufferedWriter, |
| 958 | debug_info: *SelfInfo, | 969 | debug_info: *SelfInfo, |
| 959 | tty_config: io.tty.Config, | 970 | tty_config: io.tty.Config, |
| 960 | start_addr: ?usize, | 971 | start_addr: ?usize, |
| ... | @@ -962,7 +973,7 @@ pub fn writeCurrentStackTrace( | ... | @@ -962,7 +973,7 @@ pub fn writeCurrentStackTrace( |
| 962 | if (native_os == .windows) { | 973 | if (native_os == .windows) { |
| 963 | var context: ThreadContext = undefined; | 974 | var context: ThreadContext = undefined; |
| 964 | assert(getContext(&context)); | 975 | 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); |
| 966 | } | 977 | } |
| 967 | var context: ThreadContext = undefined; | 978 | var context: ThreadContext = undefined; |
| 968 | const has_context = getContext(&context); | 979 | const has_context = getContext(&context); |
| ... | @@ -973,7 +984,7 @@ pub fn writeCurrentStackTrace( | ... | @@ -973,7 +984,7 @@ pub fn writeCurrentStackTrace( |
| 973 | defer it.deinit(); | 984 | defer it.deinit(); |
| 974 | 985 | ||
| 975 | while (it.next()) |return_address| { | 986 | while (it.next()) |return_address| { |
| 976 | printLastUnwindError(&it, debug_info, out_stream, tty_config); | 987 | printLastUnwindError(&it, debug_info, writer, tty_config); |
| 977 | 988 | ||
| 978 | // On arm64 macOS, the address of the last frame is 0x0 rather than 0x1 as on x86_64 macOS, | 989 | // On arm64 macOS, the address of the last frame is 0x0 rather than 0x1 as on x86_64 macOS, |
| 979 | // therefore, we do a check for `return_address == 0` before subtracting 1 from it to avoid | 990 | // therefore, we do a check for `return_address == 0` before subtracting 1 from it to avoid |
| ... | @@ -981,8 +992,8 @@ pub fn writeCurrentStackTrace( | ... | @@ -981,8 +992,8 @@ pub fn writeCurrentStackTrace( |
| 981 | // condition on the subsequent iteration and return `null` thus terminating the loop. | 992 | // condition on the subsequent iteration and return `null` thus terminating the loop. |
| 982 | // same behaviour for x86-windows-msvc | 993 | // same behaviour for x86-windows-msvc |
| 983 | const address = return_address -| 1; | 994 | const address = return_address -| 1; |
| 984 | try printSourceAtAddress(debug_info, out_stream, address, tty_config); | 995 | try printSourceAtAddress(debug_info, writer, address, tty_config); |
| 985 | } else printLastUnwindError(&it, debug_info, out_stream, tty_config); | 996 | } else printLastUnwindError(&it, debug_info, writer, tty_config); |
| 986 | } | 997 | } |
| 987 | 998 | ||
| 988 | pub noinline fn walkStackWindows(addresses: []usize, existing_context: ?*const windows.CONTEXT) usize { | 999 | pub 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 | ... | @@ -1042,7 +1053,7 @@ pub noinline fn walkStackWindows(addresses: []usize, existing_context: ?*const w |
| 1042 | } | 1053 | } |
| 1043 | 1054 | ||
| 1044 | pub fn writeStackTraceWindows( | 1055 | pub fn writeStackTraceWindows( |
| 1045 | out_stream: anytype, | 1056 | writer: *std.io.BufferedWriter, |
| 1046 | debug_info: *SelfInfo, | 1057 | debug_info: *SelfInfo, |
| 1047 | tty_config: io.tty.Config, | 1058 | tty_config: io.tty.Config, |
| 1048 | context: *const windows.CONTEXT, | 1059 | context: *const windows.CONTEXT, |
| ... | @@ -1058,14 +1069,14 @@ pub fn writeStackTraceWindows( | ... | @@ -1058,14 +1069,14 @@ pub fn writeStackTraceWindows( |
| 1058 | return; | 1069 | return; |
| 1059 | } else 0; | 1070 | } else 0; |
| 1060 | for (addrs[start_i..]) |addr| { | 1071 | 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); |
| 1062 | } | 1073 | } |
| 1063 | } | 1074 | } |
| 1064 | 1075 | ||
| 1065 | fn printUnknownSource(debug_info: *SelfInfo, out_stream: anytype, address: usize, tty_config: io.tty.Config) !void { | 1076 | fn printUnknownSource(debug_info: *SelfInfo, writer: *std.io.BufferedWriter, address: usize, tty_config: io.tty.Config) !void { |
| 1066 | const module_name = debug_info.getModuleNameForAddress(address); | 1077 | const module_name = debug_info.getModuleNameForAddress(address); |
| 1067 | return printLineInfo( | 1078 | return printLineInfo( |
| 1068 | out_stream, | 1079 | writer, |
| 1069 | null, | 1080 | null, |
| 1070 | address, | 1081 | address, |
| 1071 | "???", | 1082 | "???", |
| ... | @@ -1075,38 +1086,38 @@ fn printUnknownSource(debug_info: *SelfInfo, out_stream: anytype, address: usize | ... | @@ -1075,38 +1086,38 @@ fn printUnknownSource(debug_info: *SelfInfo, out_stream: anytype, address: usize |
| 1075 | ); | 1086 | ); |
| 1076 | } | 1087 | } |
| 1077 | 1088 | ||
| 1078 | fn printLastUnwindError(it: *StackIterator, debug_info: *SelfInfo, out_stream: anytype, tty_config: io.tty.Config) void { | 1089 | fn printLastUnwindError(it: *StackIterator, debug_info: *SelfInfo, writer: *std.io.BufferedWriter, tty_config: io.tty.Config) void { |
| 1079 | if (!have_ucontext) return; | 1090 | if (!have_ucontext) return; |
| 1080 | if (it.getLastError()) |unwind_error| { | 1091 | 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 {}; |
| 1082 | } | 1093 | } |
| 1083 | } | 1094 | } |
| 1084 | 1095 | ||
| 1085 | fn printUnwindError(debug_info: *SelfInfo, out_stream: anytype, address: usize, err: UnwindError, tty_config: io.tty.Config) !void { | 1096 | fn printUnwindError(debug_info: *SelfInfo, writer: *std.io.BufferedWriter, address: usize, err: UnwindError, tty_config: io.tty.Config) !void { |
| 1086 | const module_name = debug_info.getModuleNameForAddress(address) orelse "???"; | 1097 | const module_name = debug_info.getModuleNameForAddress(address) orelse "???"; |
| 1087 | try tty_config.setColor(out_stream, .dim); | 1098 | try tty_config.setColor(writer, .dim); |
| 1088 | if (err == error.MissingDebugInfo) { | 1099 | 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 }); |
| 1090 | } else { | 1101 | } 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 }); |
| 1092 | } | 1103 | } |
| 1093 | try tty_config.setColor(out_stream, .reset); | 1104 | try tty_config.setColor(writer, .reset); |
| 1094 | } | 1105 | } |
| 1095 | 1106 | ||
| 1096 | pub fn printSourceAtAddress(debug_info: *SelfInfo, out_stream: anytype, address: usize, tty_config: io.tty.Config) !void { | 1107 | pub fn printSourceAtAddress(debug_info: *SelfInfo, writer: *std.io.BufferedWriter, address: usize, tty_config: io.tty.Config) !void { |
| 1097 | const module = debug_info.getModuleForAddress(address) catch |err| switch (err) { | 1108 | 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), |
| 1099 | else => return err, | 1110 | else => return err, |
| 1100 | }; | 1111 | }; |
| 1101 | 1112 | ||
| 1102 | const symbol_info = module.getSymbolAtAddress(debug_info.allocator, address) catch |err| switch (err) { | 1113 | 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), |
| 1104 | else => return err, | 1115 | else => return err, |
| 1105 | }; | 1116 | }; |
| 1106 | defer if (symbol_info.source_location) |sl| debug_info.allocator.free(sl.file_name); | 1117 | defer if (symbol_info.source_location) |sl| debug_info.allocator.free(sl.file_name); |
| 1107 | 1118 | ||
| 1108 | return printLineInfo( | 1119 | return printLineInfo( |
| 1109 | out_stream, | 1120 | writer, |
| 1110 | symbol_info.source_location, | 1121 | symbol_info.source_location, |
| 1111 | address, | 1122 | address, |
| 1112 | symbol_info.name, | 1123 | symbol_info.name, |
| ... | @@ -1117,7 +1128,7 @@ pub fn printSourceAtAddress(debug_info: *SelfInfo, out_stream: anytype, address: | ... | @@ -1117,7 +1128,7 @@ pub fn printSourceAtAddress(debug_info: *SelfInfo, out_stream: anytype, address: |
| 1117 | } | 1128 | } |
| 1118 | 1129 | ||
| 1119 | fn printLineInfo( | 1130 | fn printLineInfo( |
| 1120 | out_stream: anytype, | 1131 | writer: *std.io.BufferedWriter, |
| 1121 | source_location: ?SourceLocation, | 1132 | source_location: ?SourceLocation, |
| 1122 | address: usize, | 1133 | address: usize, |
| 1123 | symbol_name: []const u8, | 1134 | symbol_name: []const u8, |
| ... | @@ -1126,34 +1137,34 @@ fn printLineInfo( | ... | @@ -1126,34 +1137,34 @@ fn printLineInfo( |
| 1126 | comptime printLineFromFile: anytype, | 1137 | comptime printLineFromFile: anytype, |
| 1127 | ) !void { | 1138 | ) !void { |
| 1128 | nosuspend { | 1139 | nosuspend { |
| 1129 | try tty_config.setColor(out_stream, .bold); | 1140 | try tty_config.setColor(writer, .bold); |
| 1130 | 1141 | ||
| 1131 | if (source_location) |*sl| { | 1142 | 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 }); |
| 1133 | } else { | 1144 | } else { |
| 1134 | try out_stream.writeAll("???:?:?"); | 1145 | try writer.writeAll("???:?:?"); |
| 1135 | } | 1146 | } |
| 1136 | 1147 | ||
| 1137 | try tty_config.setColor(out_stream, .reset); | 1148 | try tty_config.setColor(writer, .reset); |
| 1138 | try out_stream.writeAll(": "); | 1149 | try writer.writeAll(": "); |
| 1139 | try tty_config.setColor(out_stream, .dim); | 1150 | try tty_config.setColor(writer, .dim); |
| 1140 | try out_stream.print("0x{x} in {s} ({s})", .{ address, symbol_name, compile_unit_name }); | 1151 | try writer.print("0x{x} in {s} ({s})", .{ address, symbol_name, compile_unit_name }); |
| 1141 | try tty_config.setColor(out_stream, .reset); | 1152 | try tty_config.setColor(writer, .reset); |
| 1142 | try out_stream.writeAll("\n"); | 1153 | try writer.writeAll("\n"); |
| 1143 | 1154 | ||
| 1144 | // Show the matching source code line if possible | 1155 | // Show the matching source code line if possible |
| 1145 | if (source_location) |sl| { | 1156 | if (source_location) |sl| { |
| 1146 | if (printLineFromFile(out_stream, sl)) { | 1157 | if (printLineFromFile(writer, sl)) { |
| 1147 | if (sl.column > 0) { | 1158 | if (sl.column > 0) { |
| 1148 | // The caret already takes one char | 1159 | // The caret already takes one char |
| 1149 | const space_needed = @as(usize, @intCast(sl.column - 1)); | 1160 | const space_needed = @as(usize, @intCast(sl.column - 1)); |
| 1150 | 1161 | ||
| 1151 | try out_stream.writeByteNTimes(' ', space_needed); | 1162 | try writer.splatByteAll(' ', space_needed); |
| 1152 | try tty_config.setColor(out_stream, .green); | 1163 | try tty_config.setColor(writer, .green); |
| 1153 | try out_stream.writeAll("^"); | 1164 | try writer.writeAll("^"); |
| 1154 | try tty_config.setColor(out_stream, .reset); | 1165 | try tty_config.setColor(writer, .reset); |
| 1155 | } | 1166 | } |
| 1156 | try out_stream.writeAll("\n"); | 1167 | try writer.writeAll("\n"); |
| 1157 | } else |err| switch (err) { | 1168 | } else |err| switch (err) { |
| 1158 | error.EndOfFile, error.FileNotFound => {}, | 1169 | error.EndOfFile, error.FileNotFound => {}, |
| 1159 | error.BadPathName => {}, | 1170 | error.BadPathName => {}, |
| ... | @@ -1164,7 +1175,7 @@ fn printLineInfo( | ... | @@ -1164,7 +1175,7 @@ fn printLineInfo( |
| 1164 | } | 1175 | } |
| 1165 | } | 1176 | } |
| 1166 | 1177 | ||
| 1167 | fn printLineFromFileAnyOs(out_stream: anytype, source_location: SourceLocation) !void { | 1178 | fn printLineFromFileAnyOs(writer: *std.io.BufferedWriter, source_location: SourceLocation) !void { |
| 1168 | // Need this to always block even in async I/O mode, because this could potentially | 1179 | // Need this to always block even in async I/O mode, because this could potentially |
| 1169 | // be called from e.g. the event loop code crashing. | 1180 | // be called from e.g. the event loop code crashing. |
| 1170 | var f = try fs.cwd().openFile(source_location.file_name, .{}); | 1181 | var f = try fs.cwd().openFile(source_location.file_name, .{}); |
| ... | @@ -1197,24 +1208,24 @@ fn printLineFromFileAnyOs(out_stream: anytype, source_location: SourceLocation) | ... | @@ -1197,24 +1208,24 @@ fn printLineFromFileAnyOs(out_stream: anytype, source_location: SourceLocation) |
| 1197 | if (mem.indexOfScalar(u8, slice, '\n')) |pos| { | 1208 | if (mem.indexOfScalar(u8, slice, '\n')) |pos| { |
| 1198 | const line = slice[0 .. pos + 1]; | 1209 | const line = slice[0 .. pos + 1]; |
| 1199 | mem.replaceScalar(u8, line, '\t', ' '); | 1210 | mem.replaceScalar(u8, line, '\t', ' '); |
| 1200 | return out_stream.writeAll(line); | 1211 | return writer.writeAll(line); |
| 1201 | } else { // Line is the last inside the buffer, and requires another read to find delimiter. Alternatively the file ends. | 1212 | } else { // Line is the last inside the buffer, and requires another read to find delimiter. Alternatively the file ends. |
| 1202 | mem.replaceScalar(u8, slice, '\t', ' '); | 1213 | mem.replaceScalar(u8, slice, '\t', ' '); |
| 1203 | try out_stream.writeAll(slice); | 1214 | try writer.writeAll(slice); |
| 1204 | while (amt_read == buf.len) { | 1215 | while (amt_read == buf.len) { |
| 1205 | amt_read = try f.read(buf[0..]); | 1216 | amt_read = try f.read(buf[0..]); |
| 1206 | if (mem.indexOfScalar(u8, buf[0..amt_read], '\n')) |pos| { | 1217 | if (mem.indexOfScalar(u8, buf[0..amt_read], '\n')) |pos| { |
| 1207 | const line = buf[0 .. pos + 1]; | 1218 | const line = buf[0 .. pos + 1]; |
| 1208 | mem.replaceScalar(u8, line, '\t', ' '); | 1219 | mem.replaceScalar(u8, line, '\t', ' '); |
| 1209 | return out_stream.writeAll(line); | 1220 | return writer.writeAll(line); |
| 1210 | } else { | 1221 | } else { |
| 1211 | const line = buf[0..amt_read]; | 1222 | const line = buf[0..amt_read]; |
| 1212 | mem.replaceScalar(u8, line, '\t', ' '); | 1223 | mem.replaceScalar(u8, line, '\t', ' '); |
| 1213 | try out_stream.writeAll(line); | 1224 | try writer.writeAll(line); |
| 1214 | } | 1225 | } |
| 1215 | } | 1226 | } |
| 1216 | // Make sure printing last line of file inserts extra newline | 1227 | // Make sure printing last line of file inserts extra newline |
| 1217 | try out_stream.writeByte('\n'); | 1228 | try writer.writeByte('\n'); |
| 1218 | } | 1229 | } |
| 1219 | } | 1230 | } |
| 1220 | 1231 | ||
| ... | @@ -1274,9 +1285,9 @@ test printLineFromFileAnyOs { | ... | @@ -1274,9 +1285,9 @@ test printLineFromFileAnyOs { |
| 1274 | 1285 | ||
| 1275 | const overlap = 10; | 1286 | const overlap = 10; |
| 1276 | var writer = file.writer(); | 1287 | 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); |
| 1278 | try writer.writeByte('\n'); | 1289 | try writer.writeByte('\n'); |
| 1279 | try writer.writeByteNTimes('a', overlap); | 1290 | try writer.splatByteAll('a', overlap); |
| 1280 | 1291 | ||
| 1281 | try printLineFromFileAnyOs(output_stream, .{ .file_name = path, .line = 2, .column = 0 }); | 1292 | try printLineFromFileAnyOs(output_stream, .{ .file_name = path, .line = 2, .column = 0 }); |
| 1282 | try expectEqualStrings(("a" ** overlap) ++ "\n", output.items); | 1293 | try expectEqualStrings(("a" ** overlap) ++ "\n", output.items); |
| ... | @@ -1289,7 +1300,7 @@ test printLineFromFileAnyOs { | ... | @@ -1289,7 +1300,7 @@ test printLineFromFileAnyOs { |
| 1289 | defer allocator.free(path); | 1300 | defer allocator.free(path); |
| 1290 | 1301 | ||
| 1291 | var writer = file.writer(); | 1302 | var writer = file.writer(); |
| 1292 | try writer.writeByteNTimes('a', std.heap.page_size_max); | 1303 | try writer.splatByteAll('a', std.heap.page_size_max); |
| 1293 | 1304 | ||
| 1294 | try printLineFromFileAnyOs(output_stream, .{ .file_name = path, .line = 1, .column = 0 }); | 1305 | try printLineFromFileAnyOs(output_stream, .{ .file_name = path, .line = 1, .column = 0 }); |
| 1295 | try expectEqualStrings(("a" ** std.heap.page_size_max) ++ "\n", output.items); | 1306 | try expectEqualStrings(("a" ** std.heap.page_size_max) ++ "\n", output.items); |
| ... | @@ -1302,7 +1313,7 @@ test printLineFromFileAnyOs { | ... | @@ -1302,7 +1313,7 @@ test printLineFromFileAnyOs { |
| 1302 | defer allocator.free(path); | 1313 | defer allocator.free(path); |
| 1303 | 1314 | ||
| 1304 | var writer = file.writer(); | 1315 | 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); |
| 1306 | 1317 | ||
| 1307 | try expectError(error.EndOfFile, printLineFromFileAnyOs(output_stream, .{ .file_name = path, .line = 2, .column = 0 })); | 1318 | try expectError(error.EndOfFile, printLineFromFileAnyOs(output_stream, .{ .file_name = path, .line = 2, .column = 0 })); |
| 1308 | 1319 | ||
| ... | @@ -1328,7 +1339,7 @@ test printLineFromFileAnyOs { | ... | @@ -1328,7 +1339,7 @@ test printLineFromFileAnyOs { |
| 1328 | 1339 | ||
| 1329 | var writer = file.writer(); | 1340 | var writer = file.writer(); |
| 1330 | const real_file_start = 3 * std.heap.page_size_min; | 1341 | 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); |
| 1332 | try writer.writeAll("abc\ndef"); | 1343 | try writer.writeAll("abc\ndef"); |
| 1333 | 1344 | ||
| 1334 | try printLineFromFileAnyOs(output_stream, .{ .file_name = path, .line = real_file_start + 1, .column = 0 }); | 1345 | 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 | ... | @@ -1461,7 +1472,7 @@ fn handleSegfaultPosix(sig: i32, info: *const posix.siginfo_t, ctx_ptr: ?*anyopa |
| 1461 | } | 1472 | } |
| 1462 | 1473 | ||
| 1463 | fn dumpSegfaultInfoPosix(sig: i32, code: i32, addr: usize, ctx_ptr: ?*anyopaque) void { | 1474 | fn dumpSegfaultInfoPosix(sig: i32, code: i32, addr: usize, ctx_ptr: ?*anyopaque) void { |
| 1464 | const stderr = io.getStdErr().writer(); | 1475 | var stderr = io.getStdErr().unbufferedWriter(); |
| 1465 | _ = switch (sig) { | 1476 | _ = switch (sig) { |
| 1466 | posix.SIG.SEGV => if (native_arch == .x86_64 and native_os == .linux and code == 128) // SI_KERNEL | 1477 | posix.SIG.SEGV => if (native_arch == .x86_64 and native_os == .linux and code == 128) // SI_KERNEL |
| 1467 | // x86_64 doesn't have a full 64-bit virtual address space. | 1478 | // 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) | ... | @@ -1471,7 +1482,7 @@ fn dumpSegfaultInfoPosix(sig: i32, code: i32, addr: usize, ctx_ptr: ?*anyopaque) |
| 1471 | // but can also happen when no addressable memory is involved; | 1482 | // but can also happen when no addressable memory is involved; |
| 1472 | // for example when reading/writing model-specific registers | 1483 | // for example when reading/writing model-specific registers |
| 1473 | // by executing `rdmsr` or `wrmsr` in user-space (unprivileged mode). | 1484 | // 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") |
| 1475 | else | 1486 | else |
| 1476 | stderr.print("Segmentation fault at address 0x{x}\n", .{addr}), | 1487 | stderr.print("Segmentation fault at address 0x{x}\n", .{addr}), |
| 1477 | posix.SIG.ILL => stderr.print("Illegal instruction at address 0x{x}\n", .{addr}), | 1488 | 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) | ... | @@ -1509,7 +1520,7 @@ fn dumpSegfaultInfoPosix(sig: i32, code: i32, addr: usize, ctx_ptr: ?*anyopaque) |
| 1509 | }, @ptrCast(ctx)).__mcontext_data; | 1520 | }, @ptrCast(ctx)).__mcontext_data; |
| 1510 | } | 1521 | } |
| 1511 | relocateContext(&new_ctx); | 1522 | relocateContext(&new_ctx); |
| 1512 | dumpStackTraceFromBase(&new_ctx); | 1523 | dumpStackTraceFromBase(&new_ctx, &stderr); |
| 1513 | }, | 1524 | }, |
| 1514 | else => {}, | 1525 | else => {}, |
| 1515 | } | 1526 | } |
| ... | @@ -1557,7 +1568,7 @@ fn handleSegfaultWindowsExtra(info: *windows.EXCEPTION_POINTERS, msg: u8, label: | ... | @@ -1557,7 +1568,7 @@ fn handleSegfaultWindowsExtra(info: *windows.EXCEPTION_POINTERS, msg: u8, label: |
| 1557 | } | 1568 | } |
| 1558 | 1569 | ||
| 1559 | fn dumpSegfaultInfoWindows(info: *windows.EXCEPTION_POINTERS, msg: u8, label: ?[]const u8) void { | 1570 | fn dumpSegfaultInfoWindows(info: *windows.EXCEPTION_POINTERS, msg: u8, label: ?[]const u8) void { |
| 1560 | const stderr = io.getStdErr().writer(); | 1571 | var stderr = io.getStdErr().unbufferedWriter(); |
| 1561 | _ = switch (msg) { | 1572 | _ = switch (msg) { |
| 1562 | 0 => stderr.print("{s}\n", .{label.?}), | 1573 | 0 => stderr.print("{s}\n", .{label.?}), |
| 1563 | 1 => stderr.print("Segmentation fault at address 0x{x}\n", .{info.ExceptionRecord.ExceptionInformation[1]}), | 1574 | 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: ?[ | ... | @@ -1565,7 +1576,7 @@ fn dumpSegfaultInfoWindows(info: *windows.EXCEPTION_POINTERS, msg: u8, label: ?[ |
| 1565 | else => unreachable, | 1576 | else => unreachable, |
| 1566 | } catch posix.abort(); | 1577 | } catch posix.abort(); |
| 1567 | 1578 | ||
| 1568 | dumpStackTraceFromBase(info.ContextRecord); | 1579 | dumpStackTraceFromBase(info.ContextRecord, &stderr); |
| 1569 | } | 1580 | } |
| 1570 | 1581 | ||
| 1571 | pub fn dumpStackPointerAddr(prefix: []const u8) void { | 1582 | pub fn dumpStackPointerAddr(prefix: []const u8) void { |
| ... | @@ -1688,7 +1699,7 @@ pub fn ConfigurableTrace(comptime size: usize, comptime stack_frame_count: usize | ... | @@ -1688,7 +1699,7 @@ pub fn ConfigurableTrace(comptime size: usize, comptime stack_frame_count: usize |
| 1688 | t: @This(), | 1699 | t: @This(), |
| 1689 | comptime fmt: []const u8, | 1700 | comptime fmt: []const u8, |
| 1690 | options: std.fmt.FormatOptions, | 1701 | options: std.fmt.FormatOptions, |
| 1691 | writer: anytype, | 1702 | writer: *std.io.BufferedWriter, |
| 1692 | ) !void { | 1703 | ) !void { |
| 1693 | if (fmt.len != 0) std.fmt.invalidFmtError(fmt, t); | 1704 | if (fmt.len != 0) std.fmt.invalidFmtError(fmt, t); |
| 1694 | _ = options; | 1705 | _ = options; |
lib/std/debug/Dwarf.zig+4-12| ... | @@ -2235,7 +2235,7 @@ pub const ElfModule = struct { | ... | @@ -2235,7 +2235,7 @@ pub const ElfModule = struct { |
| 2235 | 2235 | ||
| 2236 | const section_bytes = try chopSlice(mapped_mem, shdr.sh_offset, shdr.sh_size); | 2236 | const section_bytes = try chopSlice(mapped_mem, shdr.sh_offset, shdr.sh_size); |
| 2237 | sections[section_index.?] = if ((shdr.sh_flags & elf.SHF_COMPRESSED) > 0) blk: { | 2237 | 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 }; |
| 2239 | const section_reader = section_stream.reader(); | 2239 | const section_reader = section_stream.reader(); |
| 2240 | const chdr = section_reader.readStruct(elf.Chdr) catch continue; | 2240 | const chdr = section_reader.readStruct(elf.Chdr) catch continue; |
| 2241 | if (chdr.ch_type != .ZLIB) continue; | 2241 | if (chdr.ch_type != .ZLIB) continue; |
| ... | @@ -2302,11 +2302,7 @@ pub const ElfModule = struct { | ... | @@ -2302,11 +2302,7 @@ pub const ElfModule = struct { |
| 2302 | }; | 2302 | }; |
| 2303 | defer debuginfod_dir.close(); | 2303 | defer debuginfod_dir.close(); |
| 2304 | 2304 | ||
| 2305 | const filename = std.fmt.allocPrint( | 2305 | const filename = std.fmt.allocPrint(gpa, "{x}/debuginfo", .{id}) catch break :blk; |
| 2306 | gpa, | ||
| 2307 | "{s}/debuginfo", | ||
| 2308 | .{std.fmt.fmtSliceHexLower(id)}, | ||
| 2309 | ) catch break :blk; | ||
| 2310 | defer gpa.free(filename); | 2306 | defer gpa.free(filename); |
| 2311 | 2307 | ||
| 2312 | const path: Path = .{ | 2308 | const path: Path = .{ |
| ... | @@ -2330,12 +2326,8 @@ pub const ElfModule = struct { | ... | @@ -2330,12 +2326,8 @@ pub const ElfModule = struct { |
| 2330 | var id_prefix_buf: [2]u8 = undefined; | 2326 | var id_prefix_buf: [2]u8 = undefined; |
| 2331 | var filename_buf: [38 + extension.len]u8 = undefined; | 2327 | var filename_buf: [38 + extension.len]u8 = undefined; |
| 2332 | 2328 | ||
| 2333 | _ = std.fmt.bufPrint(&id_prefix_buf, "{s}", .{std.fmt.fmtSliceHexLower(id[0..1])}) catch unreachable; | 2329 | _ = std.fmt.bufPrint(&id_prefix_buf, "{x}", .{id[0..1]}) catch unreachable; |
| 2334 | const filename = std.fmt.bufPrint( | 2330 | const filename = std.fmt.bufPrint(&filename_buf, "{x}" ++ extension, .{id[1..]}) catch break :blk; |
| 2335 | &filename_buf, | ||
| 2336 | "{s}" ++ extension, | ||
| 2337 | .{std.fmt.fmtSliceHexLower(id[1..])}, | ||
| 2338 | ) catch break :blk; | ||
| 2339 | 2331 | ||
| 2340 | for (global_debug_directories) |global_directory| { | 2332 | for (global_debug_directories) |global_directory| { |
| 2341 | const path: Path = .{ | 2333 | const path: Path = .{ |
lib/std/debug/Dwarf/call_frame.zig+2-2| ... | @@ -51,7 +51,7 @@ const Opcode = enum(u8) { | ... | @@ -51,7 +51,7 @@ const Opcode = enum(u8) { |
| 51 | pub const hi_user = 0x3f; | 51 | pub const hi_user = 0x3f; |
| 52 | }; | 52 | }; |
| 53 | 53 | ||
| 54 | fn readBlock(stream: *std.io.FixedBufferStream([]const u8)) ![]const u8 { | 54 | fn readBlock(stream: *std.io.FixedBufferStream) ![]const u8 { |
| 55 | const reader = stream.reader(); | 55 | const reader = stream.reader(); |
| 56 | const block_len = try leb.readUleb128(usize, reader); | 56 | const block_len = try leb.readUleb128(usize, reader); |
| 57 | if (stream.pos + block_len > stream.buffer.len) return error.InvalidOperand; | 57 | if (stream.pos + block_len > stream.buffer.len) return error.InvalidOperand; |
| ... | @@ -147,7 +147,7 @@ pub const Instruction = union(Opcode) { | ... | @@ -147,7 +147,7 @@ pub const Instruction = union(Opcode) { |
| 147 | }, | 147 | }, |
| 148 | 148 | ||
| 149 | pub fn read( | 149 | pub fn read( |
| 150 | stream: *std.io.FixedBufferStream([]const u8), | 150 | stream: *std.io.FixedBufferStream, |
| 151 | addr_size_bytes: u8, | 151 | addr_size_bytes: u8, |
| 152 | endian: std.builtin.Endian, | 152 | endian: std.builtin.Endian, |
| 153 | ) !Instruction { | 153 | ) !Instruction { |
lib/std/debug/Dwarf/expression.zig+4-4| ... | @@ -178,7 +178,7 @@ pub fn StackMachine(comptime options: Options) type { | ... | @@ -178,7 +178,7 @@ pub fn StackMachine(comptime options: Options) type { |
| 178 | } | 178 | } |
| 179 | } | 179 | } |
| 180 | 180 | ||
| 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 { |
| 182 | const reader = stream.reader(); | 182 | const reader = stream.reader(); |
| 183 | return switch (opcode) { | 183 | return switch (opcode) { |
| 184 | OP.addr => generic(try reader.readInt(addr_type, options.endian)), | 184 | OP.addr => generic(try reader.readInt(addr_type, options.endian)), |
| ... | @@ -293,7 +293,7 @@ pub fn StackMachine(comptime options: Options) type { | ... | @@ -293,7 +293,7 @@ pub fn StackMachine(comptime options: Options) type { |
| 293 | initial_value: ?usize, | 293 | initial_value: ?usize, |
| 294 | ) Error!?Value { | 294 | ) Error!?Value { |
| 295 | if (initial_value) |i| try self.stack.append(allocator, .{ .generic = i }); | 295 | 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 }; |
| 297 | while (try self.step(&stream, allocator, context)) {} | 297 | while (try self.step(&stream, allocator, context)) {} |
| 298 | if (self.stack.items.len == 0) return null; | 298 | if (self.stack.items.len == 0) return null; |
| 299 | return self.stack.items[self.stack.items.len - 1]; | 299 | return self.stack.items[self.stack.items.len - 1]; |
| ... | @@ -302,7 +302,7 @@ pub fn StackMachine(comptime options: Options) type { | ... | @@ -302,7 +302,7 @@ pub fn StackMachine(comptime options: Options) type { |
| 302 | /// Reads an opcode and its operands from `stream`, then executes it | 302 | /// Reads an opcode and its operands from `stream`, then executes it |
| 303 | pub fn step( | 303 | pub fn step( |
| 304 | self: *Self, | 304 | self: *Self, |
| 305 | stream: *std.io.FixedBufferStream([]const u8), | 305 | stream: *std.io.FixedBufferStream, |
| 306 | allocator: std.mem.Allocator, | 306 | allocator: std.mem.Allocator, |
| 307 | context: Context, | 307 | context: Context, |
| 308 | ) Error!bool { | 308 | ) Error!bool { |
| ... | @@ -756,7 +756,7 @@ pub fn StackMachine(comptime options: Options) type { | ... | @@ -756,7 +756,7 @@ pub fn StackMachine(comptime options: Options) type { |
| 756 | if (isOpcodeRegisterLocation(block[0])) { | 756 | if (isOpcodeRegisterLocation(block[0])) { |
| 757 | if (context.thread_context == null) return error.IncompleteExpressionContext; | 757 | if (context.thread_context == null) return error.IncompleteExpressionContext; |
| 758 | 758 | ||
| 759 | var block_stream = std.io.fixedBufferStream(block); | 759 | var block_stream: std.io.FixedBufferStream = .{ .buffer = block }; |
| 760 | const register = (try readOperand(&block_stream, block[0], context)).?.register; | 760 | const register = (try readOperand(&block_stream, block[0], context)).?.register; |
| 761 | const value = mem.readInt(usize, (try abi.regBytes(context.thread_context.?, register, context.reg_context))[0..@sizeOf(usize)], native_endian); | 761 | const value = mem.readInt(usize, (try abi.regBytes(context.thread_context.?, register, context.reg_context))[0..@sizeOf(usize)], native_endian); |
| 762 | try self.stack.append(allocator, .{ .generic = value }); | 762 | try self.stack.append(allocator, .{ .generic = value }); |
lib/std/debug/SelfInfo.zig+3-6| ... | @@ -2027,12 +2027,9 @@ pub const VirtualMachine = struct { | ... | @@ -2027,12 +2027,9 @@ pub const VirtualMachine = struct { |
| 2027 | 2027 | ||
| 2028 | var prev_row: Row = self.current_row; | 2028 | var prev_row: Row = self.current_row; |
| 2029 | 2029 | ||
| 2030 | var cie_stream = std.io.fixedBufferStream(cie.initial_instructions); | 2030 | var cie_stream: std.io.FixedBufferStream = .{ .buffer = cie.initial_instructions }; |
| 2031 | var fde_stream = std.io.fixedBufferStream(fde.instructions); | 2031 | var fde_stream: std.io.FixedBufferStream = .{ .buffer = fde.instructions }; |
| 2032 | var streams = [_]*std.io.FixedBufferStream([]const u8){ | 2032 | const streams: [2]*std.io.FixedBufferStream = .{ &cie_stream, &fde_stream }; |
| 2033 | &cie_stream, | ||
| 2034 | &fde_stream, | ||
| 2035 | }; | ||
| 2036 | 2033 | ||
| 2037 | for (&streams, 0..) |stream, i| { | 2034 | for (&streams, 0..) |stream, i| { |
| 2038 | while (stream.pos < stream.buffer.len) { | 2035 | while (stream.pos < stream.buffer.len) { |
lib/std/fmt.zig+51-1155| ... | @@ -13,6 +13,8 @@ const lossyCast = math.lossyCast; | ... | @@ -13,6 +13,8 @@ const lossyCast = math.lossyCast; |
| 13 | const expectFmt = std.testing.expectFmt; | 13 | const expectFmt = std.testing.expectFmt; |
| 14 | const testing = std.testing; | 14 | const testing = std.testing; |
| 15 | 15 | ||
| 16 | pub const float = @import("fmt/float.zig"); | ||
| 17 | |||
| 16 | pub const default_max_depth = 3; | 18 | pub const default_max_depth = 3; |
| 17 | 19 | ||
| 18 | pub const Alignment = enum { | 20 | pub const Alignment = enum { |
| ... | @@ -24,11 +26,14 @@ pub const Alignment = enum { | ... | @@ -24,11 +26,14 @@ pub const Alignment = enum { |
| 24 | const default_alignment = .right; | 26 | const default_alignment = .right; |
| 25 | const default_fill_char = ' '; | 27 | const default_fill_char = ' '; |
| 26 | 28 | ||
| 27 | pub const FormatOptions = struct { | 29 | /// Deprecated; to be removed after 0.14.0 is tagged. |
| 30 | pub const FormatOptions = Options; | ||
| 31 | |||
| 32 | pub const Options = struct { | ||
| 28 | precision: ?usize = null, | 33 | precision: ?usize = null, |
| 29 | width: ?usize = null, | 34 | width: ?usize = null, |
| 30 | alignment: Alignment = default_alignment, | 35 | alignment: Alignment = default_alignment, |
| 31 | fill: u21 = default_fill_char, | 36 | fill: u8 = default_fill_char, |
| 32 | }; | 37 | }; |
| 33 | 38 | ||
| 34 | /// Renders fmt string with args, calling `writer` with slices of bytes. | 39 | /// Renders fmt string with args, calling `writer` with slices of bytes. |
| ... | @@ -45,9 +50,10 @@ pub const FormatOptions = struct { | ... | @@ -45,9 +50,10 @@ pub const FormatOptions = struct { |
| 45 | /// - when using a field name, you are required to enclose the field name (an identifier) in square | 50 | /// - when using a field name, you are required to enclose the field name (an identifier) in square |
| 46 | /// brackets, e.g. {[score]...} as opposed to the numeric index form which can be written e.g. {2...} | 51 | /// brackets, e.g. {[score]...} as opposed to the numeric index form which can be written e.g. {2...} |
| 47 | /// - *specifier* is a type-dependent formatting option that determines how a type should formatted (see below) | 52 | /// - *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 |
| 49 | /// - *alignment* is one of the three bytes '<', '^', or '>' to make the text left-, center-, or right-aligned, respectively | 54 | /// - *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. | ||
| 51 | /// - *precision* specifies how many decimals a formatted number should have | 57 | /// - *precision* specifies how many decimals a formatted number should have |
| 52 | /// | 58 | /// |
| 53 | /// Note that most of the parameters are optional and may be omitted. Also you can leave out separators like `:` and `.` when | 59 | /// 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 { | ... | @@ -66,6 +72,9 @@ pub const FormatOptions = struct { |
| 66 | /// - `o`: output integer value in octal notation | 72 | /// - `o`: output integer value in octal notation |
| 67 | /// - `c`: output integer as an ASCII character. Integer type must have 8 bits at max. | 73 | /// - `c`: output integer as an ASCII character. Integer type must have 8 bits at max. |
| 68 | /// - `u`: output integer as an UTF-8 sequence. Integer type must have 21 bits at max. | 74 | /// - `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) | ||
| 69 | /// - `?`: output optional value as either the unwrapped value, or `null`; may be followed by a format specifier for the underlying value. | 78 | /// - `?`: output optional value as either the unwrapped value, or `null`; may be followed by a format specifier for the underlying value. |
| 70 | /// - `!`: 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. | 79 | /// - `!`: 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. |
| 71 | /// - `*`: output the address of the value instead of the value itself. | 80 | /// - `*`: output the address of the value instead of the value itself. |
| ... | @@ -73,7 +82,7 @@ pub const FormatOptions = struct { | ... | @@ -73,7 +82,7 @@ pub const FormatOptions = struct { |
| 73 | /// | 82 | /// |
| 74 | /// If a formatted user type contains a function of the type | 83 | /// If a formatted user type contains a function of the type |
| 75 | /// ``` | 84 | /// ``` |
| 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 |
| 77 | /// ``` | 86 | /// ``` |
| 78 | /// with `?` being the type formatted, this function will be called instead of the default implementation. | 87 | /// with `?` being the type formatted, this function will be called instead of the default implementation. |
| 79 | /// This allows user types to be formatted in a logical manner instead of dumping all fields of the type. | 88 | /// 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 { | ... | @@ -81,11 +90,7 @@ pub const FormatOptions = struct { |
| 81 | /// A user type may be a `struct`, `vector`, `union` or `enum` type. | 90 | /// A user type may be a `struct`, `vector`, `union` or `enum` type. |
| 82 | /// | 91 | /// |
| 83 | /// To print literal curly braces, escape them by writing them twice, e.g. `{{` or `}}`. | 92 | /// To print literal curly braces, escape them by writing them twice, e.g. `{{` or `}}`. |
| 84 | pub fn format( | 93 | pub fn format(bw: *std.io.BufferedWriter, comptime fmt: []const u8, args: anytype) anyerror!void { |
| 85 | writer: anytype, | ||
| 86 | comptime fmt: []const u8, | ||
| 87 | args: anytype, | ||
| 88 | ) !void { | ||
| 89 | const ArgsType = @TypeOf(args); | 94 | const ArgsType = @TypeOf(args); |
| 90 | const args_type_info = @typeInfo(ArgsType); | 95 | const args_type_info = @typeInfo(ArgsType); |
| 91 | if (args_type_info != .@"struct") { | 96 | if (args_type_info != .@"struct") { |
| ... | @@ -130,7 +135,7 @@ pub fn format( | ... | @@ -130,7 +135,7 @@ pub fn format( |
| 130 | 135 | ||
| 131 | // Write out the literal | 136 | // Write out the literal |
| 132 | if (literal.len != 0) { | 137 | if (literal.len != 0) { |
| 133 | try writer.writeAll(literal); | 138 | try bw.writeAll(literal); |
| 134 | literal = ""; | 139 | literal = ""; |
| 135 | } | 140 | } |
| 136 | 141 | ||
| ... | @@ -190,16 +195,15 @@ pub fn format( | ... | @@ -190,16 +195,15 @@ pub fn format( |
| 190 | const arg_to_print = comptime arg_state.nextArg(arg_pos) orelse | 195 | const arg_to_print = comptime arg_state.nextArg(arg_pos) orelse |
| 191 | @compileError("too few arguments"); | 196 | @compileError("too few arguments"); |
| 192 | 197 | ||
| 193 | try formatType( | 198 | try bw.printValue( |
| 194 | @field(args, fields_info[arg_to_print].name), | ||
| 195 | placeholder.specifier_arg, | 199 | placeholder.specifier_arg, |
| 196 | FormatOptions{ | 200 | .{ |
| 197 | .fill = placeholder.fill, | 201 | .fill = placeholder.fill, |
| 198 | .alignment = placeholder.alignment, | 202 | .alignment = placeholder.alignment, |
| 199 | .width = width, | 203 | .width = width, |
| 200 | .precision = precision, | 204 | .precision = precision, |
| 201 | }, | 205 | }, |
| 202 | writer, | 206 | @field(args, fields_info[arg_to_print].name), |
| 203 | std.options.fmt_max_depth, | 207 | std.options.fmt_max_depth, |
| 204 | ); | 208 | ); |
| 205 | } | 209 | } |
| ... | @@ -298,7 +302,7 @@ pub const Placeholder = struct { | ... | @@ -298,7 +302,7 @@ pub const Placeholder = struct { |
| 298 | @compileError("extraneous trailing character '" ++ unicode.utf8EncodeComptime(ch) ++ "'"); | 302 | @compileError("extraneous trailing character '" ++ unicode.utf8EncodeComptime(ch) ++ "'"); |
| 299 | } | 303 | } |
| 300 | 304 | ||
| 301 | return Placeholder{ | 305 | return .{ |
| 302 | .specifier_arg = cacheString(specifier_arg[0..specifier_arg.len].*), | 306 | .specifier_arg = cacheString(specifier_arg[0..specifier_arg.len].*), |
| 303 | .fill = fill orelse default_fill_char, | 307 | .fill = fill orelse default_fill_char, |
| 304 | .alignment = alignment orelse default_alignment, | 308 | .alignment = alignment orelse default_alignment, |
| ... | @@ -434,429 +438,12 @@ pub const ArgState = struct { | ... | @@ -434,429 +438,12 @@ pub const ArgState = struct { |
| 434 | } | 438 | } |
| 435 | }; | 439 | }; |
| 436 | 440 | ||
| 437 | pub 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 | ||
| 464 | const ANY = "any"; | ||
| 465 | |||
| 466 | pub 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 | |||
| 484 | fn 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 | |||
| 491 | pub fn invalidFmtError(comptime fmt: []const u8, value: anytype) void { | ||
| 492 | @compileError("invalid format string '" ++ fmt ++ "' for type '" ++ @typeName(@TypeOf(value)) ++ "'"); | ||
| 493 | } | ||
| 494 | |||
| 495 | pub 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 | |||
| 720 | fn 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 | |||
| 735 | pub 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 | |||
| 783 | pub const format_float = @import("fmt/format_float.zig"); | ||
| 784 | pub const formatFloat = format_float.formatFloat; | ||
| 785 | pub const FormatFloatError = format_float.FormatError; | ||
| 786 | |||
| 787 | fn 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 | |||
| 816 | test { | 441 | test { |
| 817 | _ = &format_float; | 442 | _ = float; |
| 818 | } | 443 | } |
| 819 | 444 | ||
| 820 | pub const Case = enum { lower, upper }; | 445 | pub const Case = enum { lower, upper }; |
| 821 | 446 | ||
| 822 | fn 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 | |||
| 845 | const formatSliceHexLower = SliceHex(.lower).format; | ||
| 846 | const 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. | ||
| 850 | pub 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. | ||
| 856 | pub fn fmtSliceHexUpper(bytes: []const u8) std.fmt.Formatter(formatSliceHexUpper) { | ||
| 857 | return .{ .data = bytes }; | ||
| 858 | } | ||
| 859 | |||
| 860 | fn SliceEscape(comptime case: Case) type { | 447 | fn SliceEscape(comptime case: Case) type { |
| 861 | const charset = "0123456789" ++ if (case == .upper) "ABCDEF" else "abcdef"; | 448 | const charset = "0123456789" ++ if (case == .upper) "ABCDEF" else "abcdef"; |
| 862 | 449 | ||
| ... | @@ -864,7 +451,7 @@ fn SliceEscape(comptime case: Case) type { | ... | @@ -864,7 +451,7 @@ fn SliceEscape(comptime case: Case) type { |
| 864 | pub fn format( | 451 | pub fn format( |
| 865 | bytes: []const u8, | 452 | bytes: []const u8, |
| 866 | comptime fmt: []const u8, | 453 | comptime fmt: []const u8, |
| 867 | options: std.fmt.FormatOptions, | 454 | options: std.fmt.Options, |
| 868 | writer: anytype, | 455 | writer: anytype, |
| 869 | ) !void { | 456 | ) !void { |
| 870 | _ = fmt; | 457 | _ = fmt; |
| ... | @@ -904,352 +491,13 @@ pub fn fmtSliceEscapeUpper(bytes: []const u8) std.fmt.Formatter(formatSliceEscap | ... | @@ -904,352 +491,13 @@ pub fn fmtSliceEscapeUpper(bytes: []const u8) std.fmt.Formatter(formatSliceEscap |
| 904 | return .{ .data = bytes }; | 491 | return .{ .data = bytes }; |
| 905 | } | 492 | } |
| 906 | 493 | ||
| 907 | fn Size(comptime base: comptime_int) type { | 494 | /// Asserts the rendered integer value fits in `buffer`. |
| 908 | return struct { | 495 | /// Returns the end index within `buffer`. |
| 909 | fn format( | 496 | pub fn printInt(buffer: []u8, value: anytype, base: u8, case: Case, options: Options) usize { |
| 910 | value: u64, | 497 | var bw: std.io.BufferedWriter = undefined; |
| 911 | comptime fmt: []const u8, | 498 | bw.initFixed(buffer); |
| 912 | options: FormatOptions, | 499 | bw.printIntOptions(value, base, case, options) catch unreachable; |
| 913 | writer: anytype, | 500 | return bw.end; |
| 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 | } | ||
| 965 | const formatSizeDec = Size(1000).format; | ||
| 966 | const 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 | ||
| 972 | pub 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 | ||
| 980 | pub fn fmtIntSizeBin(value: u64) std.fmt.Formatter(formatSizeBin) { | ||
| 981 | return .{ .data = value }; | ||
| 982 | } | ||
| 983 | |||
| 984 | fn 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 | |||
| 996 | pub 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 | |||
| 1006 | pub 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 | |||
| 1014 | pub 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 | |||
| 1028 | pub 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 | |||
| 1072 | pub 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 | |||
| 1181 | pub 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 | |||
| 1249 | pub 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; | ||
| 1253 | } | 501 | } |
| 1254 | 502 | ||
| 1255 | /// Converts values in the range [0, 100) to a base 10 string. | 503 | /// Converts values in the range [0, 100) to a base 10 string. |
| ... | @@ -1261,214 +509,6 @@ pub fn digits2(value: u8) [2]u8 { | ... | @@ -1261,214 +509,6 @@ pub fn digits2(value: u8) [2]u8 { |
| 1261 | } | 509 | } |
| 1262 | } | 510 | } |
| 1263 | 511 | ||
| 1264 | const FormatDurationData = struct { | ||
| 1265 | ns: u64, | ||
| 1266 | negative: bool = false, | ||
| 1267 | }; | ||
| 1268 | |||
| 1269 | fn 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 | ||
| 1329 | pub fn fmtDuration(ns: u64) Formatter(formatDuration) { | ||
| 1330 | const data = FormatDurationData{ .ns = ns }; | ||
| 1331 | return .{ .data = data }; | ||
| 1332 | } | ||
| 1333 | |||
| 1334 | test 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 | |||
| 1382 | fn 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 | ||
| 1389 | pub fn fmtDurationSigned(ns: i64) Formatter(formatDurationSigned) { | ||
| 1390 | return .{ .data = ns }; | ||
| 1391 | } | ||
| 1392 | |||
| 1393 | test 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 | |||
| 1472 | pub const ParseIntError = error{ | 512 | pub const ParseIntError = error{ |
| 1473 | /// The result cannot fit in the type specified | 513 | /// The result cannot fit in the type specified |
| 1474 | Overflow, | 514 | Overflow, |
| ... | @@ -1484,7 +524,7 @@ pub const ParseIntError = error{ | ... | @@ -1484,7 +524,7 @@ pub const ParseIntError = error{ |
| 1484 | /// fn formatExample( | 524 | /// fn formatExample( |
| 1485 | /// data: T, | 525 | /// data: T, |
| 1486 | /// comptime fmt: []const u8, | 526 | /// comptime fmt: []const u8, |
| 1487 | /// options: std.fmt.FormatOptions, | 527 | /// options: std.fmt.Options, |
| 1488 | /// writer: anytype, | 528 | /// writer: anytype, |
| 1489 | /// ) !void; | 529 | /// ) !void; |
| 1490 | /// | 530 | /// |
| ... | @@ -1495,9 +535,9 @@ pub fn Formatter(comptime formatFn: anytype) type { | ... | @@ -1495,9 +535,9 @@ pub fn Formatter(comptime formatFn: anytype) type { |
| 1495 | pub fn format( | 535 | pub fn format( |
| 1496 | self: @This(), | 536 | self: @This(), |
| 1497 | comptime fmt: []const u8, | 537 | comptime fmt: []const u8, |
| 1498 | options: std.fmt.FormatOptions, | 538 | options: std.fmt.Options, |
| 1499 | writer: anytype, | 539 | writer: *std.io.BufferedWriter, |
| 1500 | ) @TypeOf(writer).Error!void { | 540 | ) anyerror!void { |
| 1501 | try formatFn(self.data, fmt, options, writer); | 541 | try formatFn(self.data, fmt, options, writer); |
| 1502 | } | 542 | } |
| 1503 | }; | 543 | }; |
| ... | @@ -1796,12 +836,13 @@ pub const BufPrintError = error{ | ... | @@ -1796,12 +836,13 @@ pub const BufPrintError = error{ |
| 1796 | /// Print a Formatter string into `buf`. Actually just a thin wrapper around `format` and `fixedBufferStream`. | 836 | /// Print a Formatter string into `buf`. Actually just a thin wrapper around `format` and `fixedBufferStream`. |
| 1797 | /// Returns a slice of the bytes printed to. | 837 | /// Returns a slice of the bytes printed to. |
| 1798 | pub fn bufPrint(buf: []u8, comptime fmt: []const u8, args: anytype) BufPrintError![]u8 { | 838 | pub fn bufPrint(buf: []u8, comptime fmt: []const u8, args: anytype) BufPrintError![]u8 { |
| 1799 | var fbs = std.io.fixedBufferStream(buf); | 839 | var bw: std.io.BufferedWriter = undefined; |
| 1800 | format(fbs.writer().any(), fmt, args) catch |err| switch (err) { | 840 | bw.initFixed(buf); |
| 841 | bw.print(fmt, args) catch |err| switch (err) { | ||
| 1801 | error.NoSpaceLeft => return error.NoSpaceLeft, | 842 | error.NoSpaceLeft => return error.NoSpaceLeft, |
| 1802 | else => unreachable, | 843 | else => unreachable, |
| 1803 | }; | 844 | }; |
| 1804 | return fbs.getWritten(); | 845 | return bw.getWritten(); |
| 1805 | } | 846 | } |
| 1806 | 847 | ||
| 1807 | pub fn bufPrintZ(buf: []u8, comptime fmt: []const u8, args: anytype) BufPrintError![:0]u8 { | 848 | pub 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 | ... | @@ -1809,10 +850,11 @@ pub fn bufPrintZ(buf: []u8, comptime fmt: []const u8, args: anytype) BufPrintErr |
| 1809 | return result[0 .. result.len - 1 :0]; | 850 | return result[0 .. result.len - 1 :0]; |
| 1810 | } | 851 | } |
| 1811 | 852 | ||
| 1812 | /// Count the characters needed for format. Useful for preallocating memory | 853 | /// Count the characters needed for format. |
| 1813 | pub fn count(comptime fmt: []const u8, args: anytype) u64 { | 854 | pub fn count(comptime fmt: []const u8, args: anytype) u64 { |
| 1814 | var counting_writer = std.io.countingWriter(std.io.null_writer); | 855 | var counting_writer: std.io.CountingWriter = .{ .child_writer = std.io.null_writer }; |
| 1815 | format(counting_writer.writer().any(), fmt, args) catch unreachable; | 856 | var bw = counting_writer.unbufferedWriter(); |
| 857 | bw.print(fmt, args) catch unreachable; | ||
| 1816 | return counting_writer.bytes_written; | 858 | return counting_writer.bytes_written; |
| 1817 | } | 859 | } |
| 1818 | 860 | ||
| ... | @@ -1831,31 +873,6 @@ pub fn allocPrintZ(allocator: mem.Allocator, comptime fmt: []const u8, args: any | ... | @@ -1831,31 +873,6 @@ pub fn allocPrintZ(allocator: mem.Allocator, comptime fmt: []const u8, args: any |
| 1831 | return result[0 .. result.len - 1 :0]; | 873 | return result[0 .. result.len - 1 :0]; |
| 1832 | } | 874 | } |
| 1833 | 875 | ||
| 1834 | test 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 | |||
| 1855 | pub 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 | |||
| 1859 | pub inline fn comptimePrint(comptime fmt: []const u8, args: anytype) *const [count(fmt, args):0]u8 { | 876 | pub inline fn comptimePrint(comptime fmt: []const u8, args: anytype) *const [count(fmt, args):0]u8 { |
| 1860 | comptime { | 877 | comptime { |
| 1861 | var buf: [count(fmt, args):0]u8 = undefined; | 878 | var buf: [count(fmt, args):0]u8 = undefined; |
| ... | @@ -1994,15 +1011,16 @@ test "buffer" { | ... | @@ -1994,15 +1011,16 @@ test "buffer" { |
| 1994 | { | 1011 | { |
| 1995 | var buf1: [32]u8 = undefined; | 1012 | var buf1: [32]u8 = undefined; |
| 1996 | var fbs = std.io.fixedBufferStream(&buf1); | 1013 | 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); | ||
| 1998 | try std.testing.expectEqualStrings("1234", fbs.getWritten()); | 1016 | try std.testing.expectEqualStrings("1234", fbs.getWritten()); |
| 1999 | 1017 | ||
| 2000 | fbs.reset(); | 1018 | 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); |
| 2002 | try std.testing.expectEqualStrings("a", fbs.getWritten()); | 1020 | try std.testing.expectEqualStrings("a", fbs.getWritten()); |
| 2003 | 1021 | ||
| 2004 | fbs.reset(); | 1022 | 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); |
| 2006 | try std.testing.expectEqualStrings("1100", fbs.getWritten()); | 1024 | try std.testing.expectEqualStrings("1100", fbs.getWritten()); |
| 2007 | } | 1025 | } |
| 2008 | } | 1026 | } |
| ... | @@ -2083,7 +1101,7 @@ test "slice" { | ... | @@ -2083,7 +1101,7 @@ test "slice" { |
| 2083 | const S2 = struct { | 1101 | const S2 = struct { |
| 2084 | x: u8, | 1102 | x: u8, |
| 2085 | 1103 | ||
| 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 { |
| 2087 | try writer.print("S2({})", .{s.x}); | 1105 | try writer.print("S2({})", .{s.x}); |
| 2088 | } | 1106 | } |
| 2089 | }; | 1107 | }; |
| ... | @@ -2129,21 +1147,6 @@ test "cstr" { | ... | @@ -2129,21 +1147,6 @@ test "cstr" { |
| 2129 | ); | 1147 | ); |
| 2130 | } | 1148 | } |
| 2131 | 1149 | ||
| 2132 | test "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 | |||
| 2147 | test "struct" { | 1150 | test "struct" { |
| 2148 | { | 1151 | { |
| 2149 | const Struct = struct { | 1152 | const Struct = struct { |
| ... | @@ -2354,7 +1357,7 @@ test "custom" { | ... | @@ -2354,7 +1357,7 @@ test "custom" { |
| 2354 | pub fn format( | 1357 | pub fn format( |
| 2355 | self: SelfType, | 1358 | self: SelfType, |
| 2356 | comptime fmt: []const u8, | 1359 | comptime fmt: []const u8, |
| 2357 | options: FormatOptions, | 1360 | options: Options, |
| 2358 | writer: anytype, | 1361 | writer: anytype, |
| 2359 | ) !void { | 1362 | ) !void { |
| 2360 | _ = options; | 1363 | _ = options; |
| ... | @@ -2439,17 +1442,6 @@ test "struct.zero-size" { | ... | @@ -2439,17 +1442,6 @@ test "struct.zero-size" { |
| 2439 | try expectFmt("fmt.test.struct.zero-size.B{ .a = fmt.test.struct.zero-size.A{ }, .c = 0 }", "{}", .{b}); | 1442 | try expectFmt("fmt.test.struct.zero-size.B{ .a = fmt.test.struct.zero-size.A{ }, .c = 0 }", "{}", .{b}); |
| 2440 | } | 1443 | } |
| 2441 | 1444 | ||
| 2442 | test "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 | |||
| 2453 | /// Encodes a sequence of bytes as hexadecimal digits. | 1445 | /// Encodes a sequence of bytes as hexadecimal digits. |
| 2454 | /// Returns an array containing the encoded bytes. | 1446 | /// Returns an array containing the encoded bytes. |
| 2455 | pub fn bytesToHex(input: anytype, case: Case) [input.len * 2]u8 { | 1447 | pub fn bytesToHex(input: anytype, case: Case) [input.len * 2]u8 { |
| ... | @@ -2494,110 +1486,14 @@ test bytesToHex { | ... | @@ -2494,110 +1486,14 @@ test bytesToHex { |
| 2494 | 1486 | ||
| 2495 | test hexToBytes { | 1487 | test hexToBytes { |
| 2496 | var buf: [32]u8 = undefined; | 1488 | var buf: [32]u8 = undefined; |
| 2497 | try expectFmt("90" ** 32, "{s}", .{fmtSliceHexUpper(try hexToBytes(&buf, "90" ** 32))}); | 1489 | try expectFmt("90" ** 32, "{X}", .{try hexToBytes(&buf, "90" ** 32)}); |
| 2498 | try expectFmt("ABCD", "{s}", .{fmtSliceHexUpper(try hexToBytes(&buf, "ABCD"))}); | 1490 | try expectFmt("ABCD", "{X}", .{try hexToBytes(&buf, "ABCD")}); |
| 2499 | try expectFmt("", "{s}", .{fmtSliceHexUpper(try hexToBytes(&buf, ""))}); | 1491 | try expectFmt("", "{X}", .{try hexToBytes(&buf, "")}); |
| 2500 | try std.testing.expectError(error.InvalidCharacter, hexToBytes(&buf, "012Z")); | 1492 | try std.testing.expectError(error.InvalidCharacter, hexToBytes(&buf, "012Z")); |
| 2501 | try std.testing.expectError(error.InvalidLength, hexToBytes(&buf, "AAA")); | 1493 | try std.testing.expectError(error.InvalidLength, hexToBytes(&buf, "AAA")); |
| 2502 | try std.testing.expectError(error.NoSpaceLeft, hexToBytes(buf[0..1], "ABAB")); | 1494 | try std.testing.expectError(error.NoSpaceLeft, hexToBytes(buf[0..1], "ABAB")); |
| 2503 | } | 1495 | } |
| 2504 | 1496 | ||
| 2505 | test "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 | |||
| 2514 | test "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 | |||
| 2526 | test "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 | |||
| 2601 | test "positional" { | 1497 | test "positional" { |
| 2602 | try expectFmt("2 1 0", "{2} {1} {0}", .{ @as(usize, 0), @as(usize, 1), @as(usize, 2) }); | 1498 | try expectFmt("2 1 0", "{2} {1} {0}", .{ @as(usize, 0), @as(usize, 1), @as(usize, 2) }); |
| 2603 | try expectFmt("2 1 0", "{2} {1} {}", .{ @as(usize, 0), @as(usize, 1), @as(usize, 2) }); | 1499 | try expectFmt("2 1 0", "{2} {1} {}", .{ @as(usize, 0), @as(usize, 1), @as(usize, 2) }); |
| ... | @@ -2742,7 +1638,7 @@ test "recursive format function" { | ... | @@ -2742,7 +1638,7 @@ test "recursive format function" { |
| 2742 | Leaf: i32, | 1638 | Leaf: i32, |
| 2743 | Branch: struct { left: *const R, right: *const R }, | 1639 | Branch: struct { left: *const R, right: *const R }, |
| 2744 | 1640 | ||
| 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 { |
| 2746 | return switch (self) { | 1642 | return switch (self) { |
| 2747 | .Leaf => |n| std.fmt.format(writer, "Leaf({})", .{n}), | 1643 | .Leaf => |n| std.fmt.format(writer, "Leaf({})", .{n}), |
| 2748 | .Branch => |b| std.fmt.format(writer, "Branch({}, {})", .{ b.left, b.right }), | 1644 | .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 | |||
| 4 | const std = @import("std"); | ||
| 5 | const expectFmt = std.testing.expectFmt; | ||
| 6 | |||
| 7 | const 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. | ||
| 11 | pub const min_buffer_size = 53; | ||
| 12 | |||
| 13 | /// Returns the minimum buffer size needed to print every float of a specific type and format. | ||
| 14 | pub 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 | |||
| 30 | pub const Error = error{ | ||
| 31 | BufferTooSmall, | ||
| 32 | }; | ||
| 33 | |||
| 34 | pub const Mode = enum { | ||
| 35 | scientific, | ||
| 36 | decimal, | ||
| 37 | }; | ||
| 38 | |||
| 39 | pub 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. | ||
| 55 | pub 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 | |||
| 82 | pub 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 | |||
| 91 | fn 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 | |||
| 104 | fn 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 | |||
| 122 | fn 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 | |||
| 130 | const RoundMode = enum { | ||
| 131 | /// 1234.56 = precision 2 | ||
| 132 | decimal, | ||
| 133 | /// 1.23456e3 = precision 5 | ||
| 134 | scientific, | ||
| 135 | }; | ||
| 136 | |||
| 137 | fn 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. | ||
| 195 | pub 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. | ||
| 266 | pub 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 | |||
| 356 | fn cast_i32(v: anytype) i32 { | ||
| 357 | return @intCast(v); | ||
| 358 | } | ||
| 359 | |||
| 360 | /// Convert a binary float representation to decimal. | ||
| 361 | pub 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 | |||
| 498 | fn 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)) | ||
| 535 | fn 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)) | ||
| 541 | fn 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)) | ||
| 547 | fn pow5Bits(e: u32) u32 { | ||
| 548 | std.debug.assert(e <= 1 << 15); | ||
| 549 | return @intCast(((@as(u64, @intCast(e)) * 163391164108059) >> 46) + 1); | ||
| 550 | } | ||
| 551 | |||
| 552 | fn 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 | |||
| 564 | fn 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 | |||
| 570 | fn 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 | |||
| 576 | fn 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 | |||
| 583 | fn 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 | |||
| 632 | pub 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 | |||
| 677 | fn 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 | |||
| 690 | pub 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 | |||
| 709 | pub 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 | |||
| 756 | const FLOAT64_POW5_INV_BITCOUNT = 125; | ||
| 757 | const FLOAT64_POW5_BITCOUNT = 125; | ||
| 758 | |||
| 759 | // zig fmt: off | ||
| 760 | // | ||
| 761 | // f64 small tables: 816 bytes | ||
| 762 | |||
| 763 | const FLOAT64_POW5_TABLE_SIZE: comptime_int = FLOAT64_POW5_TABLE.len; | ||
| 764 | |||
| 765 | const 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 | |||
| 781 | const 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 | |||
| 797 | const 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 | |||
| 806 | const 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 | |||
| 824 | const 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 | |||
| 837 | const 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 | |||
| 1003 | const 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 | |||
| 1181 | const FLOAT128_POW5_INV_BITCOUNT = 249; | ||
| 1182 | const FLOAT128_POW5_BITCOUNT = 249; | ||
| 1183 | const FLOAT128_POW5_TABLE_SIZE: comptime_int = FLOAT128_POW5_TABLE.len; | ||
| 1184 | |||
| 1185 | const 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 | |||
| 1244 | const 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. | ||
| 1338 | const 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 | |||
| 1380 | const 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 | |||
| 1472 | const 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 | |||
| 1516 | const builtin = @import("builtin"); | ||
| 1517 | |||
| 1518 | fn 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 | |||
| 1538 | test "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 | |||
| 1599 | test "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 | |||
| 1648 | test "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 | |||
| 1669 | test "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 | |||
| 1690 | test "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 | |||
| 4 | const std = @import("std"); | ||
| 5 | const expectFmt = std.testing.expectFmt; | ||
| 6 | |||
| 7 | const 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. | ||
| 11 | pub const min_buffer_size = 53; | ||
| 12 | |||
| 13 | /// Returns the minimum buffer size needed to print every float of a specific type and format. | ||
| 14 | pub 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 | |||
| 30 | pub const FormatError = error{ | ||
| 31 | BufferTooSmall, | ||
| 32 | }; | ||
| 33 | |||
| 34 | pub const Format = enum { | ||
| 35 | scientific, | ||
| 36 | decimal, | ||
| 37 | }; | ||
| 38 | |||
| 39 | pub 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. | ||
| 55 | pub 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 | |||
| 82 | pub 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 | |||
| 91 | fn 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 | |||
| 104 | fn 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 | |||
| 122 | fn 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 | |||
| 130 | const RoundMode = enum { | ||
| 131 | /// 1234.56 = precision 2 | ||
| 132 | decimal, | ||
| 133 | /// 1.23456e3 = precision 5 | ||
| 134 | scientific, | ||
| 135 | }; | ||
| 136 | |||
| 137 | fn 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. | ||
| 195 | pub 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. | ||
| 266 | pub 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 | |||
| 356 | fn cast_i32(v: anytype) i32 { | ||
| 357 | return @intCast(v); | ||
| 358 | } | ||
| 359 | |||
| 360 | /// Convert a binary float representation to decimal. | ||
| 361 | pub 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 | |||
| 498 | fn 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)) | ||
| 535 | fn 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)) | ||
| 541 | fn 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)) | ||
| 547 | fn pow5Bits(e: u32) u32 { | ||
| 548 | std.debug.assert(e <= 1 << 15); | ||
| 549 | return @intCast(((@as(u64, @intCast(e)) * 163391164108059) >> 46) + 1); | ||
| 550 | } | ||
| 551 | |||
| 552 | fn 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 | |||
| 564 | fn 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 | |||
| 570 | fn 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 | |||
| 576 | fn 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 | |||
| 583 | fn 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 | |||
| 632 | pub 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 | |||
| 677 | fn 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 | |||
| 690 | pub 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 | |||
| 709 | pub 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 | |||
| 756 | const FLOAT64_POW5_INV_BITCOUNT = 125; | ||
| 757 | const FLOAT64_POW5_BITCOUNT = 125; | ||
| 758 | |||
| 759 | // zig fmt: off | ||
| 760 | // | ||
| 761 | // f64 small tables: 816 bytes | ||
| 762 | |||
| 763 | const FLOAT64_POW5_TABLE_SIZE: comptime_int = FLOAT64_POW5_TABLE.len; | ||
| 764 | |||
| 765 | const 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 | |||
| 781 | const 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 | |||
| 797 | const 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 | |||
| 806 | const 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 | |||
| 824 | const 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 | |||
| 837 | const 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 | |||
| 1003 | const 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 | |||
| 1181 | const FLOAT128_POW5_INV_BITCOUNT = 249; | ||
| 1182 | const FLOAT128_POW5_BITCOUNT = 249; | ||
| 1183 | const FLOAT128_POW5_TABLE_SIZE: comptime_int = FLOAT128_POW5_TABLE.len; | ||
| 1184 | |||
| 1185 | const 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 | |||
| 1244 | const 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. | ||
| 1338 | const 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 | |||
| 1380 | const 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 | |||
| 1472 | const 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 | |||
| 1516 | const builtin = @import("builtin"); | ||
| 1517 | |||
| 1518 | fn 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 | |||
| 1538 | test "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 | |||
| 1599 | test "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 | |||
| 1648 | test "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 | |||
| 1669 | test "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 | |||
| 1690 | test "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 { | ... | @@ -1587,12 +1587,112 @@ pub fn reader(file: File) Reader { |
| 1587 | return .{ .context = file }; | 1587 | return .{ .context = file }; |
| 1588 | } | 1588 | } |
| 1589 | 1589 | ||
| 1590 | pub const Writer = io.Writer(File, WriteError, write); | 1590 | pub 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 | } | ||
| 1591 | 1599 | ||
| 1592 | pub fn writer(file: File) Writer { | 1600 | pub fn unbufferedWriter(file: File) std.io.BufferedWriter { |
| 1593 | return .{ .context = file }; | 1601 | return .{ |
| 1602 | .buffer = &.{}, | ||
| 1603 | .unbuffered_writer = writer(file), | ||
| 1604 | }; | ||
| 1594 | } | 1605 | } |
| 1595 | 1606 | ||
| 1607 | const 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 | |||
| 1596 | pub const SeekableStream = io.SeekableStream( | 1696 | pub const SeekableStream = io.SeekableStream( |
| 1597 | File, | 1697 | File, |
| 1598 | SeekError, | 1698 | SeekError, |
lib/std/io.zig+42-22| ... | @@ -336,7 +336,7 @@ pub fn GenericWriter( | ... | @@ -336,7 +336,7 @@ pub fn GenericWriter( |
| 336 | return @errorCast(self.any().writeStructEndian(value, endian)); | 336 | return @errorCast(self.any().writeStructEndian(value, endian)); |
| 337 | } | 337 | } |
| 338 | 338 | ||
| 339 | pub inline fn any(self: *const Self) AnyWriter { | 339 | pub inline fn any(self: *const Self) Writer { |
| 340 | return .{ | 340 | return .{ |
| 341 | .context = @ptrCast(&self.context), | 341 | .context = @ptrCast(&self.context), |
| 342 | .writeFn = typeErasedWriteFn, | 342 | .writeFn = typeErasedWriteFn, |
| ... | @@ -351,26 +351,23 @@ pub fn GenericWriter( | ... | @@ -351,26 +351,23 @@ pub fn GenericWriter( |
| 351 | } | 351 | } |
| 352 | 352 | ||
| 353 | /// Deprecated; consider switching to `AnyReader` or use `GenericReader` | 353 | /// 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. |
| 355 | pub const Reader = GenericReader; | 355 | pub const Reader = GenericReader; |
| 356 | /// Deprecated; consider switching to `AnyWriter` or use `GenericWriter` | 356 | pub const Writer = @import("io/Writer.zig"); |
| 357 | /// to use previous API. | ||
| 358 | pub const Writer = GenericWriter; | ||
| 359 | 357 | ||
| 360 | pub const AnyReader = @import("io/Reader.zig"); | 358 | pub const AnyReader = @import("io/Reader.zig"); |
| 361 | pub const AnyWriter = @import("io/Writer.zig"); | 359 | /// Deprecated; to be removed after 0.14.0 is tagged. |
| 360 | pub const AnyWriter = Writer; | ||
| 362 | 361 | ||
| 363 | pub const SeekableStream = @import("io/seekable_stream.zig").SeekableStream; | 362 | pub const SeekableStream = @import("io/seekable_stream.zig").SeekableStream; |
| 364 | 363 | ||
| 365 | pub const BufferedWriter = @import("io/buffered_writer.zig").BufferedWriter; | 364 | pub const BufferedWriter = @import("io/BufferedWriter.zig"); |
| 366 | pub const bufferedWriter = @import("io/buffered_writer.zig").bufferedWriter; | ||
| 367 | 365 | ||
| 368 | pub const BufferedReader = @import("io/buffered_reader.zig").BufferedReader; | 366 | pub const BufferedReader = @import("io/buffered_reader.zig").BufferedReader; |
| 369 | pub const bufferedReader = @import("io/buffered_reader.zig").bufferedReader; | 367 | pub const bufferedReader = @import("io/buffered_reader.zig").bufferedReader; |
| 370 | pub const bufferedReaderSize = @import("io/buffered_reader.zig").bufferedReaderSize; | 368 | pub const bufferedReaderSize = @import("io/buffered_reader.zig").bufferedReaderSize; |
| 371 | 369 | ||
| 372 | pub const FixedBufferStream = @import("io/fixed_buffer_stream.zig").FixedBufferStream; | 370 | pub const FixedBufferStream = @import("io/FixedBufferStream.zig"); |
| 373 | pub const fixedBufferStream = @import("io/fixed_buffer_stream.zig").fixedBufferStream; | ||
| 374 | 371 | ||
| 375 | pub const CWriter = @import("io/c_writer.zig").CWriter; | 372 | pub const CWriter = @import("io/c_writer.zig").CWriter; |
| 376 | pub const cWriter = @import("io/c_writer.zig").cWriter; | 373 | pub const cWriter = @import("io/c_writer.zig").cWriter; |
| ... | @@ -378,8 +375,7 @@ pub const cWriter = @import("io/c_writer.zig").cWriter; | ... | @@ -378,8 +375,7 @@ pub const cWriter = @import("io/c_writer.zig").cWriter; |
| 378 | pub const LimitedReader = @import("io/limited_reader.zig").LimitedReader; | 375 | pub const LimitedReader = @import("io/limited_reader.zig").LimitedReader; |
| 379 | pub const limitedReader = @import("io/limited_reader.zig").limitedReader; | 376 | pub const limitedReader = @import("io/limited_reader.zig").limitedReader; |
| 380 | 377 | ||
| 381 | pub const CountingWriter = @import("io/counting_writer.zig").CountingWriter; | 378 | pub const CountingWriter = @import("io/CountingWriter.zig"); |
| 382 | pub const countingWriter = @import("io/counting_writer.zig").countingWriter; | ||
| 383 | pub const CountingReader = @import("io/counting_reader.zig").CountingReader; | 379 | pub const CountingReader = @import("io/counting_reader.zig").CountingReader; |
| 384 | pub const countingReader = @import("io/counting_reader.zig").countingReader; | 380 | pub const countingReader = @import("io/counting_reader.zig").countingReader; |
| 385 | 381 | ||
| ... | @@ -404,17 +400,42 @@ pub const StreamSource = @import("io/stream_source.zig").StreamSource; | ... | @@ -404,17 +400,42 @@ pub const StreamSource = @import("io/stream_source.zig").StreamSource; |
| 404 | 400 | ||
| 405 | pub const tty = @import("io/tty.zig"); | 401 | pub const tty = @import("io/tty.zig"); |
| 406 | 402 | ||
| 407 | /// A Writer that doesn't write to anything. | 403 | /// A `Writer` that discards all data. |
| 408 | pub const null_writer: NullWriter = .{ .context = {} }; | 404 | pub const null_writer: Writer = .{ |
| 405 | .context = undefined, | ||
| 406 | .vtable = &.{ | ||
| 407 | .writev = null_writev, | ||
| 408 | .writeFile = null_writeFile, | ||
| 409 | }, | ||
| 410 | }; | ||
| 409 | 411 | ||
| 410 | pub const NullWriter = Writer(void, error{}, dummyWrite); | 412 | fn null_writev(context: *anyopaque, data: []const []const u8) anyerror!usize { |
| 411 | fn dummyWrite(context: void, data: []const u8) error{}!usize { | ||
| 412 | _ = context; | 413 | _ = context; |
| 413 | return data.len; | 414 | var n: usize = 0; |
| 415 | for (data) |bytes| n += bytes.len; | ||
| 416 | return n; | ||
| 417 | } | ||
| 418 | |||
| 419 | fn 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; | ||
| 414 | } | 435 | } |
| 415 | 436 | ||
| 416 | test null_writer { | 437 | test null_writer { |
| 417 | null_writer.writeAll("yay" ** 10) catch |err| switch (err) {}; | 438 | try null_writer.writeAll("yay"); |
| 418 | } | 439 | } |
| 419 | 440 | ||
| 420 | pub fn poll( | 441 | pub fn poll( |
| ... | @@ -820,16 +841,15 @@ pub fn PollFiles(comptime StreamEnum: type) type { | ... | @@ -820,16 +841,15 @@ pub fn PollFiles(comptime StreamEnum: type) type { |
| 820 | 841 | ||
| 821 | test { | 842 | test { |
| 822 | _ = AnyReader; | 843 | _ = AnyReader; |
| 823 | _ = AnyWriter; | 844 | _ = Writer; |
| 845 | _ = CountingWriter; | ||
| 846 | _ = FixedBufferStream; | ||
| 824 | _ = @import("io/bit_reader.zig"); | 847 | _ = @import("io/bit_reader.zig"); |
| 825 | _ = @import("io/bit_writer.zig"); | 848 | _ = @import("io/bit_writer.zig"); |
| 826 | _ = @import("io/buffered_atomic_file.zig"); | 849 | _ = @import("io/buffered_atomic_file.zig"); |
| 827 | _ = @import("io/buffered_reader.zig"); | 850 | _ = @import("io/buffered_reader.zig"); |
| 828 | _ = @import("io/buffered_writer.zig"); | ||
| 829 | _ = @import("io/c_writer.zig"); | 851 | _ = @import("io/c_writer.zig"); |
| 830 | _ = @import("io/counting_writer.zig"); | ||
| 831 | _ = @import("io/counting_reader.zig"); | 852 | _ = @import("io/counting_reader.zig"); |
| 832 | _ = @import("io/fixed_buffer_stream.zig"); | ||
| 833 | _ = @import("io/seekable_stream.zig"); | 853 | _ = @import("io/seekable_stream.zig"); |
| 834 | _ = @import("io/stream_source.zig"); | 854 | _ = @import("io/stream_source.zig"); |
| 835 | _ = @import("io/test.zig"); | 855 | _ = @import("io/test.zig"); |
lib/std/io/BufferedWriter.zig created+1494| ... | @@ -0,0 +1,1494 @@ | ||
| 1 | const std = @import("../std.zig"); | ||
| 2 | const BufferedWriter = @This(); | ||
| 3 | const assert = std.debug.assert; | ||
| 4 | const native_endian = @import("builtin").target.cpu.arch.endian(); | ||
| 5 | const Writer = std.io.Writer; | ||
| 6 | const testing = std.testing; | ||
| 7 | |||
| 8 | /// Underlying stream to send bytes to. | ||
| 9 | unbuffered_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. | ||
| 13 | buffer: []u8, | ||
| 14 | /// Marks the end of `buffer` - before this are buffered bytes, after this is | ||
| 15 | /// undefined. | ||
| 16 | end: 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. | ||
| 20 | pub const max_buffers_len = 8; | ||
| 21 | |||
| 22 | const passthru_vtable: Writer.VTable = .{ | ||
| 23 | .writev = passthru_writev, | ||
| 24 | .writeFile = passthru_writeFile, | ||
| 25 | }; | ||
| 26 | |||
| 27 | const fixed_vtable: Writer.VTable = .{ | ||
| 28 | .writev = fixed_writev, | ||
| 29 | .writeFile = fixed_writeFile, | ||
| 30 | }; | ||
| 31 | |||
| 32 | pub 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. | ||
| 41 | pub 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`. | ||
| 52 | pub 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`. | ||
| 58 | pub fn reset(bw: *BufferedWriter) void { | ||
| 59 | assert(bw.unbuffered_writer.vtable == &fixed_vtable); | ||
| 60 | bw.end = 0; | ||
| 61 | } | ||
| 62 | |||
| 63 | pub 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`. | ||
| 70 | pub 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 | |||
| 83 | pub fn writev(bw: *BufferedWriter, data: []const []const u8) anyerror!usize { | ||
| 84 | return passthru_writev(bw, data); | ||
| 85 | } | ||
| 86 | |||
| 87 | fn 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 | |||
| 121 | fn 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 | |||
| 132 | pub 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. | ||
| 157 | pub 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 | |||
| 162 | pub fn print(bw: *BufferedWriter, comptime format: []const u8, args: anytype) anyerror!void { | ||
| 163 | return std.fmt.format(bw, format, args); | ||
| 164 | } | ||
| 165 | |||
| 166 | pub 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. | ||
| 202 | pub 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`. | ||
| 210 | pub 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. | ||
| 278 | pub 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`. | ||
| 286 | pub 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. | ||
| 324 | pub 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 | |||
| 330 | pub 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 | |||
| 336 | pub 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 | |||
| 347 | pub 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 | |||
| 358 | fn 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 | |||
| 435 | pub 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 | |||
| 451 | pub 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 | |||
| 483 | fn 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 | |||
| 500 | pub 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 | |||
| 531 | pub 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 | |||
| 535 | pub 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 | |||
| 560 | pub 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 | |||
| 796 | pub 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 | |||
| 844 | pub fn printAsciiChar(bw: *BufferedWriter, c: u8, options: std.fmt.Options) anyerror!void { | ||
| 845 | return alignBufferOptions(bw, @as(*const [1]u8, &c), options); | ||
| 846 | } | ||
| 847 | |||
| 848 | pub fn printAscii(bw: *BufferedWriter, bytes: []const u8, options: std.fmt.Options) anyerror!void { | ||
| 849 | return alignBufferOptions(bw, bytes, options); | ||
| 850 | } | ||
| 851 | |||
| 852 | pub 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 | |||
| 858 | pub 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 | |||
| 926 | pub 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 | |||
| 958 | pub 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 | |||
| 1057 | pub 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 | ||
| 1067 | pub 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 | ||
| 1124 | const ANY = "any"; | ||
| 1125 | |||
| 1126 | fn 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 | |||
| 1144 | fn 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 | |||
| 1151 | pub fn invalidFmtError(comptime fmt: []const u8, value: anytype) noreturn { | ||
| 1152 | @compileError("invalid format string '" ++ fmt ++ "' for type '" ++ @typeName(@TypeOf(value)) ++ "'"); | ||
| 1153 | } | ||
| 1154 | |||
| 1155 | pub fn printDurationSigned(bw: *BufferedWriter, ns: i64) anyerror!void { | ||
| 1156 | if (ns < 0) try bw.writeByte('-'); | ||
| 1157 | return printDurationUnsigned(bw, @abs(ns)); | ||
| 1158 | } | ||
| 1159 | |||
| 1160 | pub 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`. | ||
| 1208 | pub 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 | |||
| 1220 | pub 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 | |||
| 1231 | test "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 | |||
| 1307 | test 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 | |||
| 1344 | test 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 | |||
| 1412 | fn 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 | |||
| 1420 | fn 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 | |||
| 1428 | test 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 | |||
| 1446 | test "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 | |||
| 1454 | test "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 | |||
| 1463 | fn 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 | |||
| 1471 | test 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 | |||
| 1486 | test "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 @@ | ||
| 1 | const std = @import("../std.zig"); | ||
| 2 | const CountingWriter = @This(); | ||
| 3 | const assert = std.debug.assert; | ||
| 4 | const native_endian = @import("builtin").target.cpu.arch.endian(); | ||
| 5 | const Writer = std.io.Writer; | ||
| 6 | const testing = std.testing; | ||
| 7 | |||
| 8 | /// Underlying stream to passthrough bytes to. | ||
| 9 | child_writer: Writer, | ||
| 10 | bytes_written: u64 = 0, | ||
| 11 | |||
| 12 | pub fn writer(cw: *CountingWriter) Writer { | ||
| 13 | return .{ | ||
| 14 | .context = cw, | ||
| 15 | .vtable = &.{ | ||
| 16 | .writev = passthru_writev, | ||
| 17 | .writeFile = passthru_writeFile, | ||
| 18 | }, | ||
| 19 | }; | ||
| 20 | } | ||
| 21 | |||
| 22 | pub fn unbufferedWriter(cw: *CountingWriter) std.io.BufferedWriter { | ||
| 23 | return .{ | ||
| 24 | .buffer = &.{}, | ||
| 25 | .unbuffered_writer = writer(cw), | ||
| 26 | }; | ||
| 27 | } | ||
| 28 | |||
| 29 | fn 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 | |||
| 36 | fn 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 | |||
| 50 | test 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 | |||
| 3 | const std = @import("../std.zig"); | ||
| 4 | const io = std.io; | ||
| 5 | const testing = std.testing; | ||
| 6 | const mem = std.mem; | ||
| 7 | const assert = std.debug.assert; | ||
| 8 | const FixedBufferStream = @This(); | ||
| 9 | |||
| 10 | buffer: []const u8, | ||
| 11 | pos: usize = 0, | ||
| 12 | |||
| 13 | pub const ReadError = error{}; | ||
| 14 | pub const SeekError = error{}; | ||
| 15 | pub const GetSeekPosError = error{}; | ||
| 16 | |||
| 17 | pub const Reader = io.Reader(*Self, ReadError, read); | ||
| 18 | |||
| 19 | pub const SeekableStream = io.SeekableStream( | ||
| 20 | *Self, | ||
| 21 | SeekError, | ||
| 22 | GetSeekPosError, | ||
| 23 | seekTo, | ||
| 24 | seekBy, | ||
| 25 | getPos, | ||
| 26 | getEndPos, | ||
| 27 | ); | ||
| 28 | |||
| 29 | const Self = @This(); | ||
| 30 | |||
| 31 | pub fn reader(self: *Self) Reader { | ||
| 32 | return .{ .context = self }; | ||
| 33 | } | ||
| 34 | |||
| 35 | pub fn seekableStream(self: *Self) SeekableStream { | ||
| 36 | return .{ .context = self }; | ||
| 37 | } | ||
| 38 | |||
| 39 | pub 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 | |||
| 49 | pub fn seekTo(self: *Self, pos: u64) SeekError!void { | ||
| 50 | self.pos = @min(std.math.lossyCast(usize, pos), self.buffer.len); | ||
| 51 | } | ||
| 52 | |||
| 53 | pub 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 | |||
| 69 | pub fn getEndPos(self: *Self) GetSeekPosError!u64 { | ||
| 70 | return self.buffer.len; | ||
| 71 | } | ||
| 72 | |||
| 73 | pub fn getPos(self: *Self) GetSeekPosError!u64 { | ||
| 74 | return self.pos; | ||
| 75 | } | ||
| 76 | |||
| 77 | pub fn getWritten(self: Self) []const u8 { | ||
| 78 | return self.buffer[0..self.pos]; | ||
| 79 | } | ||
| 80 | |||
| 81 | pub fn reset(self: *Self) void { | ||
| 82 | self.pos = 0; | ||
| 83 | } | ||
| 84 | |||
| 85 | test "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 | |||
| 94 | test "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 | |||
| 105 | test "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 | |||
| 128 | test "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 @@ | ... | @@ -1,83 +1,100 @@ |
| 1 | const std = @import("../std.zig"); | 1 | const std = @import("../std.zig"); |
| 2 | const assert = std.debug.assert; | 2 | const assert = std.debug.assert; |
| 3 | const mem = std.mem; | 3 | const Writer = @This(); |
| 4 | const native_endian = @import("builtin").target.cpu.arch.endian(); | ||
| 5 | 4 | ||
| 6 | context: *const anyopaque, | 5 | context: *anyopaque, |
| 7 | writeFn: *const fn (context: *const anyopaque, bytes: []const u8) anyerror!usize, | 6 | vtable: *const VTable, |
| 8 | 7 | ||
| 9 | const Self = @This(); | 8 | pub const VTable = struct { |
| 10 | pub const Error = anyerror; | 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, | ||
| 11 | 17 | ||
| 12 | pub fn write(self: Self, bytes: []const u8) anyerror!usize { | 18 | /// Writes contents from an open file. `headers` are written first, then `len` |
| 13 | return self.writeFn(self.context, bytes); | 19 | /// bytes of `file` starting from `offset`, then `trailers`. |
| 14 | } | 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, | ||
| 15 | 38 | ||
| 16 | pub fn writeAll(self: Self, bytes: []const u8) anyerror!void { | 39 | pub const FileLen = enum(u64) { |
| 17 | var index: usize = 0; | 40 | zero = 0, |
| 18 | while (index != bytes.len) { | 41 | entire_file = std.math.maxInt(u64), |
| 19 | index += try self.write(bytes[index..]); | 42 | _, |
| 20 | } | ||
| 21 | } | ||
| 22 | 43 | ||
| 23 | pub fn print(self: Self, comptime format: []const u8, args: anytype) anyerror!void { | 44 | pub fn init(integer: u64) FileLen { |
| 24 | return std.fmt.format(self, format, args); | 45 | const result: FileLen = @enumFromInt(integer); |
| 25 | } | 46 | assert(result != .none); |
| 26 | 47 | return result; | |
| 27 | pub fn writeByte(self: Self, byte: u8) anyerror!void { | 48 | } |
| 28 | const array = [1]u8{byte}; | ||
| 29 | return self.writeAll(&array); | ||
| 30 | } | ||
| 31 | 49 | ||
| 32 | pub fn writeByteNTimes(self: Self, byte: u8, n: usize) anyerror!void { | 50 | pub fn int(len: FileLen) u64 { |
| 33 | var bytes: [256]u8 = undefined; | 51 | return @intFromEnum(len); |
| 34 | @memset(bytes[0..], byte); | 52 | } |
| 53 | }; | ||
| 54 | }; | ||
| 35 | 55 | ||
| 36 | var remaining: usize = n; | 56 | pub fn writev(w: Writer, data: []const []const u8) anyerror!usize { |
| 37 | while (remaining > 0) { | 57 | return w.vtable.writev(w.context, data); |
| 38 | const to_write = @min(remaining, bytes.len); | ||
| 39 | try self.writeAll(bytes[0..to_write]); | ||
| 40 | remaining -= to_write; | ||
| 41 | } | ||
| 42 | } | 58 | } |
| 43 | 59 | ||
| 44 | pub fn writeBytesNTimes(self: Self, bytes: []const u8, n: usize) anyerror!void { | 60 | pub fn writeFile( |
| 45 | var i: usize = 0; | 61 | w: Writer, |
| 46 | while (i < n) : (i += 1) { | 62 | file: std.fs.File, |
| 47 | try self.writeAll(bytes); | 63 | offset: u64, |
| 48 | } | 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); | ||
| 49 | } | 69 | } |
| 50 | 70 | ||
| 51 | pub inline fn writeInt(self: Self, comptime T: type, value: T, endian: std.builtin.Endian) anyerror!void { | 71 | pub fn write(w: Writer, bytes: []const u8) anyerror!usize { |
| 52 | var bytes: [@divExact(@typeInfo(T).int.bits, 8)]u8 = undefined; | 72 | const single: [1][]const u8 = .{bytes}; |
| 53 | mem.writeInt(std.math.ByteAlignedInt(@TypeOf(value)), &bytes, value, endian); | 73 | return w.vtable.writev(w.context, &single); |
| 54 | return self.writeAll(&bytes); | ||
| 55 | } | 74 | } |
| 56 | 75 | ||
| 57 | pub fn writeStruct(self: Self, value: anytype) anyerror!void { | 76 | pub fn writeAll(w: Writer, bytes: []const u8) anyerror!void { |
| 58 | // Only extern and packed structs have defined in-memory layout. | 77 | var index: usize = 0; |
| 59 | comptime assert(@typeInfo(@TypeOf(value)).@"struct".layout != .auto); | 78 | while (index < bytes.len) index += try write(w, bytes[index..]); |
| 60 | return self.writeAll(mem.asBytes(&value)); | ||
| 61 | } | 79 | } |
| 62 | 80 | ||
| 63 | pub fn writeStructEndian(self: Self, value: anytype, endian: std.builtin.Endian) anyerror!void { | 81 | ///// Directly calls `writeAll` many times to render the formatted text. To |
| 64 | // TODO: make sure this value is not a reference type | 82 | ///// enable buffering, call `std.io.BufferedWriter.print` instead. |
| 65 | if (native_endian == endian) { | 83 | //pub fn unbufferedPrint(w: Writer, comptime format: []const u8, args: anytype) anyerror!void { |
| 66 | return self.writeStruct(value); | 84 | // return std.fmt.format(w, format, args); |
| 67 | } else { | 85 | //} |
| 68 | var copy = value; | ||
| 69 | mem.byteSwapAllFields(@TypeOf(value), &copy); | ||
| 70 | return self.writeStruct(copy); | ||
| 71 | } | ||
| 72 | } | ||
| 73 | 86 | ||
| 74 | pub fn writeFile(self: Self, file: std.fs.File) anyerror!void { | 87 | /// The `data` parameter is mutable because this function needs to mutate the |
| 75 | // TODO: figure out how to adjust std lib abstractions so that this ends up | 88 | /// fields in order to handle partial writes from `VTable.writev`. |
| 76 | // doing sendfile or maybe even copy_file_range under the right conditions. | 89 | pub fn writevAll(w: Writer, data: [][]const u8) anyerror!void { |
| 77 | var buf: [4000]u8 = undefined; | 90 | var i: usize = 0; |
| 78 | while (true) { | 91 | while (true) { |
| 79 | const n = try file.readAll(&buf); | 92 | var n = try w.vtable.writev(w.context, data[i..]); |
| 80 | try self.writeAll(buf[0..n]); | 93 | while (n >= data[i].len) { |
| 81 | if (n < buf.len) return; | 94 | n -= data[i].len; |
| 95 | i += 1; | ||
| 96 | if (i >= data.len) return; | ||
| 97 | } | ||
| 98 | data[i] = data[i][n..]; | ||
| 82 | } | 99 | } |
| 83 | } | 100 | } |
lib/std/io/buffered_writer.zig deleted-43| ... | @@ -1,43 +0,0 @@ | ||
| 1 | const std = @import("../std.zig"); | ||
| 2 | |||
| 3 | const io = std.io; | ||
| 4 | const mem = std.mem; | ||
| 5 | |||
| 6 | pub 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 | |||
| 41 | pub 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 @@ | ||
| 1 | const std = @import("../std.zig"); | ||
| 2 | const io = std.io; | ||
| 3 | const testing = std.testing; | ||
| 4 | |||
| 5 | /// A Writer that counts how many bytes has been written to it. | ||
| 6 | pub 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 | |||
| 28 | pub fn countingWriter(child_stream: anytype) CountingWriter(@TypeOf(child_stream)) { | ||
| 29 | return .{ .bytes_written = 0, .child_stream = child_stream }; | ||
| 30 | } | ||
| 31 | |||
| 32 | test 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 @@ | ||
| 1 | const std = @import("../std.zig"); | ||
| 2 | const io = std.io; | ||
| 3 | const testing = std.testing; | ||
| 4 | const mem = std.mem; | ||
| 5 | const 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. | ||
| 9 | pub 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 | |||
| 112 | pub fn fixedBufferStream(buffer: anytype) FixedBufferStream(Slice(@TypeOf(buffer))) { | ||
| 113 | return .{ .buffer = buffer, .pos = 0 }; | ||
| 114 | } | ||
| 115 | |||
| 116 | fn 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 | |||
| 135 | test "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 | |||
| 144 | test "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 | |||
| 155 | test "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 | |||
| 178 | test "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( | ... | @@ -148,14 +148,15 @@ pub fn defaultLog( |
| 148 | ) void { | 148 | ) void { |
| 149 | const level_txt = comptime message_level.asText(); | 149 | const level_txt = comptime message_level.asText(); |
| 150 | const prefix2 = if (scope == .default) ": " else "(" ++ @tagName(scope) ++ "): "; | 150 | const prefix2 = if (scope == .default) ": " else "(" ++ @tagName(scope) ++ "): "; |
| 151 | const stderr = std.io.getStdErr().writer(); | 151 | var buffer: [1024]u8 = undefined; |
| 152 | var bw = std.io.bufferedWriter(stderr); | 152 | var bw: std.io.BufferedWriter = .{ |
| 153 | const writer = bw.writer(); | 153 | .unbuffered_writer = std.io.getStdErr().writer(), |
| 154 | 154 | .buffer = &buffer, | |
| 155 | }; | ||
| 155 | std.debug.lockStdErr(); | 156 | std.debug.lockStdErr(); |
| 156 | defer std.debug.unlockStdErr(); | 157 | defer std.debug.unlockStdErr(); |
| 157 | nosuspend { | 158 | nosuspend { |
| 158 | writer.print(level_txt ++ prefix2 ++ format ++ "\n", args) catch return; | 159 | bw.print(level_txt ++ prefix2 ++ format ++ "\n", args) catch return; |
| 159 | bw.flush() catch return; | 160 | bw.flush() catch return; |
| 160 | } | 161 | } |
| 161 | } | 162 | } |
lib/std/os/uefi.zig+7-9| ... | @@ -67,19 +67,17 @@ pub const Guid = extern struct { | ... | @@ -67,19 +67,17 @@ pub const Guid = extern struct { |
| 67 | ) !void { | 67 | ) !void { |
| 68 | _ = options; | 68 | _ = options; |
| 69 | if (f.len == 0) { | 69 | if (f.len == 0) { |
| 70 | const fmt = std.fmt.fmtSliceHexLower; | ||
| 71 | |||
| 72 | const time_low = @byteSwap(self.time_low); | 70 | const time_low = @byteSwap(self.time_low); |
| 73 | const time_mid = @byteSwap(self.time_mid); | 71 | const time_mid = @byteSwap(self.time_mid); |
| 74 | const time_high_and_version = @byteSwap(self.time_high_and_version); | 72 | const time_high_and_version = @byteSwap(self.time_high_and_version); |
| 75 | 73 | ||
| 76 | return std.fmt.format(writer, "{:0>8}-{:0>4}-{:0>4}-{:0>2}{:0>2}-{:0>12}", .{ | 74 | return std.fmt.format(writer, "{x:0>8}-{x:0>4}-{x:0>4}-{x:0>2}{x:0>2}-{x:0>12}", .{ |
| 77 | fmt(std.mem.asBytes(&time_low)), | 75 | std.mem.asBytes(&time_low), |
| 78 | fmt(std.mem.asBytes(&time_mid)), | 76 | std.mem.asBytes(&time_mid), |
| 79 | fmt(std.mem.asBytes(&time_high_and_version)), | 77 | std.mem.asBytes(&time_high_and_version), |
| 80 | fmt(std.mem.asBytes(&self.clock_seq_high_and_reserved)), | 78 | std.mem.asBytes(&self.clock_seq_high_and_reserved), |
| 81 | fmt(std.mem.asBytes(&self.clock_seq_low)), | 79 | std.mem.asBytes(&self.clock_seq_low), |
| 82 | fmt(std.mem.asBytes(&self.node)), | 80 | std.mem.asBytes(&self.node), |
| 83 | }); | 81 | }); |
| 84 | } else { | 82 | } else { |
| 85 | std.fmt.invalidFmtError(f, self); | 83 | std.fmt.invalidFmtError(f, self); |