Line data Source code
1 : // Copyright (c) 2021-2023 Made to Order Software Corp. All Rights Reserved 2 : // 3 : // https://snapwebsites.org/project/snapdev 4 : // contact@m2osw.com 5 : // 6 : // This program is free software: you can redistribute it and/or modify 7 : // it under the terms of the GNU General Public License as published by 8 : // the Free Software Foundation, either version 3 of the License, or 9 : // (at your option) any later version. 10 : // 11 : // This program is distributed in the hope that it will be useful, 12 : // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 : // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 : // GNU General Public License for more details. 15 : // 16 : // You should have received a copy of the GNU General Public License 17 : // along with this program. If not, see <https://www.gnu.org/licenses/>. 18 : #pragma once 19 : 20 : /** \file 21 : * \brief Print large integers to any iostream. 22 : * 23 : * This function prints large integers (128 bits) to the specified iostream. 24 : */ 25 : 26 : // C++ 27 : // 28 : #include <ostream> 29 : #include <sstream> 30 : 31 : 32 : namespace snapdev 33 : { 34 : 35 : /** \brief Convert an __int128 to a string. 36 : * 37 : * This function converts an __int128 to a string. 38 : * 39 : * \param[in] x An __int128 number. 40 : * 41 : * \return A string representing that __int128 number. 42 : */ 43 : #pragma GCC diagnostic push 44 : #pragma GCC diagnostic ignored "-Wpedantic" 45 2043 : inline std::string to_string(__int128 x, __int128 base = 10, bool uppercase = false) 46 : { 47 2043 : char buf[129]; // binary requires 128 + '-' = 129 chars 48 : 49 2043 : char const adjust((uppercase ? 'A' : 'a') - ('9' + 1)); 50 : 51 2043 : int idx(sizeof(buf)); 52 2043 : unsigned __int128 y(x < 0 53 2043 : ? -static_cast<unsigned __int128>(x) 54 : : static_cast<unsigned __int128>(x)); 55 19066 : while(y >= static_cast<unsigned __int128>(base)) 56 : { 57 17023 : --idx; 58 17023 : buf[idx] = y % base + '0'; 59 17023 : if(buf[idx] > '9') 60 : { 61 0 : buf[idx] += adjust; 62 : } 63 17023 : y /= base; 64 : } 65 2043 : --idx; 66 2043 : buf[idx] = y + '0'; 67 2043 : if(buf[idx] > '9') 68 : { 69 0 : buf[idx] += adjust; 70 : } 71 2043 : if(x < 0) 72 : { 73 1021 : --idx; 74 1021 : buf[idx] = '-'; 75 : } 76 : 77 4086 : return std::string(buf + idx, sizeof(buf) - idx); 78 : } 79 : #pragma GCC diagnostic pop 80 : 81 : 82 : /** \brief Convert an unsigned __int128 to a string. 83 : * 84 : * This function converts an unsigned __int128 to a string. 85 : * 86 : * \param[in] x An unsigned __int128 number. 87 : * 88 : * \return A string representing that unsigned __int128 number. 89 : */ 90 : #pragma GCC diagnostic push 91 : #pragma GCC diagnostic ignored "-Wpedantic" 92 174 : inline std::string to_string(unsigned __int128 x, unsigned __int128 base = 10, bool uppercase = false) 93 : { 94 174 : char buf[128]; // binary requires 128 chars 95 : 96 174 : char const adjust((uppercase ? 'A' : 'a') - ('9' + 1)); 97 : 98 174 : int idx(sizeof(buf)); 99 3186 : while(x >= base) 100 : { 101 3012 : --idx; 102 3012 : buf[idx] = x % base + '0'; 103 3012 : if(buf[idx] > '9') 104 : { 105 1654 : buf[idx] += adjust; 106 : } 107 3012 : x /= base; 108 : } 109 174 : --idx; 110 174 : buf[idx] = x + '0'; 111 174 : if(buf[idx] > '9') 112 : { 113 59 : buf[idx] += adjust; 114 : } 115 : 116 348 : return std::string(buf + idx, sizeof(buf) - idx); 117 : } 118 : #pragma GCC diagnostic pop 119 : 120 : } //namespace snap 121 : 122 : 123 : // no namespace for operators, it's easier that way 124 : 125 : 126 : /** \brief Output an __int128 number. 127 : * 128 : * This function outputs the specified __int128 number to this output 129 : * stream. It respects the base and for hexadecimal, it also respects 130 : * the uppercase format. 131 : * 132 : * \note 133 : * The hexadecimal and octal formats do not understand negative numbers. 134 : * This function respects the C++ definition and prints out unsigned 135 : * numbers when one of the std::hex or std::oct format are set. If you 136 : * would prefer a negative number (i.e. -0x1 instead of 0xfff...fff) 137 : * then make sure to directly call the snapdev::to_string() function 138 : * instead. 139 : * 140 : * \warning 141 : * This implementation does not offer proper formatting. 142 : * It will first generate a string then output that string 143 : * which means the result is not what you'd expect if you 144 : * used formatting such as std::setfill() and std::setw(). 145 : * 146 : * \param[in] os The output stream. 147 : * \param[in] x The value to be output in \p os. 148 : * 149 : * \return A reference to \p os. 150 : */ 151 : #pragma GCC diagnostic push 152 : #pragma GCC diagnostic ignored "-Wpedantic" 153 2212 : inline std::ostream & operator << (std::ostream & os, __int128 x) 154 : { 155 2212 : std::ios_base::fmtflags const fmt(os.flags() & std::ios_base::basefield); 156 : 157 2212 : if(fmt == std::ios_base::oct) 158 : { 159 63 : if(x != 0 160 63 : && (os.flags() & std::ios_base::showbase) != 0) 161 : { 162 40 : os << '0'; 163 : } 164 63 : return os << snapdev::to_string(static_cast<unsigned __int128>(x), 8); 165 : } 166 : 167 2149 : if(fmt == std::ios_base::hex) 168 : { 169 106 : bool const uppercase(os.flags() & std::ios_base::uppercase); 170 106 : if(x != 0 171 106 : && (os.flags() & std::ios_base::showbase) != 0) 172 : { 173 40 : if(uppercase) 174 : { 175 20 : os << "0X"; 176 : } 177 : else 178 : { 179 20 : os << "0x"; 180 : } 181 : } 182 106 : return os << snapdev::to_string(static_cast<unsigned __int128>(x), 16, uppercase); 183 : } 184 : 185 : // the '-' is added by the to_string(), but not the '+' 186 : // 187 2043 : if(x >= 0 188 2043 : && (os.flags() & std::ios_base::showpos) != 0) 189 : { 190 11 : os << '+'; 191 : } 192 : 193 2043 : return os << snapdev::to_string(x); 194 : } 195 : #pragma GCC diagnostic pop 196 : 197 : 198 : /** \brief Output an unsigned __int128 number. 199 : * 200 : * This function outputs the specified __int128 number to this output 201 : * stream. It respects the base and for hexadecimal, it also respects 202 : * the uppercase format. 203 : * 204 : * \warning 205 : * This implementation does not offer proper formatting. 206 : * It will first generate a string then output that string 207 : * which means the result is not what you'd expect if you 208 : * used formatting such as std::setfill() and std::setw(). 209 : * 210 : * \param[in] os The output stream. 211 : * \param[in] x The value to be output in \p os. 212 : * 213 : * \return A reference to \p os. 214 : */ 215 : #pragma GCC diagnostic push 216 : #pragma GCC diagnostic ignored "-Wpedantic" 217 5 : inline std::ostream & operator << (std::ostream & os, unsigned __int128 x) 218 : { 219 5 : std::ios_base::fmtflags const fmt(os.flags() & std::ios_base::basefield); 220 : 221 5 : if(fmt == std::ios_base::oct) 222 : { 223 0 : if(x != 0 224 0 : && (os.flags() & std::ios_base::showbase) != 0) 225 : { 226 0 : os << '0'; 227 : } 228 0 : return os << snapdev::to_string(x, 8); 229 : } 230 : 231 5 : if(fmt == std::ios_base::hex) 232 : { 233 4 : bool const uppercase((os.flags() & std::ios_base::uppercase) != 0); 234 4 : if(x != 0 235 4 : && (os.flags() & std::ios_base::showbase) != 0) 236 : { 237 2 : if(uppercase) 238 : { 239 1 : os << "0X"; 240 : } 241 : else 242 : { 243 1 : os << "0x"; 244 : } 245 : } 246 4 : return os << snapdev::to_string(x, 16, uppercase); 247 : } 248 : 249 : // unsigned do not show the '+' sign at all 250 : // 251 1 : return os << snapdev::to_string(x, 10); 252 : } 253 : #pragma GCC diagnostic pop 254 : 255 : 256 : // vim: ts=4 sw=4 et