Line data Source code
1 : // Copyright 2020-2023 Daniel Lemire
2 : // Copyright 2023 Matt Borland
3 : // Distributed under the Boost Software License, Version 1.0.
4 : // https://www.boost.org/LICENSE_1_0.txt
5 : //
6 : // If the architecture (e.g. Apple ARM) does not have __int128 we need to emulate it
7 :
8 : #ifndef BOOST_JSON_DETAIL_DRAGONBOX_EMULATED128_HPP
9 : #define BOOST_JSON_DETAIL_DRAGONBOX_EMULATED128_HPP
10 :
11 : #include <boost/json/detail/config.hpp>
12 : #include <boost/json/detail/charconv/detail/config.hpp>
13 : #include <boost/endian/conversion.hpp>
14 : #include <boost/core/bit.hpp>
15 : #include <limits>
16 : #include <cstdint>
17 : #include <cassert>
18 : #include <cmath>
19 :
20 : namespace boost {
21 : namespace json {
22 : namespace detail {
23 :
24 : // Compilers might support built-in 128-bit integer types. However, it seems that
25 : // emulating them with a pair of 64-bit integers actually produces a better code,
26 : // so we avoid using those built-ins. That said, they are still useful for
27 : // implementing 64-bit x 64-bit -> 128-bit multiplication.
28 :
29 : // Memcpy-able temp class for uint128
30 : template <boost::endian::order Order = boost::endian::order::little>
31 : struct trivial_uint128_impl
32 : {
33 : std::uint64_t low;
34 : std::uint64_t high;
35 : };
36 :
37 : template <>
38 : struct trivial_uint128_impl<boost::endian::order::big>
39 : {
40 : std::uint64_t high;
41 : std::uint64_t low;
42 : };
43 :
44 : using trivial_uint128 = trivial_uint128_impl<boost::endian::order::native>;
45 :
46 : // Macro replacement lists can not be enclosed in parentheses
47 : struct uint128
48 : {
49 : std::uint64_t high;
50 : std::uint64_t low;
51 :
52 : // Constructors
53 : constexpr uint128() noexcept : high {}, low {} {}
54 :
55 : constexpr uint128(const uint128& v) noexcept = default;
56 :
57 : constexpr uint128(uint128&& v) noexcept = default;
58 :
59 749 : constexpr uint128(std::uint64_t high_, std::uint64_t low_) noexcept : high {high_}, low {low_} {}
60 :
61 : constexpr uint128(const trivial_uint128& v) noexcept : high {v.high}, low {v.low} {} // NOLINT
62 :
63 : constexpr uint128(trivial_uint128&& v) noexcept : high {v.high}, low {v.low} {} // NOLINT
64 :
65 : #define SIGNED_CONSTRUCTOR(expr) constexpr uint128(expr v) noexcept : high {v < 0 ? UINT64_MAX : UINT64_C(0)}, low {static_cast<std::uint64_t>(v)} {} // NOLINT
66 : #define UNSIGNED_CONSTRUCTOR(expr) constexpr uint128(expr v) noexcept : high {}, low {static_cast<std::uint64_t>(v)} {} // NOLINT
67 :
68 : SIGNED_CONSTRUCTOR(char) // NOLINT
69 : SIGNED_CONSTRUCTOR(signed char) // NOLINT
70 : SIGNED_CONSTRUCTOR(short) // NOLINT
71 : SIGNED_CONSTRUCTOR(int) // NOLINT
72 : SIGNED_CONSTRUCTOR(long) // NOLINT
73 : SIGNED_CONSTRUCTOR(long long) // NOLINT
74 :
75 : UNSIGNED_CONSTRUCTOR(unsigned char) // NOLINT
76 : UNSIGNED_CONSTRUCTOR(unsigned short) // NOLINT
77 : UNSIGNED_CONSTRUCTOR(unsigned) // NOLINT
78 : UNSIGNED_CONSTRUCTOR(unsigned long) // NOLINT
79 : UNSIGNED_CONSTRUCTOR(unsigned long long) // NOLINT
80 :
81 : #ifdef BOOST_HAS_INT128
82 : constexpr uint128(boost::int128_type v) noexcept : // NOLINT : Allow implicit conversions
83 : high {static_cast<std::uint64_t>(v >> 64)},
84 : low {static_cast<std::uint64_t>(static_cast<boost::uint128_type>(v) & ~UINT64_C(0))} {}
85 :
86 : constexpr uint128(boost::uint128_type v) noexcept : // NOLINT : Allow implicit conversions
87 : high {static_cast<std::uint64_t>(v >> 64)},
88 : low {static_cast<std::uint64_t>(v & ~UINT64_C(0))} {}
89 : #endif
90 :
91 : #undef SIGNED_CONSTRUCTOR
92 : #undef UNSIGNED_CONSTRUCTOR
93 :
94 : // Assignment Operators
95 : #define SIGNED_ASSIGNMENT_OPERATOR(expr) BOOST_JSON_CXX14_CONSTEXPR uint128 &operator=(const expr& v) noexcept { high = v < 0 ? UINT64_MAX : UINT64_C(0); low = static_cast<std::uint64_t>(v); return *this; } // NOLINT
96 : #define UNSIGNED_ASSIGNMENT_OPERATOR(expr) BOOST_JSON_CXX14_CONSTEXPR uint128 &operator=(const expr& v) noexcept { high = 0U; low = static_cast<std::uint64_t>(v); return *this; } // NOLINT
97 :
98 : SIGNED_ASSIGNMENT_OPERATOR(char) // NOLINT
99 : SIGNED_ASSIGNMENT_OPERATOR(signed char) // NOLINT
100 : SIGNED_ASSIGNMENT_OPERATOR(short) // NOLINT
101 : SIGNED_ASSIGNMENT_OPERATOR(int) // NOLINT
102 : SIGNED_ASSIGNMENT_OPERATOR(long) // NOLINT
103 : SIGNED_ASSIGNMENT_OPERATOR(long long) // NOLINT
104 :
105 : UNSIGNED_ASSIGNMENT_OPERATOR(unsigned char) // NOLINT
106 : UNSIGNED_ASSIGNMENT_OPERATOR(unsigned short) // NOLINT
107 : UNSIGNED_ASSIGNMENT_OPERATOR(unsigned) // NOLINT
108 : UNSIGNED_ASSIGNMENT_OPERATOR(unsigned long) // NOLINT
109 : UNSIGNED_ASSIGNMENT_OPERATOR(unsigned long long) // NOLINT
110 :
111 : #ifdef BOOST_HAS_INT128
112 : BOOST_JSON_CXX14_CONSTEXPR uint128 &operator=(const boost::int128_type& v) noexcept { *this = uint128(v); return *this; }
113 : BOOST_JSON_CXX14_CONSTEXPR uint128 &operator=(const boost::uint128_type& v) noexcept { *this = uint128(v); return *this; }
114 : #endif
115 :
116 : BOOST_JSON_CXX14_CONSTEXPR uint128 &operator=(const trivial_uint128& v) noexcept { this->low = v.low; this->high = v.high; return *this; }
117 :
118 : BOOST_JSON_CXX14_CONSTEXPR uint128 &operator=(const uint128&) noexcept;
119 :
120 : #undef SIGNED_ASSIGNMENT_OPERATOR
121 : #undef UNSIGNED_ASSIGNMENT_OPERATOR
122 :
123 : // Conversion Operators
124 : #define INTEGER_CONVERSION_OPERATOR(expr) explicit constexpr operator expr() const noexcept { return static_cast<expr>(low); } // NOLINT
125 : #define FLOAT_CONVERSION_OPERATOR(expr) explicit operator expr() const noexcept { return std::ldexp(static_cast<expr>(high), 64) + static_cast<expr>(low); } // NOLINT
126 :
127 : INTEGER_CONVERSION_OPERATOR(char) // NOLINT
128 : INTEGER_CONVERSION_OPERATOR(signed char) // NOLINT
129 : INTEGER_CONVERSION_OPERATOR(short) // NOLINT
130 : INTEGER_CONVERSION_OPERATOR(int) // NOLINT
131 : INTEGER_CONVERSION_OPERATOR(long) // NOLINT
132 : INTEGER_CONVERSION_OPERATOR(long long) // NOLINT
133 : INTEGER_CONVERSION_OPERATOR(unsigned char) // NOLINT
134 : INTEGER_CONVERSION_OPERATOR(unsigned short) // NOLINT
135 : INTEGER_CONVERSION_OPERATOR(unsigned) // NOLINT
136 : INTEGER_CONVERSION_OPERATOR(unsigned long) // NOLINT
137 : INTEGER_CONVERSION_OPERATOR(unsigned long long) // NOLINT
138 :
139 : explicit constexpr operator bool() const noexcept { return high || low; }
140 :
141 : #ifdef BOOST_HAS_INT128
142 : explicit constexpr operator boost::int128_type() const noexcept { return (static_cast<boost::int128_type>(high) << 64) + low; }
143 : explicit constexpr operator boost::uint128_type() const noexcept { return (static_cast<boost::uint128_type>(high) << 64) + low; }
144 : #endif
145 :
146 : FLOAT_CONVERSION_OPERATOR(float) // NOLINT
147 : FLOAT_CONVERSION_OPERATOR(double) // NOLINT
148 : FLOAT_CONVERSION_OPERATOR(long double) // NOLINT
149 :
150 : #undef INTEGER_CONVERSION_OPERATOR
151 : #undef FLOAT_CONVERSION_OPERATOR
152 :
153 : // Unary Operators
154 : constexpr friend uint128 operator-(uint128 val) noexcept;
155 : constexpr friend uint128 operator+(uint128 val) noexcept;
156 :
157 : // Comparison Operators
158 :
159 : // Equality
160 : #define INTEGER_OPERATOR_EQUAL(expr) constexpr friend bool operator==(uint128 lhs, expr rhs) noexcept { return lhs.high == 0 && rhs >= 0 && lhs.low == static_cast<std::uint64_t>(rhs); } // NOLINT
161 : #define UNSIGNED_INTEGER_OPERATOR_EQUAL(expr) constexpr friend bool operator==(uint128 lhs, expr rhs) noexcept { return lhs.high == 0 && lhs.low == static_cast<std::uint64_t>(rhs); } // NOLINT
162 :
163 : INTEGER_OPERATOR_EQUAL(char) // NOLINT
164 : INTEGER_OPERATOR_EQUAL(signed char) // NOLINT
165 : INTEGER_OPERATOR_EQUAL(short) // NOLINT
166 : INTEGER_OPERATOR_EQUAL(int) // NOLINT
167 : INTEGER_OPERATOR_EQUAL(long) // NOLINT
168 : INTEGER_OPERATOR_EQUAL(long long) // NOLINT
169 : UNSIGNED_INTEGER_OPERATOR_EQUAL(unsigned char) // NOLINT
170 : UNSIGNED_INTEGER_OPERATOR_EQUAL(unsigned short) // NOLINT
171 : UNSIGNED_INTEGER_OPERATOR_EQUAL(unsigned) // NOLINT
172 : UNSIGNED_INTEGER_OPERATOR_EQUAL(unsigned long) // NOLINT
173 : UNSIGNED_INTEGER_OPERATOR_EQUAL(unsigned long long) // NOLINT
174 :
175 : #ifdef BOOST_HAS_INT128
176 : constexpr friend bool operator==(uint128 lhs, boost::int128_type rhs) noexcept { return lhs == uint128(rhs); }
177 : constexpr friend bool operator==(uint128 lhs, boost::uint128_type rhs) noexcept { return lhs == uint128(rhs); }
178 : #endif
179 :
180 : constexpr friend bool operator==(uint128 lhs, uint128 rhs) noexcept;
181 :
182 : #undef INTEGER_OPERATOR_EQUAL
183 : #undef UNSIGNED_INTEGER_OPERATOR_EQUAL
184 :
185 : // Inequality
186 : #define INTEGER_OPERATOR_NOTEQUAL(expr) constexpr friend bool operator!=(uint128 lhs, expr rhs) noexcept { return !(lhs == rhs); } // NOLINT
187 :
188 : INTEGER_OPERATOR_NOTEQUAL(char) // NOLINT
189 : INTEGER_OPERATOR_NOTEQUAL(signed char) // NOLINT
190 : INTEGER_OPERATOR_NOTEQUAL(short) // NOLINT
191 : INTEGER_OPERATOR_NOTEQUAL(int) // NOLINT
192 : INTEGER_OPERATOR_NOTEQUAL(long) // NOLINT
193 : INTEGER_OPERATOR_NOTEQUAL(long long) // NOLINT
194 : INTEGER_OPERATOR_NOTEQUAL(unsigned char) // NOLINT
195 : INTEGER_OPERATOR_NOTEQUAL(unsigned short) // NOLINT
196 : INTEGER_OPERATOR_NOTEQUAL(unsigned) // NOLINT
197 : INTEGER_OPERATOR_NOTEQUAL(unsigned long) // NOLINT
198 : INTEGER_OPERATOR_NOTEQUAL(unsigned long long) // NOLINT
199 :
200 : #ifdef BOOST_HAS_INT128
201 : constexpr friend bool operator!=(uint128 lhs, boost::int128_type rhs) noexcept { return !(lhs == rhs); }
202 : constexpr friend bool operator!=(uint128 lhs, boost::uint128_type rhs) noexcept { return !(lhs == rhs); }
203 : #endif
204 :
205 : constexpr friend bool operator!=(uint128 lhs, uint128 rhs) noexcept;
206 :
207 : #undef INTEGER_OPERATOR_NOTEQUAL
208 :
209 : // Less than
210 : #define INTEGER_OPERATOR_LESS_THAN(expr) constexpr friend bool operator<(uint128 lhs, expr rhs) noexcept { return lhs.high == 0U && rhs > 0 && lhs.low < static_cast<std::uint64_t>(rhs); } // NOLINT
211 : #define UNSIGNED_INTEGER_OPERATOR_LESS_THAN(expr) constexpr friend bool operator<(uint128 lhs, expr rhs) noexcept { return lhs.high == 0U && lhs.low < static_cast<std::uint64_t>(rhs); } // NOLINT
212 :
213 : INTEGER_OPERATOR_LESS_THAN(char) // NOLINT
214 : INTEGER_OPERATOR_LESS_THAN(signed char) // NOLINT
215 : INTEGER_OPERATOR_LESS_THAN(short) // NOLINT
216 : INTEGER_OPERATOR_LESS_THAN(int) // NOLINT
217 : INTEGER_OPERATOR_LESS_THAN(long) // NOLINT
218 : INTEGER_OPERATOR_LESS_THAN(long long) // NOLINT
219 : UNSIGNED_INTEGER_OPERATOR_LESS_THAN(unsigned char) // NOLINT
220 : UNSIGNED_INTEGER_OPERATOR_LESS_THAN(unsigned short) // NOLINT
221 : UNSIGNED_INTEGER_OPERATOR_LESS_THAN(unsigned) // NOLINT
222 : UNSIGNED_INTEGER_OPERATOR_LESS_THAN(unsigned long) // NOLINT
223 : UNSIGNED_INTEGER_OPERATOR_LESS_THAN(unsigned long long) // NOLINT
224 :
225 : #ifdef BOOST_HAS_INT128
226 : BOOST_JSON_CXX14_CONSTEXPR friend bool operator<(uint128 lhs, boost::int128_type rhs) noexcept { return lhs < uint128(rhs); }
227 : BOOST_JSON_CXX14_CONSTEXPR friend bool operator<(uint128 lhs, boost::uint128_type rhs) noexcept { return lhs < uint128(rhs); }
228 : #endif
229 :
230 : BOOST_JSON_CXX14_CONSTEXPR friend bool operator<(uint128 lhs, uint128 rhs) noexcept;
231 :
232 : #undef INTEGER_OPERATOR_LESS_THAN
233 : #undef UNSIGNED_INTEGER_OPERATOR_LESS_THAN
234 :
235 : // Less than or equal to
236 : #define INTEGER_OPERATOR_LESS_THAN_OR_EQUAL_TO(expr) constexpr friend bool operator<=(uint128 lhs, expr rhs) noexcept { return lhs.high == 0U && rhs >= 0 && lhs.low <= static_cast<std::uint64_t>(rhs); } // NOLINT
237 : #define UNSIGNED_INTEGER_OPERATOR_LESS_THAN_OR_EQUAL_TO(expr) constexpr friend bool operator<=(uint128 lhs, expr rhs) noexcept { return lhs.high == 0U && lhs.low <= static_cast<std::uint64_t>(rhs); } // NOLINT
238 :
239 : INTEGER_OPERATOR_LESS_THAN_OR_EQUAL_TO(char) // NOLINT
240 : INTEGER_OPERATOR_LESS_THAN_OR_EQUAL_TO(signed char) // NOLINT
241 : INTEGER_OPERATOR_LESS_THAN_OR_EQUAL_TO(short) // NOLINT
242 : INTEGER_OPERATOR_LESS_THAN_OR_EQUAL_TO(int) // NOLINT
243 : INTEGER_OPERATOR_LESS_THAN_OR_EQUAL_TO(long) // NOLINT
244 : INTEGER_OPERATOR_LESS_THAN_OR_EQUAL_TO(long long) // NOLINT
245 : UNSIGNED_INTEGER_OPERATOR_LESS_THAN_OR_EQUAL_TO(unsigned char) // NOLINT
246 : UNSIGNED_INTEGER_OPERATOR_LESS_THAN_OR_EQUAL_TO(unsigned short) // NOLINT
247 : UNSIGNED_INTEGER_OPERATOR_LESS_THAN_OR_EQUAL_TO(unsigned) // NOLINT
248 : UNSIGNED_INTEGER_OPERATOR_LESS_THAN_OR_EQUAL_TO(unsigned long) // NOLINT
249 : UNSIGNED_INTEGER_OPERATOR_LESS_THAN_OR_EQUAL_TO(unsigned long long) // NOLINT
250 :
251 : #ifdef BOOST_HAS_INT128
252 : BOOST_JSON_CXX14_CONSTEXPR friend bool operator<=(uint128 lhs, boost::int128_type rhs) noexcept { return lhs <= uint128(rhs); }
253 : BOOST_JSON_CXX14_CONSTEXPR friend bool operator<=(uint128 lhs, boost::uint128_type rhs) noexcept { return lhs <= uint128(rhs); }
254 : #endif
255 :
256 : BOOST_JSON_CXX14_CONSTEXPR friend bool operator<=(uint128 lhs, uint128 rhs) noexcept;
257 :
258 : #undef INTEGER_OPERATOR_LESS_THAN_OR_EQUAL_TO
259 : #undef UNSIGNED_INTEGER_OPERATOR_LESS_THAN_OR_EQUAL_TO
260 :
261 : // Greater than
262 : #define INTEGER_OPERATOR_GREATER_THAN(expr) constexpr friend bool operator>(uint128 lhs, expr rhs) noexcept { return lhs.high > 0U || rhs < 0 || lhs.low > static_cast<std::uint64_t>(rhs); } // NOLINT
263 : #define UNSIGNED_INTEGER_OPERATOR_GREATER_THAN(expr) constexpr friend bool operator>(uint128 lhs, expr rhs) noexcept { return lhs.high > 0U || lhs.low > static_cast<std::uint64_t>(rhs); } // NOLINT
264 :
265 : INTEGER_OPERATOR_GREATER_THAN(char) // NOLINT
266 : INTEGER_OPERATOR_GREATER_THAN(signed char) // NOLINT
267 : INTEGER_OPERATOR_GREATER_THAN(short) // NOLINT
268 : INTEGER_OPERATOR_GREATER_THAN(int) // NOLINT
269 : INTEGER_OPERATOR_GREATER_THAN(long) // NOLINT
270 : INTEGER_OPERATOR_GREATER_THAN(long long) // NOLINT
271 : UNSIGNED_INTEGER_OPERATOR_GREATER_THAN(unsigned char) // NOLINT
272 : UNSIGNED_INTEGER_OPERATOR_GREATER_THAN(unsigned short) // NOLINT
273 : UNSIGNED_INTEGER_OPERATOR_GREATER_THAN(unsigned) // NOLINT
274 : UNSIGNED_INTEGER_OPERATOR_GREATER_THAN(unsigned long) // NOLINT
275 : UNSIGNED_INTEGER_OPERATOR_GREATER_THAN(unsigned long long) // NOLINT
276 :
277 : #ifdef BOOST_HAS_INT128
278 : BOOST_JSON_CXX14_CONSTEXPR friend bool operator>(uint128 lhs, boost::int128_type rhs) noexcept { return lhs > uint128(rhs); }
279 : BOOST_JSON_CXX14_CONSTEXPR friend bool operator>(uint128 lhs, boost::uint128_type rhs) noexcept { return lhs > uint128(rhs); }
280 : #endif
281 :
282 : BOOST_JSON_CXX14_CONSTEXPR friend bool operator>(uint128 lhs, uint128 rhs) noexcept;
283 :
284 : #undef INTEGER_OPERATOR_GREATER_THAN
285 : #undef UNSIGNED_INTEGER_OPERATOR_GREATER_THAN
286 :
287 : // Greater than or equal to
288 : #define INTEGER_OPERATOR_GREATER_THAN_OR_EQUAL_TO(expr) constexpr friend bool operator>=(uint128 lhs, expr rhs) noexcept { return lhs.high > 0U || rhs < 0 || lhs.low >= static_cast<std::uint64_t>(rhs); } // NOLINT
289 : #define UNSIGNED_INTEGER_OPERATOR_GREATER_THAN_OR_EQUAL_TO(expr) constexpr friend bool operator>=(uint128 lhs, expr rhs) noexcept { return lhs.high > 0U || lhs.low >= static_cast<std::uint64_t>(rhs); } // NOLINT
290 :
291 : INTEGER_OPERATOR_GREATER_THAN_OR_EQUAL_TO(char) // NOLINT
292 : INTEGER_OPERATOR_GREATER_THAN_OR_EQUAL_TO(signed char) // NOLINT
293 : INTEGER_OPERATOR_GREATER_THAN_OR_EQUAL_TO(short) // NOLINT
294 : INTEGER_OPERATOR_GREATER_THAN_OR_EQUAL_TO(int) // NOLINT
295 : INTEGER_OPERATOR_GREATER_THAN_OR_EQUAL_TO(long) // NOLINT
296 : INTEGER_OPERATOR_GREATER_THAN_OR_EQUAL_TO(long long) // NOLINT
297 : UNSIGNED_INTEGER_OPERATOR_GREATER_THAN_OR_EQUAL_TO(unsigned char) // NOLINT
298 : UNSIGNED_INTEGER_OPERATOR_GREATER_THAN_OR_EQUAL_TO(unsigned short) // NOLINT
299 : UNSIGNED_INTEGER_OPERATOR_GREATER_THAN_OR_EQUAL_TO(unsigned) // NOLINT
300 : UNSIGNED_INTEGER_OPERATOR_GREATER_THAN_OR_EQUAL_TO(unsigned long) // NOLINT
301 : UNSIGNED_INTEGER_OPERATOR_GREATER_THAN_OR_EQUAL_TO(unsigned long long) // NOLINT
302 :
303 : #ifdef BOOST_HAS_INT128
304 : BOOST_JSON_CXX14_CONSTEXPR friend bool operator>=(uint128 lhs, boost::int128_type rhs) noexcept { return lhs >= uint128(rhs); }
305 : BOOST_JSON_CXX14_CONSTEXPR friend bool operator>=(uint128 lhs, boost::uint128_type rhs) noexcept { return lhs >= uint128(rhs); }
306 : #endif
307 :
308 : BOOST_JSON_CXX14_CONSTEXPR friend bool operator>=(uint128 lhs, uint128 rhs) noexcept;
309 :
310 : #undef INTEGER_OPERATOR_GREATER_THAN_OR_EQUAL_TO
311 : #undef UNSIGNED_INTEGER_OPERATOR_GREATER_THAN_OR_EQUAL_TO
312 :
313 : // Binary Operators
314 :
315 : // Not
316 : constexpr friend uint128 operator~(uint128 v) noexcept;
317 :
318 : // Or
319 : #define INTEGER_BINARY_OPERATOR_OR(expr) constexpr friend uint128 operator|(uint128 lhs, expr rhs) noexcept { return {lhs.high, lhs.low | static_cast<std::uint64_t>(rhs)}; } // NOLINT
320 :
321 : INTEGER_BINARY_OPERATOR_OR(char) // NOLINT
322 : INTEGER_BINARY_OPERATOR_OR(signed char) // NOLINT
323 : INTEGER_BINARY_OPERATOR_OR(short) // NOLINT
324 : INTEGER_BINARY_OPERATOR_OR(int) // NOLINT
325 : INTEGER_BINARY_OPERATOR_OR(long) // NOLINT
326 : INTEGER_BINARY_OPERATOR_OR(long long) // NOLINT
327 : INTEGER_BINARY_OPERATOR_OR(unsigned char) // NOLINT
328 : INTEGER_BINARY_OPERATOR_OR(unsigned short) // NOLINT
329 : INTEGER_BINARY_OPERATOR_OR(unsigned) // NOLINT
330 : INTEGER_BINARY_OPERATOR_OR(unsigned long) // NOLINT
331 : INTEGER_BINARY_OPERATOR_OR(unsigned long long) // NOLINT
332 :
333 : #ifdef BOOST_HAS_INT128
334 : constexpr friend uint128 operator|(uint128 lhs, boost::int128_type rhs) noexcept { return lhs | uint128(rhs); }
335 : constexpr friend uint128 operator|(uint128 lhs, boost::uint128_type rhs) noexcept { return lhs | uint128(rhs); }
336 : #endif
337 :
338 : constexpr friend uint128 operator|(uint128 lhs, uint128 rhs) noexcept;
339 :
340 : BOOST_JSON_CXX14_CONSTEXPR uint128 &operator|=(uint128 v) noexcept;
341 :
342 : #undef INTEGER_BINARY_OPERATOR_OR
343 :
344 : // And
345 : #define INTEGER_BINARY_OPERATOR_AND(expr) constexpr friend uint128 operator&(uint128 lhs, expr rhs) noexcept { return {lhs.high, lhs.low & static_cast<std::uint64_t>(rhs)}; } // NOLINT
346 :
347 : INTEGER_BINARY_OPERATOR_AND(char) // NOLINT
348 : INTEGER_BINARY_OPERATOR_AND(signed char) // NOLINT
349 : INTEGER_BINARY_OPERATOR_AND(short) // NOLINT
350 : INTEGER_BINARY_OPERATOR_AND(int) // NOLINT
351 : INTEGER_BINARY_OPERATOR_AND(long) // NOLINT
352 : INTEGER_BINARY_OPERATOR_AND(long long) // NOLINT
353 : INTEGER_BINARY_OPERATOR_AND(unsigned char) // NOLINT
354 : INTEGER_BINARY_OPERATOR_AND(unsigned short) // NOLINT
355 : INTEGER_BINARY_OPERATOR_AND(unsigned) // NOLINT
356 : INTEGER_BINARY_OPERATOR_AND(unsigned long) // NOLINT
357 : INTEGER_BINARY_OPERATOR_AND(unsigned long long) // NOLINT
358 :
359 : #ifdef BOOST_HAS_INT128
360 : constexpr friend uint128 operator&(uint128 lhs, boost::int128_type rhs) noexcept { return lhs & uint128(rhs); }
361 : constexpr friend uint128 operator&(uint128 lhs, boost::uint128_type rhs) noexcept { return lhs & uint128(rhs); }
362 : #endif
363 :
364 : constexpr friend uint128 operator&(uint128 lhs, uint128 rhs) noexcept;
365 :
366 : BOOST_JSON_CXX14_CONSTEXPR uint128 &operator&=(uint128 v) noexcept;
367 :
368 : #undef INTEGER_BINARY_OPERATOR_AND
369 :
370 : // Xor
371 : #define INTEGER_BINARY_OPERATOR_XOR(expr) constexpr friend uint128 operator^(uint128 lhs, expr rhs) noexcept { return {lhs.high, lhs.low ^ static_cast<std::uint64_t>(rhs)}; } // NOLINT
372 :
373 : INTEGER_BINARY_OPERATOR_XOR(char) // NOLINT
374 : INTEGER_BINARY_OPERATOR_XOR(signed char) // NOLINT
375 : INTEGER_BINARY_OPERATOR_XOR(short) // NOLINT
376 : INTEGER_BINARY_OPERATOR_XOR(int) // NOLINT
377 : INTEGER_BINARY_OPERATOR_XOR(long) // NOLINT
378 : INTEGER_BINARY_OPERATOR_XOR(long long) // NOLINT
379 : INTEGER_BINARY_OPERATOR_XOR(unsigned char) // NOLINT
380 : INTEGER_BINARY_OPERATOR_XOR(unsigned short) // NOLINT
381 : INTEGER_BINARY_OPERATOR_XOR(unsigned) // NOLINT
382 : INTEGER_BINARY_OPERATOR_XOR(unsigned long) // NOLINT
383 : INTEGER_BINARY_OPERATOR_XOR(unsigned long long) // NOLINT
384 :
385 : #ifdef BOOST_HAS_INT128
386 : constexpr friend uint128 operator^(uint128 lhs, boost::int128_type rhs) noexcept { return lhs ^ uint128(rhs); }
387 : constexpr friend uint128 operator^(uint128 lhs, boost::uint128_type rhs) noexcept { return lhs ^ uint128(rhs); }
388 : #endif
389 :
390 : constexpr friend uint128 operator^(uint128 lhs, uint128 rhs) noexcept;
391 :
392 : BOOST_JSON_CXX14_CONSTEXPR uint128 &operator^=(uint128 v) noexcept;
393 :
394 : #undef INTEGER_BINARY_OPERATOR_XOR
395 :
396 : // Left shift
397 : #define INTEGER_BINARY_OPERATOR_LEFT_SHIFT(expr) \
398 : BOOST_CXX14_CONSTEXPR friend uint128 operator<<(uint128 lhs, expr rhs) noexcept \
399 : { \
400 : if (rhs >= 64) \
401 : { \
402 : return {lhs.low << (rhs - 64), 0}; \
403 : } \
404 : else if (rhs == 0) \
405 : { \
406 : return lhs; \
407 : } \
408 : \
409 : return {(lhs.high << rhs) | (lhs.low >> (64 - rhs)), lhs.low << rhs}; \
410 : } // NOLINT
411 :
412 : INTEGER_BINARY_OPERATOR_LEFT_SHIFT(char) // NOLINT
413 : INTEGER_BINARY_OPERATOR_LEFT_SHIFT(signed char) // NOLINT
414 : INTEGER_BINARY_OPERATOR_LEFT_SHIFT(short) // NOLINT
415 : INTEGER_BINARY_OPERATOR_LEFT_SHIFT(int) // NOLINT
416 : INTEGER_BINARY_OPERATOR_LEFT_SHIFT(long) // NOLINT
417 : INTEGER_BINARY_OPERATOR_LEFT_SHIFT(long long) // NOLINT
418 : INTEGER_BINARY_OPERATOR_LEFT_SHIFT(unsigned char) // NOLINT
419 : INTEGER_BINARY_OPERATOR_LEFT_SHIFT(unsigned short) // NOLINT
420 : INTEGER_BINARY_OPERATOR_LEFT_SHIFT(unsigned) // NOLINT
421 : INTEGER_BINARY_OPERATOR_LEFT_SHIFT(unsigned long) // NOLINT
422 : INTEGER_BINARY_OPERATOR_LEFT_SHIFT(unsigned long long) // NOLINT
423 :
424 : #define INTEGER_BINARY_OPERATOR_EQUALS_LEFT_SHIFT(expr) \
425 : BOOST_CXX14_CONSTEXPR uint128 &operator<<=(expr amount) noexcept \
426 : { \
427 : *this = *this << amount; \
428 : return *this; \
429 : } // NOLINT
430 :
431 : INTEGER_BINARY_OPERATOR_EQUALS_LEFT_SHIFT(char) // NOLINT
432 : INTEGER_BINARY_OPERATOR_EQUALS_LEFT_SHIFT(signed char) // NOLINT
433 : INTEGER_BINARY_OPERATOR_EQUALS_LEFT_SHIFT(short) // NOLINT
434 : INTEGER_BINARY_OPERATOR_EQUALS_LEFT_SHIFT(int) // NOLINT
435 : INTEGER_BINARY_OPERATOR_EQUALS_LEFT_SHIFT(long) // NOLINT
436 : INTEGER_BINARY_OPERATOR_EQUALS_LEFT_SHIFT(long long) // NOLINT
437 : INTEGER_BINARY_OPERATOR_EQUALS_LEFT_SHIFT(unsigned char) // NOLINT
438 : INTEGER_BINARY_OPERATOR_EQUALS_LEFT_SHIFT(unsigned short) // NOLINT
439 : INTEGER_BINARY_OPERATOR_EQUALS_LEFT_SHIFT(unsigned) // NOLINT
440 : INTEGER_BINARY_OPERATOR_EQUALS_LEFT_SHIFT(unsigned long) // NOLINT
441 : INTEGER_BINARY_OPERATOR_EQUALS_LEFT_SHIFT(unsigned long long) // NOLINT
442 :
443 : #undef INTEGER_BINARY_OPERATOR_LEFT_SHIFT
444 : #undef INTEGER_BINARY_OPERATOR_EQUALS_LEFT_SHIFT
445 :
446 : // Right Shift
447 : #define INTEGER_BINARY_OPERATOR_RIGHT_SHIFT(expr) \
448 : BOOST_CXX14_CONSTEXPR friend uint128 operator>>(uint128 lhs, expr amount) noexcept \
449 : { \
450 : if (amount >= 64) \
451 : { \
452 : return {0, lhs.high >> (amount - 64)}; \
453 : } \
454 : else if (amount == 0) \
455 : { \
456 : return lhs; \
457 : } \
458 : \
459 : return {lhs.high >> amount, (lhs.low >> amount) | (lhs.high << (64 - amount))}; \
460 : } // NOLINT
461 :
462 : INTEGER_BINARY_OPERATOR_RIGHT_SHIFT(char) // NOLINT
463 : INTEGER_BINARY_OPERATOR_RIGHT_SHIFT(signed char) // NOLINT
464 : INTEGER_BINARY_OPERATOR_RIGHT_SHIFT(short) // NOLINT
465 : INTEGER_BINARY_OPERATOR_RIGHT_SHIFT(int) // NOLINT
466 : INTEGER_BINARY_OPERATOR_RIGHT_SHIFT(long) // NOLINT
467 : INTEGER_BINARY_OPERATOR_RIGHT_SHIFT(long long) // NOLINT
468 : INTEGER_BINARY_OPERATOR_RIGHT_SHIFT(unsigned char) // NOLINT
469 : INTEGER_BINARY_OPERATOR_RIGHT_SHIFT(unsigned short) // NOLINT
470 : INTEGER_BINARY_OPERATOR_RIGHT_SHIFT(unsigned) // NOLINT
471 : INTEGER_BINARY_OPERATOR_RIGHT_SHIFT(unsigned long) // NOLINT
472 : INTEGER_BINARY_OPERATOR_RIGHT_SHIFT(unsigned long long) // NOLINT
473 :
474 : #define INTEGER_BINARY_OPERATOR_EQUALS_RIGHT_SHIFT(expr) \
475 : BOOST_JSON_CXX14_CONSTEXPR uint128 &operator>>=(expr amount) noexcept \
476 : { \
477 : *this = *this >> amount; \
478 : return *this; \
479 : } // NOLINT
480 :
481 : INTEGER_BINARY_OPERATOR_EQUALS_RIGHT_SHIFT(char) // NOLINT
482 : INTEGER_BINARY_OPERATOR_EQUALS_RIGHT_SHIFT(signed char) // NOLINT
483 : INTEGER_BINARY_OPERATOR_EQUALS_RIGHT_SHIFT(short) // NOLINT
484 : INTEGER_BINARY_OPERATOR_EQUALS_RIGHT_SHIFT(int) // NOLINT
485 : INTEGER_BINARY_OPERATOR_EQUALS_RIGHT_SHIFT(long) // NOLINT
486 : INTEGER_BINARY_OPERATOR_EQUALS_RIGHT_SHIFT(long long) // NOLINT
487 : INTEGER_BINARY_OPERATOR_EQUALS_RIGHT_SHIFT(unsigned char) // NOLINT
488 : INTEGER_BINARY_OPERATOR_EQUALS_RIGHT_SHIFT(unsigned short) // NOLINT
489 : INTEGER_BINARY_OPERATOR_EQUALS_RIGHT_SHIFT(unsigned) // NOLINT
490 : INTEGER_BINARY_OPERATOR_EQUALS_RIGHT_SHIFT(unsigned long) // NOLINT
491 : INTEGER_BINARY_OPERATOR_EQUALS_RIGHT_SHIFT(unsigned long long) // NOLINT
492 :
493 : #undef INTEGER_BINARY_OPERATOR_RIGHT_SHIFT
494 : #undef INTEGER_BINARY_OPERATOR_EQUALS_RIGHT_SHIFT
495 :
496 : // Arithmetic operators (Add, sub, mul, div, mod)
497 : inline uint128 &operator+=(std::uint64_t n) noexcept;
498 :
499 : BOOST_JSON_CXX14_CONSTEXPR friend uint128 operator+(uint128 lhs, uint128 rhs) noexcept;
500 :
501 : BOOST_JSON_CXX14_CONSTEXPR uint128 &operator+=(uint128 v) noexcept;
502 :
503 : BOOST_JSON_CXX14_CONSTEXPR uint128 &operator++() noexcept;
504 :
505 : BOOST_JSON_CXX14_CONSTEXPR const uint128 operator++(int) noexcept;
506 :
507 : BOOST_JSON_CXX14_CONSTEXPR friend uint128 operator-(uint128 lhs, uint128 rhs) noexcept;
508 :
509 : BOOST_JSON_CXX14_CONSTEXPR uint128 &operator-=(uint128 v) noexcept;
510 :
511 : BOOST_JSON_CXX14_CONSTEXPR uint128 &operator--() noexcept;
512 :
513 : BOOST_JSON_CXX14_CONSTEXPR const uint128 operator--(int) noexcept;
514 :
515 : BOOST_JSON_CXX14_CONSTEXPR friend uint128 operator*(uint128 lhs, uint128 rhs) noexcept;
516 :
517 : BOOST_JSON_CXX14_CONSTEXPR uint128 &operator*=(uint128 v) noexcept;
518 :
519 : BOOST_JSON_CXX14_CONSTEXPR friend uint128 operator/(uint128 lhs, uint128 rhs) noexcept;
520 :
521 : BOOST_JSON_CXX14_CONSTEXPR uint128 &operator/=(uint128 v) noexcept;
522 :
523 : BOOST_JSON_CXX14_CONSTEXPR friend uint128 operator%(uint128 lhs, uint128 rhs) noexcept;
524 :
525 : BOOST_JSON_CXX14_CONSTEXPR uint128 &operator%=(uint128 v) noexcept;
526 :
527 : private:
528 : BOOST_JSON_CXX14_CONSTEXPR friend int high_bit(uint128 v) noexcept;
529 :
530 : BOOST_JSON_CXX14_CONSTEXPR friend void
531 : div_impl(uint128 lhs, uint128 rhs, uint128 "ient, uint128 &remainder) noexcept;
532 : };
533 :
534 : constexpr uint128 operator-(uint128 val) noexcept
535 : {
536 : return {~val.high + static_cast<std::uint64_t>(val.low == 0), ~val.low + 1};
537 : }
538 :
539 : constexpr uint128 operator+(uint128 val) noexcept
540 : {
541 : return val;
542 : }
543 :
544 : BOOST_JSON_CXX14_CONSTEXPR uint128 &uint128::operator=(const uint128& v) noexcept // NOLINT : User defined for older compilers
545 : {
546 : low = v.low;
547 : high = v.high;
548 : return *this;
549 : }
550 :
551 : constexpr bool operator==(uint128 lhs, uint128 rhs) noexcept
552 : {
553 : return lhs.high == rhs.high && lhs.low == rhs.low;
554 : }
555 :
556 : constexpr bool operator!=(uint128 lhs, uint128 rhs) noexcept
557 : {
558 : return !(lhs == rhs);
559 : }
560 :
561 : BOOST_JSON_CXX14_CONSTEXPR bool operator<(uint128 lhs, uint128 rhs) noexcept
562 : {
563 : if (lhs.high == rhs.high)
564 : {
565 : return lhs.low < rhs.low;
566 : }
567 :
568 : return lhs.high < rhs.high;
569 : }
570 :
571 : BOOST_JSON_CXX14_CONSTEXPR bool operator<=(uint128 lhs, uint128 rhs) noexcept
572 : {
573 : return !(rhs < lhs);
574 : }
575 :
576 : BOOST_JSON_CXX14_CONSTEXPR bool operator>(uint128 lhs, uint128 rhs) noexcept
577 : {
578 : return rhs < lhs;
579 : }
580 :
581 : BOOST_JSON_CXX14_CONSTEXPR bool operator>=(uint128 lhs, uint128 rhs) noexcept
582 : {
583 : return !(lhs < rhs);
584 : }
585 :
586 : constexpr uint128 operator~(uint128 v) noexcept
587 : {
588 : return {~v.high, ~v.low};
589 : }
590 :
591 : constexpr uint128 operator|(uint128 lhs, uint128 rhs) noexcept
592 : {
593 : return {lhs.high | rhs.high, lhs.low | rhs.low};
594 : }
595 :
596 : BOOST_JSON_CXX14_CONSTEXPR uint128 &uint128::operator|=(uint128 v) noexcept
597 : {
598 : *this = *this | v;
599 : return *this;
600 : }
601 :
602 : constexpr uint128 operator&(uint128 lhs, uint128 rhs) noexcept
603 : {
604 : return {lhs.high & rhs.high, lhs.low & rhs.low};
605 : }
606 :
607 : BOOST_JSON_CXX14_CONSTEXPR uint128 &uint128::operator&=(uint128 v) noexcept
608 : {
609 : *this = *this & v;
610 : return *this;
611 : }
612 :
613 : constexpr uint128 operator^(uint128 lhs, uint128 rhs) noexcept
614 : {
615 : return {lhs.high ^ rhs.high, lhs.low ^ rhs.low};
616 : }
617 :
618 : BOOST_JSON_CXX14_CONSTEXPR uint128 &uint128::operator^=(uint128 v) noexcept
619 : {
620 : *this = *this ^ v;
621 : return *this;
622 : }
623 :
624 306 : inline uint128 &uint128::operator+=(std::uint64_t n) noexcept
625 : {
626 : #if BOOST_JSON_HAS_BUILTIN(__builtin_addcll)
627 :
628 : unsigned long long carry {};
629 : low = __builtin_addcll(low, n, 0, &carry);
630 : high = __builtin_addcll(high, 0, carry, &carry);
631 :
632 : #elif BOOST_JSON_HAS_BUILTIN(__builtin_ia32_addcarryx_u64)
633 :
634 306 : unsigned long long result {};
635 306 : auto carry = __builtin_ia32_addcarryx_u64(0, low, n, &result);
636 306 : low = result;
637 306 : __builtin_ia32_addcarryx_u64(carry, high, 0, &result);
638 306 : high = result;
639 :
640 : #elif defined(BOOST_MSVC) && defined(_M_X64)
641 :
642 : auto carry = _addcarry_u64(0, low, n, &low);
643 : _addcarry_u64(carry, high, 0, &high);
644 :
645 : #else
646 :
647 : auto sum = low + n;
648 : high += (sum < low ? 1 : 0);
649 : low = sum;
650 :
651 : #endif
652 306 : return *this;
653 : }
654 :
655 : BOOST_JSON_CXX14_CONSTEXPR uint128 operator+(uint128 lhs, uint128 rhs) noexcept
656 : {
657 : const uint128 temp = {lhs.high + rhs.high, lhs.low + rhs.low};
658 :
659 : // Need to carry a bit into rhs
660 : if (temp.low < lhs.low)
661 : {
662 : return {temp.high + 1, temp.low};
663 : }
664 :
665 : return temp;
666 : }
667 :
668 : BOOST_JSON_CXX14_CONSTEXPR uint128 &uint128::operator+=(uint128 v) noexcept
669 : {
670 : *this = *this + v;
671 : return *this;
672 : }
673 :
674 : BOOST_JSON_CXX14_CONSTEXPR uint128 &uint128::operator++() noexcept
675 : {
676 : if (this->low == UINT64_MAX)
677 : {
678 : this->low = 0;
679 : ++this->high;
680 : }
681 : else
682 : {
683 : ++this->low;
684 : }
685 :
686 : return *this;
687 : }
688 :
689 : BOOST_JSON_CXX14_CONSTEXPR const uint128 uint128::operator++(int) noexcept
690 : {
691 : return ++(*this);
692 : }
693 :
694 : BOOST_JSON_CXX14_CONSTEXPR uint128 operator-(uint128 lhs, uint128 rhs) noexcept
695 : {
696 : const uint128 temp {lhs.high - rhs.high, lhs.low - rhs.low};
697 :
698 : // Check for carry
699 : if (lhs.low < rhs.low)
700 : {
701 : return {temp.high - 1, temp.low};
702 : }
703 :
704 : return temp;
705 : }
706 :
707 : BOOST_JSON_CXX14_CONSTEXPR uint128 &uint128::operator-=(uint128 v) noexcept
708 : {
709 : *this = *this - v;
710 : return *this;
711 : }
712 :
713 : BOOST_JSON_CXX14_CONSTEXPR uint128 &uint128::operator--() noexcept
714 : {
715 : if (this->low == 0)
716 : {
717 : this->low = UINT64_MAX;
718 : --this->high;
719 : }
720 : else // NOLINT
721 : {
722 : --this->low;
723 : }
724 :
725 : return *this;
726 : }
727 :
728 : BOOST_JSON_CXX14_CONSTEXPR const uint128 uint128::operator--(int) noexcept
729 : {
730 : return --(*this);
731 : }
732 : BOOST_JSON_CXX14_CONSTEXPR uint128 operator*(uint128 lhs, uint128 rhs) noexcept
733 : {
734 : const auto a = static_cast<std::uint64_t>(lhs.low >> 32);
735 : const auto b = static_cast<std::uint64_t>(lhs.low & UINT32_MAX);
736 : const auto c = static_cast<std::uint64_t>(rhs.low >> 32);
737 : const auto d = static_cast<std::uint64_t>(rhs.low & UINT32_MAX);
738 :
739 : uint128 result { lhs.high * rhs.low + lhs.low * rhs.high + a * c, b * d };
740 : result += uint128(a * d) << 32;
741 : result += uint128(b * c) << 32;
742 : return result;
743 : }
744 :
745 : BOOST_JSON_CXX14_CONSTEXPR uint128 &uint128::operator*=(uint128 v) noexcept
746 : {
747 : *this = *this * v;
748 : return *this;
749 : }
750 :
751 : BOOST_JSON_CXX14_CONSTEXPR int high_bit(uint128 v) noexcept
752 : {
753 : if (v.high != 0)
754 : {
755 : return 127 - boost::core::countl_zero(v.high);
756 : }
757 : else if (v.low != 0)
758 : {
759 : return 63 - boost::core::countl_zero(v.low);
760 : }
761 :
762 : return 0;
763 : }
764 :
765 : // See: https://stackoverflow.com/questions/5386377/division-without-using
766 : BOOST_JSON_CXX14_CONSTEXPR void div_impl(uint128 lhs, uint128 rhs, uint128& quotient, uint128& remainder) noexcept
767 : {
768 : constexpr uint128 one {0, 1};
769 :
770 : if (rhs > lhs)
771 : {
772 : quotient = 0U;
773 : remainder = 0U;
774 : }
775 : else if (lhs == rhs)
776 : {
777 : quotient = 1U;
778 : remainder = 0U;
779 : }
780 :
781 : uint128 denom = rhs;
782 : quotient = 0U;
783 :
784 : std::int32_t shift = high_bit(lhs) - high_bit(rhs);
785 : if (shift < 0)
786 : {
787 : shift = 32 - shift;
788 : }
789 : denom <<= shift;
790 :
791 : for (int i = 0; i <= shift; ++i)
792 : {
793 : quotient <<= 1;
794 : if (lhs >= denom)
795 : {
796 : lhs -= denom;
797 : quotient |= one;
798 : }
799 : denom >>= 1;
800 : }
801 :
802 : remainder = lhs;
803 : }
804 :
805 : BOOST_JSON_CXX14_CONSTEXPR uint128 operator/(uint128 lhs, uint128 rhs) noexcept
806 : {
807 : uint128 quotient {0, 0};
808 : uint128 remainder {0, 0};
809 : div_impl(lhs, rhs, quotient, remainder);
810 :
811 : return quotient;
812 : }
813 :
814 : BOOST_JSON_CXX14_CONSTEXPR uint128 &uint128::operator/=(uint128 v) noexcept
815 : {
816 : *this = *this / v;
817 : return *this;
818 : }
819 :
820 : BOOST_JSON_CXX14_CONSTEXPR uint128 operator%(uint128 lhs, uint128 rhs) noexcept
821 : {
822 : uint128 quotient {0, 0};
823 : uint128 remainder {0, 0};
824 : div_impl(lhs, rhs, quotient, remainder);
825 :
826 : return remainder;
827 : }
828 :
829 : BOOST_JSON_CXX14_CONSTEXPR uint128 &uint128::operator%=(uint128 v) noexcept
830 : {
831 : *this = *this % v;
832 : return *this;
833 : }
834 :
835 : static inline std::uint64_t umul64(std::uint32_t x, std::uint32_t y) noexcept
836 : {
837 : // __emulu is not available on ARM https://learn.microsoft.com/en-us/cpp/intrinsics/emul-emulu?view=msvc-170
838 : #if defined(BOOST_JSON_HAS_MSVC_32BIT_INTRINSICS) && !defined(_M_ARM)
839 :
840 : return __emulu(x, y);
841 :
842 : #else
843 :
844 : return x * static_cast<std::uint64_t>(y);
845 :
846 : #endif
847 : }
848 :
849 : // Get 128-bit result of multiplication of two 64-bit unsigned integers.
850 749 : BOOST_JSON_SAFEBUFFERS inline uint128 umul128(std::uint64_t x, std::uint64_t y) noexcept
851 : {
852 : #if defined(BOOST_HAS_INT128)
853 :
854 749 : auto result = static_cast<boost::uint128_type>(x) * static_cast<boost::uint128_type>(y);
855 749 : return {static_cast<std::uint64_t>(result >> 64), static_cast<std::uint64_t>(result)};
856 :
857 : // _umul128 is x64 only https://learn.microsoft.com/en-us/cpp/intrinsics/umul128?view=msvc-170
858 : #elif defined(BOOST_JSON_HAS_MSVC_64BIT_INTRINSICS) && !defined(_M_ARM64)
859 :
860 : unsigned long long high;
861 : std::uint64_t low = _umul128(x, y, &high);
862 : return {static_cast<std::uint64_t>(high), low};
863 :
864 : // https://developer.arm.com/documentation/dui0802/a/A64-General-Instructions/UMULH
865 : #elif defined(_M_ARM64) && !defined(__MINGW32__)
866 :
867 : std::uint64_t high = __umulh(x, y);
868 : std::uint64_t low = x * y;
869 : return {high, low};
870 :
871 : #else
872 :
873 : auto a = static_cast<std::uint32_t>(x >> 32);
874 : auto b = static_cast<std::uint32_t>(x);
875 : auto c = static_cast<std::uint32_t>(y >> 32);
876 : auto d = static_cast<std::uint32_t>(y);
877 :
878 : auto ac = umul64(a, c);
879 : auto bc = umul64(b, c);
880 : auto ad = umul64(a, d);
881 : auto bd = umul64(b, d);
882 :
883 : auto intermediate = (bd >> 32) + static_cast<std::uint32_t>(ad) + static_cast<std::uint32_t>(bc);
884 :
885 : return {ac + (intermediate >> 32) + (ad >> 32) + (bc >> 32),
886 : (intermediate << 32) + static_cast<std::uint32_t>(bd)};
887 :
888 : #endif
889 : }
890 :
891 612 : BOOST_JSON_SAFEBUFFERS inline std::uint64_t umul128_upper64(std::uint64_t x, std::uint64_t y) noexcept
892 : {
893 : #if defined(BOOST_HAS_INT128)
894 :
895 612 : auto result = static_cast<boost::uint128_type>(x) * static_cast<boost::uint128_type>(y);
896 612 : return static_cast<std::uint64_t>(result >> 64);
897 :
898 : #elif defined(BOOST_JSON_HAS_MSVC_64BIT_INTRINSICS)
899 :
900 : return __umulh(x, y);
901 :
902 : #else
903 :
904 : auto a = static_cast<std::uint32_t>(x >> 32);
905 : auto b = static_cast<std::uint32_t>(x);
906 : auto c = static_cast<std::uint32_t>(y >> 32);
907 : auto d = static_cast<std::uint32_t>(y);
908 :
909 : auto ac = umul64(a, c);
910 : auto bc = umul64(b, c);
911 : auto ad = umul64(a, d);
912 : auto bd = umul64(b, d);
913 :
914 : auto intermediate = (bd >> 32) + static_cast<std::uint32_t>(ad) + static_cast<std::uint32_t>(bc);
915 :
916 : return ac + (intermediate >> 32) + (ad >> 32) + (bc >> 32);
917 :
918 : #endif
919 : }
920 :
921 : // Get upper 128-bits of multiplication of a 64-bit unsigned integer and a 128-bit
922 : // unsigned integer.
923 306 : BOOST_JSON_SAFEBUFFERS inline uint128 umul192_upper128(std::uint64_t x, uint128 y) noexcept
924 : {
925 306 : auto r = umul128(x, y.high);
926 306 : r += umul128_upper64(x, y.low);
927 306 : return r;
928 : }
929 :
930 : // Get upper 64-bits of multiplication of a 32-bit unsigned integer and a 64-bit
931 : // unsigned integer.
932 : inline std::uint64_t umul96_upper64(std::uint32_t x, std::uint64_t y) noexcept
933 : {
934 : #if defined(BOOST_HAS_INT128) || defined(BOOST_JSON_HAS_MSVC_64BIT_INTRINSICS)
935 :
936 : return umul128_upper64(static_cast<std::uint64_t>(x) << 32, y);
937 :
938 : #else
939 :
940 : auto yh = static_cast<std::uint32_t>(y >> 32);
941 : auto yl = static_cast<std::uint32_t>(y);
942 :
943 : auto xyh = umul64(x, yh);
944 : auto xyl = umul64(x, yl);
945 :
946 : return xyh + (xyl >> 32);
947 :
948 : #endif
949 : }
950 :
951 : // Get lower 128-bits of multiplication of a 64-bit unsigned integer and a 128-bit
952 : // unsigned integer.
953 0 : BOOST_JSON_SAFEBUFFERS inline uint128 umul192_lower128(std::uint64_t x, uint128 y) noexcept
954 : {
955 0 : auto high = x * y.high;
956 0 : auto highlow = umul128(x, y.low);
957 0 : return {high + highlow.high, highlow.low};
958 : }
959 :
960 : // Get lower 64-bits of multiplication of a 32-bit unsigned integer and a 64-bit
961 : // unsigned integer.
962 : inline std::uint64_t umul96_lower64(std::uint32_t x, std::uint64_t y) noexcept
963 : {
964 : return x * y;
965 : }
966 :
967 : } // namespace detail
968 : } // namespace json
969 : } // namespace boost
970 :
971 : // Non-standard libraries may add specializations for library-provided types
972 : namespace std {
973 :
974 : template <>
975 : struct numeric_limits<boost::json::detail::uint128>
976 : {
977 : // Member constants
978 : BOOST_ATTRIBUTE_UNUSED static constexpr bool is_specialized = true;
979 : BOOST_ATTRIBUTE_UNUSED static constexpr bool is_signed = false;
980 : BOOST_ATTRIBUTE_UNUSED static constexpr bool is_integer = true;
981 : BOOST_ATTRIBUTE_UNUSED static constexpr bool is_exact = true;
982 : BOOST_ATTRIBUTE_UNUSED static constexpr bool has_infinity = false;
983 : BOOST_ATTRIBUTE_UNUSED static constexpr bool has_quiet_NaN = false;
984 : BOOST_ATTRIBUTE_UNUSED static constexpr bool has_signaling_NaN = false;
985 : BOOST_ATTRIBUTE_UNUSED static constexpr std::float_round_style round_style = std::round_toward_zero;
986 : BOOST_ATTRIBUTE_UNUSED static constexpr bool is_iec559 = false;
987 : BOOST_ATTRIBUTE_UNUSED static constexpr bool is_bounded = true;
988 : BOOST_ATTRIBUTE_UNUSED static constexpr bool is_modulo = true;
989 : BOOST_ATTRIBUTE_UNUSED static constexpr int digits = 128;
990 : BOOST_ATTRIBUTE_UNUSED static constexpr int digits10 = 38;
991 : BOOST_ATTRIBUTE_UNUSED static constexpr int max_digits10 = 0;
992 : BOOST_ATTRIBUTE_UNUSED static constexpr int radix = 2;
993 : BOOST_ATTRIBUTE_UNUSED static constexpr int min_exponent = 0;
994 : BOOST_ATTRIBUTE_UNUSED static constexpr int min_exponent10 = 0;
995 : BOOST_ATTRIBUTE_UNUSED static constexpr int max_exponent = 0;
996 : BOOST_ATTRIBUTE_UNUSED static constexpr int max_exponent10 = 0;
997 : BOOST_ATTRIBUTE_UNUSED static constexpr bool traps = std::numeric_limits<std::uint64_t>::traps;
998 : BOOST_ATTRIBUTE_UNUSED static constexpr bool tinyness_before = false;
999 :
1000 : // Member functions
1001 : BOOST_ATTRIBUTE_UNUSED static constexpr boost::json::detail::uint128 (min)() { return 0; }
1002 : BOOST_ATTRIBUTE_UNUSED static constexpr boost::json::detail::uint128 lowest() { return 0; }
1003 : BOOST_ATTRIBUTE_UNUSED static constexpr boost::json::detail::uint128 (max)() { return {UINT64_MAX, UINT64_MAX}; }
1004 : BOOST_ATTRIBUTE_UNUSED static constexpr boost::json::detail::uint128 epsilon() { return 0; }
1005 : BOOST_ATTRIBUTE_UNUSED static constexpr boost::json::detail::uint128 round_error() { return 0; }
1006 : BOOST_ATTRIBUTE_UNUSED static constexpr boost::json::detail::uint128 infinity() { return 0; }
1007 : BOOST_ATTRIBUTE_UNUSED static constexpr boost::json::detail::uint128 quiet_NaN() { return 0; }
1008 : BOOST_ATTRIBUTE_UNUSED static constexpr boost::json::detail::uint128 signaling_NaN() { return 0; }
1009 : BOOST_ATTRIBUTE_UNUSED static constexpr boost::json::detail::uint128 (denorm_min)() { return 0; }
1010 : };
1011 :
1012 : } // Namespace std
1013 :
1014 : #endif // BOOST_JSON_DETAIL_DRAGONBOX_EMULATED128_HPP
|