|
14 | 14 | #ifndef bigint_DISABLE_IO |
15 | 15 | #include <iostream> |
16 | 16 | #endif |
| 17 | +#include <memory> |
17 | 18 | #include <ranges> |
18 | 19 | #include <regex> |
19 | 20 | #include <stdexcept> |
@@ -825,6 +826,15 @@ namespace bigint { |
825 | 826 | friend class bigint; |
826 | 827 |
|
827 | 828 | #ifndef bigint_DISABLE_IO |
| 829 | + template<std::size_t other_bits, bool other_is_signed> |
| 830 | + friend constexpr std::ostream &print_hex(std::ostream &, bigint<other_bits, other_is_signed> const &, bool); |
| 831 | + |
| 832 | + template<std::size_t other_bits, bool other_is_signed> |
| 833 | + friend constexpr std::ostream &print_oct(std::ostream &, bigint<other_bits, other_is_signed> const &); |
| 834 | + |
| 835 | + template<std::size_t other_bits, bool other_is_signed> |
| 836 | + friend constexpr std::ostream &print_dec(std::ostream &, bigint<other_bits, other_is_signed> const &); |
| 837 | + |
828 | 838 | template<std::size_t other_bits, bool other_is_signed> |
829 | 839 | friend constexpr std::ostream &operator<<(std::ostream &, bigint<other_bits, other_is_signed> const &); |
830 | 840 |
|
@@ -986,82 +996,122 @@ namespace bigint { |
986 | 996 | }; |
987 | 997 |
|
988 | 998 | #ifndef bigint_DISABLE_IO |
| 999 | + template<std::size_t bits, bool is_signed> |
| 1000 | + constexpr std::ostream &print_hex(std::ostream &os, bigint<bits, is_signed> const &data, bool const use_uppercase) { |
| 1001 | + auto const &buf = data.data_; |
| 1002 | + auto start = buf.size(); |
| 1003 | + while (start > 1 and buf[start - 1] == 0) { |
| 1004 | + --start; |
| 1005 | + } |
| 1006 | + |
| 1007 | + if constexpr (std::endian::native == std::endian::little) { |
| 1008 | + for (auto const i: std::views::reverse(std::views::iota(0uz, start))) { |
| 1009 | + auto local = std::array<char, 3>{}; |
| 1010 | + std::snprintf( |
| 1011 | + local.data(), |
| 1012 | + local.size(), |
| 1013 | + use_uppercase ? "%02X" : "%02x", |
| 1014 | + buf[i] |
| 1015 | + ); |
| 1016 | + os.write(local.data(), local.size() - 1); |
| 1017 | + } |
| 1018 | + } else { |
| 1019 | + for (auto const i: std::views::iota(0uz, start)) { |
| 1020 | + auto local = std::array<char, 3>{}; |
| 1021 | + std::snprintf( |
| 1022 | + local.data(), |
| 1023 | + local.size(), |
| 1024 | + use_uppercase ? "%02X" : "%02x", |
| 1025 | + buf[i] |
| 1026 | + ); |
| 1027 | + os.write(local.data(), local.size() - 1); |
| 1028 | + } |
| 1029 | + } |
| 1030 | + |
| 1031 | + return os; |
| 1032 | + } |
| 1033 | + |
| 1034 | + template<std::size_t bits, bool is_signed> |
| 1035 | + constexpr std::ostream &print_oct(std::ostream &os, bigint<bits, is_signed> const &data) { |
| 1036 | + auto temp = data; |
| 1037 | + |
| 1038 | + if (temp == std::int8_t{0}) { |
| 1039 | + os.put('0'); |
| 1040 | + return os; |
| 1041 | + } |
| 1042 | + |
| 1043 | + constexpr auto max_oct_digits = std::size_t{(bits / 3) + 2}; |
| 1044 | + auto buffer = std::array<char, max_oct_digits>{}; |
| 1045 | + auto pos = buffer.end(); |
| 1046 | + |
| 1047 | + while (temp != std::int8_t{0}) { |
| 1048 | + auto r = temp % std::int8_t{8}; |
| 1049 | + auto digit = r.data_[0]; |
| 1050 | + *--pos = static_cast<char>('0' + digit); |
| 1051 | + temp /= std::int8_t{8}; |
| 1052 | + } |
| 1053 | + |
| 1054 | + auto const length = static_cast<std::size_t>(buffer.end() - pos); |
| 1055 | + os.write(std::to_address(pos), length); |
| 1056 | + return os; |
| 1057 | + } |
| 1058 | + |
| 1059 | + template<std::size_t bits, bool is_signed> |
| 1060 | + constexpr std::ostream &print_dec(std::ostream &os, bigint<bits, is_signed> const &data) { |
| 1061 | + auto temp = data; |
| 1062 | + |
| 1063 | + if (temp == std::int8_t{0}) { |
| 1064 | + os.put('0'); |
| 1065 | + return os; |
| 1066 | + } |
| 1067 | + |
| 1068 | + auto negative = false; |
| 1069 | + if constexpr (is_signed) { |
| 1070 | + if (temp < std::int8_t{0}) { |
| 1071 | + negative = true; |
| 1072 | + temp = -temp; |
| 1073 | + } |
| 1074 | + } |
| 1075 | + |
| 1076 | + constexpr auto max_dec_digits = std::size_t{static_cast<std::size_t>(bits * 0.3010299957) + 3}; //std::log10(2) |
| 1077 | + auto buffer = std::array<char, max_dec_digits>{}; |
| 1078 | + auto pos = buffer.end(); |
| 1079 | + |
| 1080 | + while (temp != std::int8_t{0}) { |
| 1081 | + auto r = temp % std::int8_t{10}; |
| 1082 | + auto digit = r.data_[0]; |
| 1083 | + *--pos = static_cast<char>('0' + digit); |
| 1084 | + temp /= std::int8_t{10}; |
| 1085 | + } |
| 1086 | + |
| 1087 | + if (negative) { |
| 1088 | + os.put('-'); |
| 1089 | + } |
| 1090 | + |
| 1091 | + auto const length = static_cast<std::size_t>(buffer.end() - pos); |
| 1092 | + os.write(std::to_address(pos), length); |
| 1093 | + return os; |
| 1094 | + } |
| 1095 | + |
989 | 1096 | template<std::size_t bits, bool is_signed> |
990 | 1097 | constexpr std::ostream &operator<<(std::ostream &os, bigint<bits, is_signed> const &data) { |
991 | 1098 | auto const flags = os.flags(); |
992 | | - auto result = std::string{}; |
993 | | - |
994 | 1099 | auto const base_flag = flags & std::ios_base::basefield; |
995 | 1100 | auto const use_uppercase = (flags & std::ios_base::uppercase) != 0; |
996 | 1101 |
|
997 | | - if (base_flag == std::ios_base::hex) { |
998 | | - if constexpr (std::endian::native == std::endian::little) { |
999 | | - for (auto const i: std::views::reverse(std::views::iota(1uz, data.data_.size()))) { |
1000 | | - if (result.empty() and data.data_[i - 1] == 0 and i != 1) { |
1001 | | - continue; |
1002 | | - } |
1003 | | - auto buffer = std::array<char, 3>{}; |
1004 | | - std::snprintf(buffer.data(), buffer.size(), use_uppercase ? "%02X" : "%02x", data.data_[i - 1]); |
1005 | | - result.append(buffer.data()); |
1006 | | - } |
1007 | | - } else { |
1008 | | - for (auto const i: std::views::iota(0uz, data.data_.size())) { |
1009 | | - if (result.empty() and data.data_[i] == 0 and i != 1) { |
1010 | | - continue; |
1011 | | - } |
1012 | | - auto buffer = std::array<char, 3>{}; |
1013 | | - std::snprintf(buffer.data(), buffer.size(), use_uppercase ? "%02X" : "%02x", data.data_[i]); |
1014 | | - result.append(buffer.data()); |
1015 | | - } |
1016 | | - } |
1017 | | - } else if (base_flag == std::ios_base::oct) { |
1018 | | - auto temp = bigint<bits, is_signed>{data}; |
1019 | | - if (temp == std::int8_t{0}) { |
1020 | | - result = "0"; |
1021 | | - } else { |
1022 | | - while (temp != std::int8_t{0}) { |
1023 | | - auto r = temp % static_cast<std::int8_t>(8); |
1024 | | - auto digit = 0; |
1025 | | - if constexpr (std::endian::native == std::endian::little) { |
1026 | | - digit = r.data_[0]; |
1027 | | - } else { |
1028 | | - digit = r.data_[r.data_.size() - 1]; |
1029 | | - } |
1030 | | - result.push_back('0' + digit); |
1031 | | - temp /= std::int8_t{8}; |
1032 | | - } |
1033 | | - std::ranges::reverse(result); |
1034 | | - } |
1035 | | - } else if (base_flag == std::ios_base::dec) { |
1036 | | - auto temp = bigint<bits, is_signed>{data}; |
1037 | | - auto negative = false; |
1038 | | - if constexpr (is_signed) { |
1039 | | - if (temp < std::int8_t{0}) { |
1040 | | - negative = true; |
1041 | | - temp = -temp; |
1042 | | - } |
1043 | | - } |
1044 | | - if (temp == static_cast<std::int8_t>(0)) { |
1045 | | - result = "0"; |
1046 | | - } else { |
1047 | | - while (temp != static_cast<std::int8_t>(0)) { |
1048 | | - auto r = temp % static_cast<std::int8_t>(10); |
1049 | | - auto digit = 0; |
1050 | | - if constexpr (std::endian::native == std::endian::little) { |
1051 | | - digit = r.data_[0]; |
1052 | | - } else { |
1053 | | - digit = r.data_[r.data_.size() - 1]; |
1054 | | - } |
1055 | | - result.push_back('0' + digit); |
1056 | | - temp /= static_cast<std::int8_t>(10); |
1057 | | - } |
1058 | | - std::ranges::reverse(result); |
1059 | | - if (negative) { |
1060 | | - result.insert(result.begin(), '-'); |
1061 | | - } |
1062 | | - } |
| 1102 | + switch (base_flag) { |
| 1103 | + case std::ios_base::hex: |
| 1104 | + print_hex(os, data, use_uppercase); |
| 1105 | + break; |
| 1106 | + case std::ios_base::oct: |
| 1107 | + print_oct(os, data); |
| 1108 | + break; |
| 1109 | + case std::ios_base::dec: |
| 1110 | + default: |
| 1111 | + print_dec(os, data); |
| 1112 | + break; |
1063 | 1113 | } |
1064 | | - os << result; |
| 1114 | + |
1065 | 1115 | return os; |
1066 | 1116 | } |
1067 | 1117 |
|
|
0 commit comments