GCC Code Coverage Report


Directory: libs/json/include/boost/json/
File: detail/dragonbox/emulated128.hpp
Date: 2025-12-23 16:57:39
Exec Total Coverage
Lines: 18 22 81.8%
Functions: 5 6 83.3%
Branches: 0 0 -%

Line Branch Exec Source
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 &quotient, 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 BOOST_JSON_SAFEBUFFERS inline uint128 umul192_lower128(std::uint64_t x, uint128 y) noexcept
954 {
955 auto high = x * y.high;
956 auto highlow = umul128(x, y.low);
957 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
1015