| ... | @@ -381,14 +381,15 @@ pub const Int = struct { | ... | @@ -381,14 +381,15 @@ pub const Int = struct { |
| 381 | return if (d < base) d else return error.DigitTooLargeForBase; | 381 | return if (d < base) d else return error.DigitTooLargeForBase; |
| 382 | } | 382 | } |
| 383 | | 383 | |
| 384 | fn digitToChar(d: u8, base: u8) !u8 { | 384 | fn digitToChar(d: u8, base: u8, uppercase: bool) !u8 { |
| 385 | if (d >= base) { | 385 | if (d >= base) { |
| 386 | return error.DigitTooLargeForBase; | 386 | return error.DigitTooLargeForBase; |
| 387 | } | 387 | } |
| 388 | | 388 | |
| | 389 | const a: u8 = if (uppercase) 'A' else 'a'; |
| 389 | return switch (d) { | 390 | return switch (d) { |
| 390 | 0...9 => '0' + d, | 391 | 0...9 => '0' + d, |
| 391 | 0xa...0xf => ('a' - 0xa) + d, | 392 | 0xa...0xf => (a - 0xa) + d, |
| 392 | else => unreachable, | 393 | else => unreachable, |
| 393 | }; | 394 | }; |
| 394 | } | 395 | } |
| ... | @@ -434,7 +435,7 @@ pub const Int = struct { | ... | @@ -434,7 +435,7 @@ pub const Int = struct { |
| 434 | /// Converts self to a string in the requested base. Memory is allocated from the provided | 435 | /// Converts self to a string in the requested base. Memory is allocated from the provided |
| 435 | /// allocator and not the one present in self. | 436 | /// allocator and not the one present in self. |
| 436 | /// TODO make this call format instead of the other way around | 437 | /// TODO make this call format instead of the other way around |
| 437 | pub fn toString(self: Int, allocator: *Allocator, base: u8) ![]const u8 { | 438 | pub fn toString(self: Int, allocator: *Allocator, base: u8, uppercase: bool) ![]const u8 { |
| 438 | if (base < 2 or base > 16) { | 439 | if (base < 2 or base > 16) { |
| 439 | return error.InvalidBase; | 440 | return error.InvalidBase; |
| 440 | } | 441 | } |
| ... | @@ -456,7 +457,7 @@ pub const Int = struct { | ... | @@ -456,7 +457,7 @@ pub const Int = struct { |
| 456 | var shift: usize = 0; | 457 | var shift: usize = 0; |
| 457 | while (shift < Limb.bit_count) : (shift += base_shift) { | 458 | while (shift < Limb.bit_count) : (shift += base_shift) { |
| 458 | const r = @intCast(u8, (limb >> @intCast(Log2Limb, shift)) & @as(Limb, base - 1)); | 459 | const r = @intCast(u8, (limb >> @intCast(Log2Limb, shift)) & @as(Limb, base - 1)); |
| 459 | const ch = try digitToChar(r, base); | 460 | const ch = try digitToChar(r, base, uppercase); |
| 460 | try digits.append(ch); | 461 | try digits.append(ch); |
| 461 | } | 462 | } |
| 462 | } | 463 | } |
| ... | @@ -492,7 +493,7 @@ pub const Int = struct { | ... | @@ -492,7 +493,7 @@ pub const Int = struct { |
| 492 | var r_word = r.limbs[0]; | 493 | var r_word = r.limbs[0]; |
| 493 | var i: usize = 0; | 494 | var i: usize = 0; |
| 494 | while (i < digits_per_limb) : (i += 1) { | 495 | while (i < digits_per_limb) : (i += 1) { |
| 495 | const ch = try digitToChar(@intCast(u8, r_word % base), base); | 496 | const ch = try digitToChar(@intCast(u8, r_word % base), base, uppercase); |
| 496 | r_word /= base; | 497 | r_word /= base; |
| 497 | try digits.append(ch); | 498 | try digits.append(ch); |
| 498 | } | 499 | } |
| ... | @@ -503,7 +504,7 @@ pub const Int = struct { | ... | @@ -503,7 +504,7 @@ pub const Int = struct { |
| 503 | | 504 | |
| 504 | var r_word = q.limbs[0]; | 505 | var r_word = q.limbs[0]; |
| 505 | while (r_word != 0) { | 506 | while (r_word != 0) { |
| 506 | const ch = try digitToChar(@intCast(u8, r_word % base), base); | 507 | const ch = try digitToChar(@intCast(u8, r_word % base), base, uppercase); |
| 507 | r_word /= base; | 508 | r_word /= base; |
| 508 | try digits.append(ch); | 509 | try digits.append(ch); |
| 509 | } | 510 | } |
| ... | @@ -528,9 +529,28 @@ pub const Int = struct { | ... | @@ -528,9 +529,28 @@ pub const Int = struct { |
| 528 | out_stream: var, | 529 | out_stream: var, |
| 529 | ) !void { | 530 | ) !void { |
| 530 | self.assertWritable(); | 531 | self.assertWritable(); |
| 531 | // TODO look at fmt and support other bases | | |
| 532 | // TODO support read-only fixed integers | 532 | // TODO support read-only fixed integers |
| 533 | const str = self.toString(self.allocator.?, 10) catch @panic("TODO make this non allocating"); | 533 | |
| | 534 | comptime var radix = 10; |
| | 535 | comptime var uppercase = false; |
| | 536 | |
| | 537 | if (fmt.len == 0 or comptime std.mem.eql(u8, fmt, "d")) { |
| | 538 | radix = 10; |
| | 539 | uppercase = false; |
| | 540 | } else if (comptime std.mem.eql(u8, fmt, "b")) { |
| | 541 | radix = 2; |
| | 542 | uppercase = false; |
| | 543 | } else if (comptime std.mem.eql(u8, fmt, "x")) { |
| | 544 | radix = 16; |
| | 545 | uppercase = false; |
| | 546 | } else if (comptime std.mem.eql(u8, fmt, "X")) { |
| | 547 | radix = 16; |
| | 548 | uppercase = true; |
| | 549 | } else { |
| | 550 | @compileError("Unknown format string: '" ++ fmt ++ "'"); |
| | 551 | } |
| | 552 | |
| | 553 | const str = self.toString(self.allocator.?, radix, uppercase) catch @panic("TODO make this non allocating"); |
| 534 | defer self.allocator.?.free(str); | 554 | defer self.allocator.?.free(str); |
| 535 | return out_stream.writeAll(str); | 555 | return out_stream.writeAll(str); |
| 536 | } | 556 | } |
| ... | @@ -1746,7 +1766,7 @@ test "big.int string to" { | ... | @@ -1746,7 +1766,7 @@ test "big.int string to" { |
| 1746 | const a = try Int.initSet(testing.allocator, 120317241209124781241290847124); | 1766 | const a = try Int.initSet(testing.allocator, 120317241209124781241290847124); |
| 1747 | defer a.deinit(); | 1767 | defer a.deinit(); |
| 1748 | | 1768 | |
| 1749 | const as = try a.toString(testing.allocator, 10); | 1769 | const as = try a.toString(testing.allocator, 10, false); |
| 1750 | defer testing.allocator.free(as); | 1770 | defer testing.allocator.free(as); |
| 1751 | const es = "120317241209124781241290847124"; | 1771 | const es = "120317241209124781241290847124"; |
| 1752 | | 1772 | |
| ... | @@ -1757,14 +1777,14 @@ test "big.int string to base base error" { | ... | @@ -1757,14 +1777,14 @@ test "big.int string to base base error" { |
| 1757 | const a = try Int.initSet(testing.allocator, 0xffffffff); | 1777 | const a = try Int.initSet(testing.allocator, 0xffffffff); |
| 1758 | defer a.deinit(); | 1778 | defer a.deinit(); |
| 1759 | | 1779 | |
| 1760 | testing.expectError(error.InvalidBase, a.toString(testing.allocator, 45)); | 1780 | testing.expectError(error.InvalidBase, a.toString(testing.allocator, 45, false)); |
| 1761 | } | 1781 | } |
| 1762 | | 1782 | |
| 1763 | test "big.int string to base 2" { | 1783 | test "big.int string to base 2" { |
| 1764 | const a = try Int.initSet(testing.allocator, -0b1011); | 1784 | const a = try Int.initSet(testing.allocator, -0b1011); |
| 1765 | defer a.deinit(); | 1785 | defer a.deinit(); |
| 1766 | | 1786 | |
| 1767 | const as = try a.toString(testing.allocator, 2); | 1787 | const as = try a.toString(testing.allocator, 2, false); |
| 1768 | defer testing.allocator.free(as); | 1788 | defer testing.allocator.free(as); |
| 1769 | const es = "-1011"; | 1789 | const es = "-1011"; |
| 1770 | | 1790 | |
| ... | @@ -1775,7 +1795,7 @@ test "big.int string to base 16" { | ... | @@ -1775,7 +1795,7 @@ test "big.int string to base 16" { |
| 1775 | const a = try Int.initSet(testing.allocator, 0xefffffff00000001eeeeeeefaaaaaaab); | 1795 | const a = try Int.initSet(testing.allocator, 0xefffffff00000001eeeeeeefaaaaaaab); |
| 1776 | defer a.deinit(); | 1796 | defer a.deinit(); |
| 1777 | | 1797 | |
| 1778 | const as = try a.toString(testing.allocator, 16); | 1798 | const as = try a.toString(testing.allocator, 16, false); |
| 1779 | defer testing.allocator.free(as); | 1799 | defer testing.allocator.free(as); |
| 1780 | const es = "efffffff00000001eeeeeeefaaaaaaab"; | 1800 | const es = "efffffff00000001eeeeeeefaaaaaaab"; |
| 1781 | | 1801 | |
| ... | @@ -1786,7 +1806,7 @@ test "big.int neg string to" { | ... | @@ -1786,7 +1806,7 @@ test "big.int neg string to" { |
| 1786 | const a = try Int.initSet(testing.allocator, -123907434); | 1806 | const a = try Int.initSet(testing.allocator, -123907434); |
| 1787 | defer a.deinit(); | 1807 | defer a.deinit(); |
| 1788 | | 1808 | |
| 1789 | const as = try a.toString(testing.allocator, 10); | 1809 | const as = try a.toString(testing.allocator, 10, false); |
| 1790 | defer testing.allocator.free(as); | 1810 | defer testing.allocator.free(as); |
| 1791 | const es = "-123907434"; | 1811 | const es = "-123907434"; |
| 1792 | | 1812 | |
| ... | @@ -1797,7 +1817,7 @@ test "big.int zero string to" { | ... | @@ -1797,7 +1817,7 @@ test "big.int zero string to" { |
| 1797 | const a = try Int.initSet(testing.allocator, 0); | 1817 | const a = try Int.initSet(testing.allocator, 0); |
| 1798 | defer a.deinit(); | 1818 | defer a.deinit(); |
| 1799 | | 1819 | |
| 1800 | const as = try a.toString(testing.allocator, 10); | 1820 | const as = try a.toString(testing.allocator, 10, false); |
| 1801 | defer testing.allocator.free(as); | 1821 | defer testing.allocator.free(as); |
| 1802 | const es = "0"; | 1822 | const es = "0"; |
| 1803 | | 1823 | |
| ... | @@ -2628,7 +2648,7 @@ test "big.int div multi-multi zero-limb trailing (with rem)" { | ... | @@ -2628,7 +2648,7 @@ test "big.int div multi-multi zero-limb trailing (with rem)" { |
| 2628 | | 2648 | |
| 2629 | testing.expect((try q.to(u128)) == 0x10000000000000000); | 2649 | testing.expect((try q.to(u128)) == 0x10000000000000000); |
| 2630 | | 2650 | |
| 2631 | const rs = try r.toString(testing.allocator, 16); | 2651 | const rs = try r.toString(testing.allocator, 16, false); |
| 2632 | defer testing.allocator.free(rs); | 2652 | defer testing.allocator.free(rs); |
| 2633 | testing.expect(std.mem.eql(u8, rs, "4444444344444443111111111111111100000000000000000000000000000000")); | 2653 | testing.expect(std.mem.eql(u8, rs, "4444444344444443111111111111111100000000000000000000000000000000")); |
| 2634 | } | 2654 | } |
| ... | @@ -2647,7 +2667,7 @@ test "big.int div multi-multi zero-limb trailing (with rem) and dividend zero-li | ... | @@ -2647,7 +2667,7 @@ test "big.int div multi-multi zero-limb trailing (with rem) and dividend zero-li |
| 2647 | | 2667 | |
| 2648 | testing.expect((try q.to(u128)) == 0x1); | 2668 | testing.expect((try q.to(u128)) == 0x1); |
| 2649 | | 2669 | |
| 2650 | const rs = try r.toString(testing.allocator, 16); | 2670 | const rs = try r.toString(testing.allocator, 16, false); |
| 2651 | defer testing.allocator.free(rs); | 2671 | defer testing.allocator.free(rs); |
| 2652 | testing.expect(std.mem.eql(u8, rs, "444444434444444311111111111111110000000000000000")); | 2672 | testing.expect(std.mem.eql(u8, rs, "444444434444444311111111111111110000000000000000")); |
| 2653 | } | 2673 | } |
| ... | @@ -2664,11 +2684,11 @@ test "big.int div multi-multi zero-limb trailing (with rem) and dividend zero-li | ... | @@ -2664,11 +2684,11 @@ test "big.int div multi-multi zero-limb trailing (with rem) and dividend zero-li |
| 2664 | defer r.deinit(); | 2684 | defer r.deinit(); |
| 2665 | try Int.divTrunc(&q, &r, a, b); | 2685 | try Int.divTrunc(&q, &r, a, b); |
| 2666 | | 2686 | |
| 2667 | const qs = try q.toString(testing.allocator, 16); | 2687 | const qs = try q.toString(testing.allocator, 16, false); |
| 2668 | defer testing.allocator.free(qs); | 2688 | defer testing.allocator.free(qs); |
| 2669 | testing.expect(std.mem.eql(u8, qs, "10000000000000000820820803105186f")); | 2689 | testing.expect(std.mem.eql(u8, qs, "10000000000000000820820803105186f")); |
| 2670 | | 2690 | |
| 2671 | const rs = try r.toString(testing.allocator, 16); | 2691 | const rs = try r.toString(testing.allocator, 16, false); |
| 2672 | defer testing.allocator.free(rs); | 2692 | defer testing.allocator.free(rs); |
| 2673 | testing.expect(std.mem.eql(u8, rs, "4e11f2baa5896a321d463b543d0104e30000000000000000")); | 2693 | testing.expect(std.mem.eql(u8, rs, "4e11f2baa5896a321d463b543d0104e30000000000000000")); |
| 2674 | } | 2694 | } |
| ... | @@ -2688,11 +2708,11 @@ test "big.int div multi-multi fuzz case #1" { | ... | @@ -2688,11 +2708,11 @@ test "big.int div multi-multi fuzz case #1" { |
| 2688 | defer r.deinit(); | 2708 | defer r.deinit(); |
| 2689 | try Int.divTrunc(&q, &r, a, b); | 2709 | try Int.divTrunc(&q, &r, a, b); |
| 2690 | | 2710 | |
| 2691 | const qs = try q.toString(testing.allocator, 16); | 2711 | const qs = try q.toString(testing.allocator, 16, false); |
| 2692 | defer testing.allocator.free(qs); | 2712 | defer testing.allocator.free(qs); |
| 2693 | testing.expect(std.mem.eql(u8, qs, "3ffffffffffffffffffffffffffff0000000000000000000000000000000000001ffffffffffffffffffffffffffff7fffffffe000000000000000000000000000180000000000000000000003fffffbfffffffdfffffffffffffeffff800000100101000000100000000020003fffffdfbfffffe3ffffffffffffeffff7fffc00800a100000017ffe000002000400007efbfff7fe9f00000037ffff3fff7fffa004006100000009ffe00000190038200bf7d2ff7fefe80400060000f7d7f8fbf9401fe38e0403ffc0bdffffa51102c300d7be5ef9df4e5060007b0127ad3fa69f97d0f820b6605ff617ddf7f32ad7a05c0d03f2e7bc78a6000e087a8bbcdc59e07a5a079128a7861f553ddebed7e8e56701756f9ead39b48cd1b0831889ea6ec1fddf643d0565b075ff07e6caea4e2854ec9227fd635ed60a2f5eef2893052ffd54718fa08604acbf6a15e78a467c4a3c53c0278af06c4416573f925491b195e8fd79302cb1aaf7caf4ecfc9aec1254cc969786363ac729f914c6ddcc26738d6b0facd54eba026580aba2eb6482a088b0d224a8852420b91ec1")); | 2713 | testing.expect(std.mem.eql(u8, qs, "3ffffffffffffffffffffffffffff0000000000000000000000000000000000001ffffffffffffffffffffffffffff7fffffffe000000000000000000000000000180000000000000000000003fffffbfffffffdfffffffffffffeffff800000100101000000100000000020003fffffdfbfffffe3ffffffffffffeffff7fffc00800a100000017ffe000002000400007efbfff7fe9f00000037ffff3fff7fffa004006100000009ffe00000190038200bf7d2ff7fefe80400060000f7d7f8fbf9401fe38e0403ffc0bdffffa51102c300d7be5ef9df4e5060007b0127ad3fa69f97d0f820b6605ff617ddf7f32ad7a05c0d03f2e7bc78a6000e087a8bbcdc59e07a5a079128a7861f553ddebed7e8e56701756f9ead39b48cd1b0831889ea6ec1fddf643d0565b075ff07e6caea4e2854ec9227fd635ed60a2f5eef2893052ffd54718fa08604acbf6a15e78a467c4a3c53c0278af06c4416573f925491b195e8fd79302cb1aaf7caf4ecfc9aec1254cc969786363ac729f914c6ddcc26738d6b0facd54eba026580aba2eb6482a088b0d224a8852420b91ec1")); |
| 2694 | | 2714 | |
| 2695 | const rs = try r.toString(testing.allocator, 16); | 2715 | const rs = try r.toString(testing.allocator, 16, false); |
| 2696 | defer testing.allocator.free(rs); | 2716 | defer testing.allocator.free(rs); |
| 2697 | testing.expect(std.mem.eql(u8, rs, "310d1d4c414426b4836c2635bad1df3a424e50cbdd167ffccb4dfff57d36b4aae0d6ca0910698220171a0f3373c1060a046c2812f0027e321f72979daa5e7973214170d49e885de0c0ecc167837d44502430674a82522e5df6a0759548052420b91ec1")); | 2717 | testing.expect(std.mem.eql(u8, rs, "310d1d4c414426b4836c2635bad1df3a424e50cbdd167ffccb4dfff57d36b4aae0d6ca0910698220171a0f3373c1060a046c2812f0027e321f72979daa5e7973214170d49e885de0c0ecc167837d44502430674a82522e5df6a0759548052420b91ec1")); |
| 2698 | } | 2718 | } |
| ... | @@ -2712,11 +2732,11 @@ test "big.int div multi-multi fuzz case #2" { | ... | @@ -2712,11 +2732,11 @@ test "big.int div multi-multi fuzz case #2" { |
| 2712 | defer r.deinit(); | 2732 | defer r.deinit(); |
| 2713 | try Int.divTrunc(&q, &r, a, b); | 2733 | try Int.divTrunc(&q, &r, a, b); |
| 2714 | | 2734 | |
| 2715 | const qs = try q.toString(testing.allocator, 16); | 2735 | const qs = try q.toString(testing.allocator, 16, false); |
| 2716 | defer testing.allocator.free(qs); | 2736 | defer testing.allocator.free(qs); |
| 2717 | testing.expect(std.mem.eql(u8, qs, "40100400fe3f8fe3f8fe3f8fe3f8fe3f8fe4f93e4f93e4f93e4f93e4f93e4f93e4f93e4f93e4f93e4f93e4f93e4f91e4791e4791e4791e4791e4791e4791e4791e4791e4791e4791e4791e4791e4992649926499264991e4791e4791e4791e4791e4791e4791e4791e4791e4791e4791e4791e4791e4791e4791e4791e4791e4791e4791e4791e4791e4791e4791e4791e4792e4b92e4b92e4b92e4b92a4a92a4a92a4")); | 2737 | testing.expect(std.mem.eql(u8, qs, "40100400fe3f8fe3f8fe3f8fe3f8fe3f8fe4f93e4f93e4f93e4f93e4f93e4f93e4f93e4f93e4f93e4f93e4f93e4f91e4791e4791e4791e4791e4791e4791e4791e4791e4791e4791e4791e4791e4992649926499264991e4791e4791e4791e4791e4791e4791e4791e4791e4791e4791e4791e4791e4791e4791e4791e4791e4791e4791e4791e4791e4791e4791e4791e4792e4b92e4b92e4b92e4b92a4a92a4a92a4")); |
| 2718 | | 2738 | |
| 2719 | const rs = try r.toString(testing.allocator, 16); | 2739 | const rs = try r.toString(testing.allocator, 16, false); |
| 2720 | defer testing.allocator.free(rs); | 2740 | defer testing.allocator.free(rs); |
| 2721 | testing.expect(std.mem.eql(u8, rs, "a900000000000000000000000000000000000000000000000000")); | 2741 | testing.expect(std.mem.eql(u8, rs, "a900000000000000000000000000000000000000000000000000")); |
| 2722 | } | 2742 | } |