Line data Source code
1 : // Copyright (c) 2021-2022 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 2 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 along
17 : // with this program; if not, write to the Free Software Foundation, Inc.,
18 : // 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19 : #pragma once
20 :
21 : /** \file
22 : * \brief Print large integers to any iostream.
23 : *
24 : * This function prints large integers (128 bits) to the specified iostream.
25 : */
26 :
27 : // C++
28 : //
29 : #include <ostream>
30 : #include <sstream>
31 :
32 :
33 : namespace snapdev
34 : {
35 :
36 : /** \brief Convert an __int128 to a string.
37 : *
38 : * This function converts an __int128 to a string.
39 : *
40 : * \param[in] x An __int128 number.
41 : *
42 : * \return A string representing that __int128 number.
43 : */
44 : #pragma GCC diagnostic push
45 : #pragma GCC diagnostic ignored "-Wpedantic"
46 2022 : inline std::string to_string(__int128 x, __int128 base = 10, bool uppercase = false)
47 : {
48 2022 : char buf[129]; // binary requires 128 + '-' = 129 chars
49 :
50 2022 : char const adjust((uppercase ? 'A' : 'a') - ('9' + 1));
51 :
52 2022 : int idx(sizeof(buf));
53 2022 : unsigned __int128 y(x < 0
54 2022 : ? -static_cast<unsigned __int128>(x)
55 : : static_cast<unsigned __int128>(x));
56 36058 : while(y >= static_cast<unsigned __int128>(base))
57 : {
58 17018 : --idx;
59 17018 : buf[idx] = y % base + '0';
60 17018 : if(buf[idx] > '9')
61 : {
62 0 : buf[idx] += adjust;
63 : }
64 17018 : y /= base;
65 : }
66 2022 : --idx;
67 2022 : buf[idx] = y + '0';
68 2022 : if(buf[idx] > '9')
69 : {
70 0 : buf[idx] += adjust;
71 : }
72 2022 : if(x < 0)
73 : {
74 1011 : --idx;
75 1011 : buf[idx] = '-';
76 : }
77 :
78 2022 : return std::string(buf + idx, sizeof(buf) - idx);
79 : }
80 : #pragma GCC diagnostic pop
81 :
82 :
83 : /** \brief Convert an unsigned __int128 to a string.
84 : *
85 : * This function converts an unsigned __int128 to a string.
86 : *
87 : * \param[in] x An unsigned __int128 number.
88 : *
89 : * \return A string representing that unsigned __int128 number.
90 : */
91 : #pragma GCC diagnostic push
92 : #pragma GCC diagnostic ignored "-Wpedantic"
93 132 : inline std::string to_string(unsigned __int128 x, unsigned __int128 base = 10, bool uppercase = false)
94 : {
95 132 : char buf[128]; // binary requires 128 chars
96 :
97 132 : char const adjust((uppercase ? 'A' : 'a') - ('9' + 1));
98 :
99 132 : int idx(sizeof(buf));
100 4690 : while(x >= base)
101 : {
102 2279 : --idx;
103 2279 : buf[idx] = x % base + '0';
104 2279 : if(buf[idx] > '9')
105 : {
106 1348 : buf[idx] += adjust;
107 : }
108 2279 : x /= base;
109 : }
110 132 : --idx;
111 132 : buf[idx] = x + '0';
112 132 : if(buf[idx] > '9')
113 : {
114 48 : buf[idx] += adjust;
115 : }
116 :
117 132 : return std::string(buf + idx, sizeof(buf) - idx);
118 : }
119 : #pragma GCC diagnostic pop
120 :
121 : } //namespace snap
122 :
123 :
124 : // no namespace for operators, it's easier that way
125 :
126 :
127 : /** \brief Output an __int128 number.
128 : *
129 : * This function outputs the specified __int128 number to this output
130 : * stream. It respects the base and for hexadecimal, it also respects
131 : * the uppercase format.
132 : *
133 : * \note
134 : * The hexadecimal and octal formats do not understand negative numbers.
135 : * This function respects the C++ definition and prints out unsigned
136 : * numbers when one of the std::hex or std::oct format are set. If you
137 : * would prefer a negative number (i.e. -0x1 instead of 0xfff...fff)
138 : * then make sure to directly call the snapdev::to_string() function
139 : * instead.
140 : *
141 : * \warning
142 : * This implementation does not offer proper formatting.
143 : * It will first generate a string then output that string
144 : * which means the result is not what you'd expect if you
145 : * used formatting such as std::setfill() and std::setw().
146 : *
147 : * \param[in] os The output stream.
148 : * \param[in] x The value to be output in \p os.
149 : *
150 : * \return A reference to \p os.
151 : */
152 : #pragma GCC diagnostic push
153 : #pragma GCC diagnostic ignored "-Wpedantic"
154 2149 : inline std::ostream & operator << (std::ostream & os, __int128 x)
155 : {
156 2149 : std::ios_base::fmtflags const fmt(os.flags() & std::ios_base::basefield);
157 2149 : if(fmt == std::ios_base::oct)
158 : {
159 42 : if(os.flags() & std::ios_base::showbase)
160 : {
161 21 : os << '0';
162 : }
163 42 : return os << snapdev::to_string(static_cast<unsigned __int128>(x), 8);
164 : }
165 2107 : else if(fmt == std::ios_base::hex)
166 : {
167 85 : if(os.flags() & std::ios_base::showbase)
168 : {
169 42 : if(os.flags() & std::ios_base::uppercase)
170 : {
171 21 : os << "0X";
172 : }
173 : else
174 : {
175 21 : os << "0x";
176 : }
177 : }
178 85 : return os << snapdev::to_string(static_cast<unsigned __int128>(x), 16, (os.flags() & std::ios_base::uppercase) != 0);
179 : }
180 2022 : return os << snapdev::to_string(x);
181 : }
182 : #pragma GCC diagnostic pop
183 :
184 :
185 : /** \brief Output an unsigned __int128 number.
186 : *
187 : * This function outputs the specified __int128 number to this output
188 : * stream. It respects the base and for hexadecimal, it also respects
189 : * the uppercase format.
190 : *
191 : * \warning
192 : * This implementation does not offer proper formatting.
193 : * It will first generate a string then output that string
194 : * which means the result is not what you'd expect if you
195 : * used formatting such as std::setfill() and std::setw().
196 : *
197 : * \param[in] os The output stream.
198 : * \param[in] x The value to be output in \p os.
199 : *
200 : * \return A reference to \p os.
201 : */
202 : #pragma GCC diagnostic push
203 : #pragma GCC diagnostic ignored "-Wpedantic"
204 5 : inline std::ostream & operator << (std::ostream & os, unsigned __int128 x)
205 : {
206 5 : std::ios_base::fmtflags const fmt(os.flags() & std::ios_base::basefield);
207 5 : int base(10);
208 5 : bool uppercase(false);
209 5 : if(fmt == std::ios_base::oct)
210 : {
211 0 : base = 8;
212 0 : if(os.flags() & std::ios_base::showbase)
213 : {
214 0 : os << '0';
215 : }
216 : }
217 5 : else if(fmt == std::ios_base::hex)
218 : {
219 4 : uppercase = (os.flags() & std::ios_base::uppercase) != 0;
220 4 : base = 16;
221 4 : if(os.flags() & std::ios_base::showbase)
222 : {
223 2 : if(uppercase)
224 : {
225 1 : os << "0X";
226 : }
227 : else
228 : {
229 1 : os << "0x";
230 : }
231 : }
232 : }
233 5 : return os << snapdev::to_string(x, base, uppercase);
234 : }
235 : #pragma GCC diagnostic pop
236 :
237 :
238 : // vim: ts=4 sw=4 et
|