ipaddress 1.1.0
Loading...
Searching...
No Matches
uint128.hpp
Go to the documentation of this file.
1/**
2 * @file uint128.hpp
3 * @brief Defines `uint128_t`, a portable 128-bit unsigned integer type
4 * @author Vladimir Shaleev
5 * @copyright MIT License
6 *
7 * This header introduces `uint128_t`, a class that emulates a 128-bit unsigned integer.
8 * It is designed to fill the gap in the C++ standard, which does not natively support
9 * 128-bit integers across all platforms. Unlike compiler-specific extensions like `__int128`,
10 * `uint128_t` ensures compatibility and portability across different compilers and architectures.
11 * The implementation is inspired by the algorithms used in the .NET framework's
12 * [UInt128](https://source.dot.net/#System.Private.CoreLib/src/libraries/System.Private.CoreLib/src/System/UInt128.cs),
13 * providing a reliable foundation for arithmetic operations and other integer-related functionalities.
14 * The class integrates seamlessly with the `ipaddress` library, offering standard hash support and
15 * optional type compatibility.
16 *
17 * The `uint128_t` type is especially useful in applications requiring precise control over
18 * large integer values, such as cryptography, high-precision arithmetic, and IP address manipulation.
19 * Its design prioritizes accuracy, making it a robust tool for developers
20 * working with high-volume data or complex numerical computations.
21 */
22
23#ifndef IPADDRESS_UINT128_HPP
24#define IPADDRESS_UINT128_HPP
25
26#include "config.hpp"
27#include "hash.hpp"
28#include "optional.hpp"
29
30namespace IPADDRESS_NAMESPACE {
31
32/**
33 * Class for representing a 128-bit unsigned integer.
34 *
35 * `uint128_t` offers a comprehensive suite of operations and utilities for handling
36 * 128-bit unsigned integers. It supports basic arithmetic operations, bitwise logic,
37 * comparison operators, and specialized functions for advanced integer manipulation.
38 * The class is optimized for both space and time efficiency, ensuring minimal overhead
39 * and maximum performance.
40 *
41 * The design of `uint128_t` is focused on ease of use and integration. It provides
42 * constructors for seamless conversion from built-in integer types, as well as explicit
43 * methods for converting to and from other numeric representations. The class also
44 * includes support for standard library features like hashing and optional values,
45 * enhancing its utility in a wide range of programming scenarios.
46 *
47 * The implementation is based on algorithms from the .NET `UInt128`
48 * structure, ensuring reliable and efficient operations.
49 *
50 * @see [UInt128](https://source.dot.net/#System.Private.CoreLib/src/libraries/System.Private.CoreLib/src/System/UInt128.cs) .NET Implementation.
51 */
52IPADDRESS_EXPORT class uint128_t final { // NOLINT(cppcoreguidelines-special-member-functions)
53public:
54 /**
55 * Enumerates the string formats available for `uint128_t`.
56 *
57 * This enumeration defines the possible string representations of `uint128_t` values.
58 * It allows users to specify the desired format when converting `uint128_t` instances to strings.
59 */
60 enum class format {
61 decimal = 0, /**< Represents the number in decimal format. *This is the default format.* */
62 octal, /**< Represents the number in octal format. */
63 hexadecimal /**< Represents the number in hexadecimal format. */
64 };
65
66 /**
67 * Default constructor.
68 *
69 * Constructs a new `uint128_t` instance with default values.
70 */
71 IPADDRESS_CONSTEXPR IPADDRESS_FORCE_INLINE uint128_t() IPADDRESS_NOEXCEPT = default;
72
73 /**
74 * Copy constructor.
75 *
76 * Constructs a new `uint128_t` instance by copying the value from another instance.
77 *
78 * @param[in] other The `uint128_t` instance to copy.
79 */
80 IPADDRESS_CONSTEXPR IPADDRESS_FORCE_INLINE uint128_t(const uint128_t& other) IPADDRESS_NOEXCEPT = default;
81
82 /**
83 * Move constructor.
84 *
85 * Constructs a new `uint128_t` instance by moving the value from another instance.
86 *
87 * @param[in,out] other The `uint128_t` instance to move.
88 */
89 IPADDRESS_CONSTEXPR IPADDRESS_FORCE_INLINE uint128_t(uint128_t&& other) IPADDRESS_NOEXCEPT = default;
90
91 /**
92 * Assignment operator.
93 *
94 * Assigns the value of one `uint128_t` instance to another.
95 *
96 * @param[in] other The `uint128_t` instance to assign from.
97 * @return A reference to the assigned `uint128_t` instance.
98 */
99 IPADDRESS_CONSTEXPR IPADDRESS_FORCE_INLINE uint128_t& operator=(const uint128_t& other) IPADDRESS_NOEXCEPT = default;
100
101 /**
102 * Move assignment operator.
103 *
104 * Moves the value of one `uint128_t` instance to another.
105 *
106 * @param[in,out] other The `uint128_t` instance to move from.
107 * @return A reference to the moved `uint128_t` instance.
108 */
109 IPADDRESS_CONSTEXPR IPADDRESS_FORCE_INLINE uint128_t& operator=(uint128_t&& other) IPADDRESS_NOEXCEPT = default;
110
111 /**
112 * Constructs a `uint128_t` instance from upper and lower parts.
113 *
114 * This constructor initializes a `uint128_t` instance using separate upper and lower 64-bit integers.
115 *
116 * @param[in] upper The upper 64 bits of the `uint128_t` value.
117 * @param[in] lower The lower 64 bits of the `uint128_t` value.
118 */
119 IPADDRESS_CONSTEXPR IPADDRESS_FORCE_INLINE uint128_t(uint64_t upper, uint64_t lower) IPADDRESS_NOEXCEPT
120
121#if IPADDRESS_ENDIAN == IPADDRESS_BIG_ENDIAN
122
123 : _upper(upper), _lower(lower)
124
125#else // IPADDRESS_ENDIAN != IPADDRESS_BIG_ENDIAN
126
128
129#endif // IPADDRESS_ENDIAN != IPADDRESS_BIG_ENDIAN
130 { }
131
132 /**
133 * Constructs a `uint128_t` instance from an unsigned integer.
134 *
135 * This constructor initializes a `uint128_t` instance using an unsigned integer,
136 * setting it as the lower part of the `uint128_t` value.
137 *
138 * @param[in] lower The unsigned integer to initialize the `uint128_t` instance with.
139 */
140 IPADDRESS_CONSTEXPR IPADDRESS_FORCE_INLINE uint128_t(unsigned long long lower) IPADDRESS_NOEXCEPT : _lower(uint64_t(lower)) {
141 }
142
143 /**
144 * Constructs a `uint128_t` instance from an unsigned integer.
145 *
146 * This constructor initializes a `uint128_t` instance using an unsigned integer,
147 * setting it as the lower part of the `uint128_t` value.
148 *
149 * @param[in] lower The unsigned integer to initialize the `uint128_t` instance with.
150 */
151 IPADDRESS_CONSTEXPR IPADDRESS_FORCE_INLINE uint128_t(unsigned long lower) IPADDRESS_NOEXCEPT : uint128_t((unsigned long long) lower) {
152 }
153
154 /**
155 * Constructs a `uint128_t` instance from an unsigned integer.
156 *
157 * This constructor initializes a `uint128_t` instance using an unsigned integer,
158 * setting it as the lower part of the `uint128_t` value.
159 *
160 * @param[in] lower The unsigned integer to initialize the `uint128_t` instance with.
161 */
162 IPADDRESS_CONSTEXPR IPADDRESS_FORCE_INLINE uint128_t(unsigned int lower) IPADDRESS_NOEXCEPT : uint128_t((unsigned long long) lower) {
163 }
164
165 /**
166 * Constructs a `uint128_t` instance from an unsigned integer.
167 *
168 * This constructor initializes a `uint128_t` instance using an unsigned integer,
169 * setting it as the lower part of the `uint128_t` value.
170 *
171 * @param[in] lower The unsigned integer to initialize the `uint128_t` instance with.
172 */
173 IPADDRESS_CONSTEXPR IPADDRESS_FORCE_INLINE uint128_t(unsigned short lower) IPADDRESS_NOEXCEPT : uint128_t((unsigned long long) lower) {
174 }
175
176 /**
177 * Constructs a `uint128_t` instance from a signed integer.
178 *
179 * This constructor initializes a `uint128_t` instance using a signed integer,
180 * setting it as the lower part of the `uint128_t` value and extending the sign to the upper part.
181 *
182 * @param[in] lower The signed integer to initialize the `uint128_t` instance with.
183 */
184 IPADDRESS_CONSTEXPR IPADDRESS_FORCE_INLINE uint128_t(long long lower) IPADDRESS_NOEXCEPT
185
186#if IPADDRESS_ENDIAN == IPADDRESS_BIG_ENDIAN
187
188 : _upper(uint64_t(int64_t(lower) >> 63)), _lower(uint64_t(lower))
189
190#else // IPADDRESS_ENDIAN != IPADDRESS_BIG_ENDIAN
191
193
194#endif // IPADDRESS_ENDIAN != IPADDRESS_BIG_ENDIAN
195 { }
196
197 /**
198 * Constructs a `uint128_t` instance from a signed integer.
199 *
200 * This constructor initializes a `uint128_t` instance using a signed integer,
201 * setting it as the lower part of the `uint128_t` value and extending the sign to the upper part.
202 *
203 * @param[in] lower The signed integer to initialize the `uint128_t` instance with.
204 */
205 IPADDRESS_CONSTEXPR IPADDRESS_FORCE_INLINE uint128_t(long lower) IPADDRESS_NOEXCEPT : uint128_t((long long) lower) {
206 }
207
208 /**
209 * Constructs a `uint128_t` instance from a signed integer.
210 *
211 * This constructor initializes a `uint128_t` instance using a signed integer,
212 * setting it as the lower part of the `uint128_t` value and extending the sign to the upper part.
213 *
214 * @param[in] lower The signed integer to initialize the `uint128_t` instance with.
215 */
216 IPADDRESS_CONSTEXPR IPADDRESS_FORCE_INLINE uint128_t(int lower) IPADDRESS_NOEXCEPT : uint128_t((long long) lower) {
217 }
218
219 /**
220 * Constructs a `uint128_t` instance from a signed integer.
221 *
222 * This constructor initializes a `uint128_t` instance using a signed integer,
223 * setting it as the lower part of the `uint128_t` value and extending the sign to the upper part.
224 *
225 * @param[in] lower The signed integer to initialize the `uint128_t` instance with.
226 */
227 IPADDRESS_CONSTEXPR IPADDRESS_FORCE_INLINE uint128_t(short lower) IPADDRESS_NOEXCEPT : uint128_t((long long) lower) {
228 }
229
230 /**
231 * Constructs a `uint128_t` instance from a floating-point value.
232 *
233 * This constructor initializes a `uint128_t` instance by converting a floating-point value to its
234 * 128-bit unsigned integer representation. The conversion is explicit to prevent unintended implicit conversions.
235 *
236 * @param[in] value The floating-point value to convert.
237 */
239 const auto result = from_double(value);
240 _upper = result._upper;
241 _lower = result._lower;
242 }
243
244 /**
245 * Constructs a `uint128_t` instance from a floating-point value.
246 *
247 * This constructor initializes a `uint128_t` instance by converting a floating-point value to its
248 * 128-bit unsigned integer representation. The conversion is explicit to prevent unintended implicit conversions.
249 *
250 * @param[in] value The floating-point value to convert.
251 */
252 IPADDRESS_FORCE_INLINE explicit uint128_t(long double value) IPADDRESS_NOEXCEPT : uint128_t((double) value) {
253 }
254
255 /**
256 * Constructs a `uint128_t` instance from a floating-point value.
257 *
258 * This constructor initializes a `uint128_t` instance by converting a floating-point value to its
259 * 128-bit unsigned integer representation. The conversion is explicit to prevent unintended implicit conversions.
260 *
261 * @param[in] value The floating-point value to convert.
262 */
263 IPADDRESS_FORCE_INLINE explicit uint128_t(float value) IPADDRESS_NOEXCEPT : uint128_t((double) value) {
264 }
265
266 /**
267 * Retrieves the lower 64 bits of the `uint128_t` value.
268 *
269 * This method returns the lower part of the `uint128_t` instance, allowing access to the least significant bits.
270 *
271 * @return The lower 64 bits as a `uint64_t`.
272 */
274 return _lower;
275 }
276
277 /**
278 * Retrieves the upper 64 bits of the `uint128_t` value.
279 *
280 * This method returns the upper part of the `uint128_t` instance, allowing access to the most significant bits.
281 *
282 * @return The upper 64 bits as a `uint64_t`.
283 */
285 return _upper;
286 }
287
288 /**
289 * Computes the hash value of the `uint128_t` instance.
290 *
291 * This method calculates a hash value for the `uint128_t` instance, which can be used in hash-based data structures.
292 *
293 * @return A `size_t` representing the hash value of the `uint128_t` instance.
294 */
296 internal::hash_combine<8> hasher{};
297 const auto seed = hasher(_upper);
298 const auto hash = hasher(seed + 0x9e3779b9 + _lower);
299 return hash;
300 }
301
302 /**
303 * Swaps the values of two `uint128_t` instances.
304 *
305 * This method exchanges the contents of the `uint128_t` instance with those of another instance.
306 *
307 * @param[in,out] other The other `uint128_t` instance to swap with.
308 */
309 IPADDRESS_CONSTEXPR IPADDRESS_FORCE_INLINE void swap(uint128_t& other) IPADDRESS_NOEXCEPT {
310 const auto tmp = *this;
311 *this = other;
312 other = tmp;
313 }
314
315 /**
316 * Converts the `uint128_t` value to a string representation.
317 *
318 * This method converts the `uint128_t` instance to its string representation in the specified format.
319 * It supports decimal, octal, and hexadecimal formats.
320 *
321 * @param[in] fmt The format to use for the conversion, with `format::decimal` as the default.
322 * @return A `std::string` holding the converted value.
323 */
325 if (_upper == 0) {
326 std::ostringstream ss;
327 switch (fmt) {
328 case format::octal:
329 ss << std::oct;
330 break;
332 ss << std::hex;
333 break;
334 default:
335 ss << std::dec;
336 break;
337 }
338 ss << _lower;
339 return ss.str();
340 }
341
342 switch (fmt) {
343 case format::octal:
344 return uint128_to_oct_str(*this);
346 return uint128_to_hex_str(*this);
347 default:
348 return uint128_to_dec_str(*this);
349 }
350 }
351
352 /**
353 * Converts the `uint128_t` value to a string representation.
354 *
355 * This method converts the `uint128_t` instance to its string representation in the specified format.
356 * It supports decimal, octal, and hexadecimal formats.
357 *
358 * @param[in] fmt The format to use for the conversion, with `format::decimal` as the default.
359 * @return A `std::wstring` holding the converted value.
360 */
362 return internal::string_converter<wchar_t>::convert(to_string(fmt));
363 }
364
365 /**
366 * Converts the `uint128_t` value to a string representation.
367 *
368 * This method converts the `uint128_t` instance to its string representation in the specified format.
369 * It supports decimal, octal, and hexadecimal formats.
370 *
371 * @param[in] fmt The format to use for the conversion, with `format::decimal` as the default.
372 * @return A `std::u16string` holding the converted value.
373 */
375 return internal::string_converter<char16_t>::convert(to_string(fmt));
376 }
377
378 /**
379 * Converts the `uint128_t` value to a string representation.
380 *
381 * This method converts the `uint128_t` instance to its string representation in the specified format.
382 * It supports decimal, octal, and hexadecimal formats.
383 *
384 * @param[in] fmt The format to use for the conversion, with `format::decimal` as the default.
385 * @return A `std::u32string` holding the converted value.
386 */
388 return internal::string_converter<char32_t>::convert(to_string(fmt));
389 }
390
391#if __cpp_char8_t >= 201811L
392
393 /**
394 * Converts the `uint128_t` value to a string representation.
395 *
396 * This method converts the `uint128_t` instance to its string representation in the specified format.
397 * It supports decimal, octal, and hexadecimal formats.
398 *
399 * @param[in] fmt The format to use for the conversion, with `format::decimal` as the default.
400 * @return A `std::u8string` holding the converted value.
401 */
404 }
405
406#endif // __cpp_char8_t
407
408 /**
409 * Parses a string to a `uint128_t` instance.
410 *
411 * This static method attempts to parse a given string as a `uint128_t` value in the specified format.
412 * If the parsing is successful, it returns an optional containing the parsed `uint128_t` value.
413 *
414 * @param[in] str The input string to parse.
415 * @param[in] fmt The string format to interpret the input string (*defaults to decimal*).
416 * @return An optional containing the parsed `uint128_t` value if successful, otherwise an empty optional.
417 */
419 return str_to_uint128(str.data(), str.data() + str.length(), fmt);
420 }
421
422 /**
423 * Parses a string to a `uint128_t` instance.
424 *
425 * This static method attempts to parse a given string as a `uint128_t` value in the specified format.
426 * If the parsing is successful, it returns an optional containing the parsed `uint128_t` value.
427 *
428 * @param[in] str The input string to parse.
429 * @param[in] fmt The string format to interpret the input string (*defaults to decimal*).
430 * @return An optional containing the parsed `uint128_t` value if successful, otherwise an empty optional.
431 */
433 return str_to_uint128(str.data(), str.data() + str.length(), fmt);
434 }
435
436 /**
437 * Parses a string to a `uint128_t` instance.
438 *
439 * This static method attempts to parse a given string as a `uint128_t` value in the specified format.
440 * If the parsing is successful, it returns an optional containing the parsed `uint128_t` value.
441 *
442 * @param[in] str The input string to parse.
443 * @param[in] fmt The string format to interpret the input string (*defaults to decimal*).
444 * @return An optional containing the parsed `uint128_t` value if successful, otherwise an empty optional.
445 */
447 return str_to_uint128(str.data(), str.data() + str.length(), fmt);
448 }
449
450 /**
451 * Parses a string to a `uint128_t` instance.
452 *
453 * This static method attempts to parse a given string as a `uint128_t` value in the specified format.
454 * If the parsing is successful, it returns an optional containing the parsed `uint128_t` value.
455 *
456 * @param[in] str The input string to parse.
457 * @param[in] fmt The string format to interpret the input string (*defaults to decimal*).
458 * @return An optional containing the parsed `uint128_t` value if successful, otherwise an empty optional.
459 */
461 return str_to_uint128(str.data(), str.data() + str.length(), fmt);
462 }
463
464#if __cpp_char8_t >= 201811L
465
466 /**
467 * Parses a string to a `uint128_t` instance.
468 *
469 * This static method attempts to parse a given string as a `uint128_t` value in the specified format.
470 * If the parsing is successful, it returns an optional containing the parsed `uint128_t` value.
471 *
472 * @param[in] str The input string to parse.
473 * @param[in] fmt The string format to interpret the input string (*defaults to decimal*).
474 * @return An optional containing the parsed `uint128_t` value if successful, otherwise an empty optional.
475 */
477 return str_to_uint128(str.data(), str.data() + str.length(), fmt);
478 }
479
480#endif // __cpp_char8_t
481
482 /**
483 * Parses a string to a `uint128_t` instance.
484 *
485 * This static method attempts to parse a given string as a `uint128_t` value in the specified format.
486 * If the parsing is successful, it returns an optional containing the parsed `uint128_t` value.
487 *
488 * @tparam T The character type of the array.
489 * @tparam N The size of the character array.
490 * @param[in] str The input string to parse.
491 * @param[in] fmt The string format to interpret the input string (*defaults to decimal*).
492 * @return An optional containing the parsed `uint128_t` value if successful, otherwise an empty optional.
493 */
494 template <typename T, size_t N>
496 return str_to_uint128(str, str + N, fmt);
497 }
498
499 /**
500 * Checks if the `uint128_t` value is non-zero.
501 *
502 * This method allows `uint128_t` instances to be contextually converted to a boolean to check for non-zero values.
503 *
504 * @return `true` if the `uint128_t` value is non-zero, `false` otherwise.
505 */
506 IPADDRESS_NODISCARD IPADDRESS_CONSTEXPR IPADDRESS_FORCE_INLINE explicit operator bool() const IPADDRESS_NOEXCEPT {
507 return _upper || _lower;
508 }
509
510 /**
511 * Casts the `uint128_t` value to an integral type.
512 *
513 * This method allows for the explicit conversion of a `uint128_t` value to a specified integral type.
514 *
515 * @return The `uint128_t` value cast to the specified integral type.
516 */
517 IPADDRESS_NODISCARD IPADDRESS_CONSTEXPR IPADDRESS_FORCE_INLINE explicit operator unsigned long long() const IPADDRESS_NOEXCEPT {
518 return (unsigned long long) _lower;
519 }
520
521 /**
522 * Casts the `uint128_t` value to an integral type.
523 *
524 * This method allows for the explicit conversion of a `uint128_t` value to a specified integral type.
525 *
526 * @return The `uint128_t` value cast to the specified integral type.
527 */
528 IPADDRESS_NODISCARD IPADDRESS_CONSTEXPR IPADDRESS_FORCE_INLINE explicit operator long long() const IPADDRESS_NOEXCEPT {
529 return (long long) _lower;
530 }
531
532 /**
533 * Casts the `uint128_t` value to an integral type.
534 *
535 * This method allows for the explicit conversion of a `uint128_t` value to a specified integral type.
536 *
537 * @return The `uint128_t` value cast to the specified integral type.
538 */
539 IPADDRESS_NODISCARD IPADDRESS_CONSTEXPR IPADDRESS_FORCE_INLINE explicit operator unsigned long() const IPADDRESS_NOEXCEPT {
540 return (unsigned long) _lower;
541 }
542
543 /**
544 * Casts the `uint128_t` value to an integral type.
545 *
546 * This method allows for the explicit conversion of a `uint128_t` value to a specified integral type.
547 *
548 * @return The `uint128_t` value cast to the specified integral type.
549 */
550 IPADDRESS_NODISCARD IPADDRESS_CONSTEXPR IPADDRESS_FORCE_INLINE explicit operator long() const IPADDRESS_NOEXCEPT {
551 return (long) _lower;
552 }
553
554 /**
555 * Casts the `uint128_t` value to an integral type.
556 *
557 * This method allows for the explicit conversion of a `uint128_t` value to a specified integral type.
558 *
559 * @return The `uint128_t` value cast to the specified integral type.
560 */
561 IPADDRESS_NODISCARD IPADDRESS_CONSTEXPR IPADDRESS_FORCE_INLINE explicit operator unsigned int() const IPADDRESS_NOEXCEPT {
562 return (unsigned int) _lower;
563 }
564
565 /**
566 * Casts the `uint128_t` value to an integral type.
567 *
568 * This method allows for the explicit conversion of a `uint128_t` value to a specified integral type.
569 *
570 * @return The `uint128_t` value cast to the specified integral type.
571 */
573 return (int) _lower;
574 }
575
576 /**
577 * Casts the `uint128_t` value to an integral type.
578 *
579 * This method allows for the explicit conversion of a `uint128_t` value to a specified integral type.
580 *
581 * @return The `uint128_t` value cast to the specified integral type.
582 */
583 IPADDRESS_NODISCARD IPADDRESS_CONSTEXPR IPADDRESS_FORCE_INLINE explicit operator unsigned short() const IPADDRESS_NOEXCEPT {
584 return (unsigned short) _lower;
585 }
586
587 /**
588 * Casts the `uint128_t` value to an integral type.
589 *
590 * This method allows for the explicit conversion of a `uint128_t` value to a specified integral type.
591 *
592 * @return The `uint128_t` value cast to the specified integral type.
593 */
594 IPADDRESS_NODISCARD IPADDRESS_CONSTEXPR IPADDRESS_FORCE_INLINE explicit operator short() const IPADDRESS_NOEXCEPT {
595 return (short) _lower;
596 }
597
598 /**
599 * Casts the `uint128_t` value to an integral type.
600 *
601 * This method allows for the explicit conversion of a `uint128_t` value to a specified integral type.
602 *
603 * @return The `uint128_t` value cast to the specified integral type.
604 */
605 IPADDRESS_NODISCARD IPADDRESS_CONSTEXPR IPADDRESS_FORCE_INLINE explicit operator unsigned char() const IPADDRESS_NOEXCEPT {
606 return (char) _lower;
607 }
608
609 /**
610 * Casts the `uint128_t` value to an integral type.
611 *
612 * This method allows for the explicit conversion of a `uint128_t` value to a specified integral type.
613 *
614 * @return The `uint128_t` value cast to the specified integral type.
615 */
616 IPADDRESS_NODISCARD IPADDRESS_CONSTEXPR IPADDRESS_FORCE_INLINE explicit operator char() const IPADDRESS_NOEXCEPT {
617 return (char) _lower;
618 }
619
620 /**
621 * Casts the `uint128_t` value to an integral type.
622 *
623 * This method allows for the explicit conversion of a `uint128_t` value to a specified integral type.
624 *
625 * @return The `uint128_t` value cast to the specified integral type.
626 */
627 IPADDRESS_NODISCARD IPADDRESS_CONSTEXPR IPADDRESS_FORCE_INLINE explicit operator signed char() const IPADDRESS_NOEXCEPT {
628 return (signed char) _lower;
629 }
630
631 /**
632 * Casts the `uint128_t` value to a floating-point type.
633 *
634 * This method allows for the explicit conversion of a `uint128_t` value to a specified floating-point type.
635 *
636 * @return The `uint128_t` value cast to the specified floating-point type.
637 */
639 return (long double) to_double(*this);
640 }
641
642 /**
643 * Casts the `uint128_t` value to a floating-point type.
644 *
645 * This method allows for the explicit conversion of a `uint128_t` value to a specified floating-point type.
646 *
647 * @return The `uint128_t` value cast to the specified floating-point type.
648 */
650 return to_double(*this);
651 }
652
653 /**
654 * Casts the `uint128_t` value to a floating-point type.
655 *
656 * This method allows for the explicit conversion of a `uint128_t` value to a specified floating-point type.
657 *
658 * @return The `uint128_t` value cast to the specified floating-point type.
659 */
661 return (float) to_double(*this);
662 }
663
664 /**
665 * Addition assignment operator.
666 *
667 * Adds the value of another `uint128_t` instance to this instance and assigns the result to this instance.
668 *
669 * @param[in] other The `uint128_t` instance to add.
670 * @return A reference to this instance after addition.
671 */
673 *this = *this + other;
674 return *this;
675 }
676
677 /**
678 * Subtraction assignment operator.
679 *
680 * Subtracts the value of another `uint128_t` instance from this instance and assigns the result to this instance.
681 *
682 * @param[in] other The `uint128_t` instance to subtract.
683 * @return A reference to this instance after subtraction.
684 */
686 *this = *this - other;
687 return *this;
688 }
689
690 /**
691 * Multiplication assignment operator.
692 *
693 * Multiplies this instance by another `uint128_t` instance and assigns the result to this instance.
694 *
695 * @param[in] other The `uint128_t` instance to multiply by.
696 * @return A reference to this instance after multiplication.
697 */
699 *this = *this * other;
700 return *this;
701 }
702
703 /**
704 * Division assignment operator.
705 *
706 * Divides this instance by another `uint128_t` instance and assigns the result to this instance.
707 *
708 * @param[in] other The `uint128_t` instance to divide by.
709 * @return A reference to this instance after division.
710 */
712 *this = *this / other;
713 return *this;
714 }
715
716 /**
717 * Remainder assignment operator.
718 *
719 * Calculates the remainder of this instance divided by another `uint128_t` instance and assigns the result to this instance.
720 *
721 * @param[in] other The `uint128_t` instance to divide by.
722 * @return A reference to this instance after calculating the remainder.
723 */
725 *this = *this % other;
726 return *this;
727 }
728
729 /**
730 * Bitwise AND assignment operator.
731 *
732 * Performs a bitwise AND operation between this instance and another `uint128_t` instance and assigns the result to this instance.
733 *
734 * @param[in] other The `uint128_t` instance to perform the bitwise AND with.
735 * @return A reference to this instance after the bitwise AND operation.
736 */
738 _upper &= other._upper;
739 _lower &= other._lower;
740 return *this;
741 }
742
743 /**
744 * Bitwise OR assignment operator.
745 *
746 * Performs a bitwise OR operation between this instance and another `uint128_t` instance and assigns the result to this instance.
747 *
748 * @param[in] other The `uint128_t` instance to perform the bitwise OR with.
749 * @return A reference to this instance after the bitwise OR operation.
750 */
752 _upper |= other._upper;
753 _lower |= other._lower;
754 return *this;
755 }
756
757 /**
758 * Bitwise XOR assignment operator.
759 *
760 * Performs a bitwise XOR operation between this instance and another `uint128_t` instance and assigns the result to this instance.
761 *
762 * @param[in] other The `uint128_t` instance to perform the bitwise XOR with.
763 * @return A reference to this instance after the bitwise XOR operation.
764 */
766 _upper ^= other._upper;
767 _lower ^= other._lower;
768 return *this;
769 }
770
771 /**
772 * Bitwise left shift assignment operator.
773 *
774 * Shifts the bits of this instance to the left by the specified number of places and assigns the result to this instance.
775 *
776 * @tparam T An integral type representing the number of places to shift.
777 * @param[in] shift The number of bits to shift to the left.
778 * @return A reference to this instance after the shift operation.
779 */
780 template <typename T, typename = typename std::enable_if<std::is_integral<T>::value, T>::type>
781 IPADDRESS_CONSTEXPR IPADDRESS_FORCE_INLINE uint128_t& operator<<=(T shift) IPADDRESS_NOEXCEPT {
782 *this = *this << shift;
783 return *this;
784 }
785
786 /**
787 * Bitwise right shift assignment operator.
788 *
789 * Shifts the bits of this instance to the right by the specified number of places and assigns the result to this instance.
790 *
791 * @tparam T An integral type representing the number of places to shift.
792 * @param[in] shift The number of bits to shift to the right.
793 * @return A reference to this instance after the shift operation.
794 */
795 template <typename T, typename = typename std::enable_if<std::is_integral<T>::value, T>::type>
797 *this = *this >> shift;
798 return *this;
799 }
800
801 /**
802 * Unary plus operator.
803 *
804 * Returns a new instance of `uint128_t` with the same value as this instance.
805 *
806 * @return A new `uint128_t` instance with the same value.
807 */
809 return *this;
810 }
811
812 /**
813 * Unary minus operator.
814 *
815 * Returns a new instance of `uint128_t` representing the two's complement of this instance.
816 *
817 * @return A new `uint128_t` instance representing the negated value.
818 */
820 return ++(~*this);
821 }
822
823 /**
824 * Bitwise NOT operator.
825 *
826 * Returns a new instance of `uint128_t` with all the bits of this instance inverted.
827 *
828 * @return A new `uint128_t` instance with inverted bits.
829 */
831 return { ~_upper, ~_lower };
832 }
833
834 /**
835 * Addition operator with another `uint128_t` instance.
836 *
837 * Adds the value of another `uint128_t` instance to this instance and returns a new `uint128_t` instance with the result.
838 *
839 * @param[in] other The `uint128_t` instance to add.
840 * @return A new `uint128_t` instance representing the sum.
841 */
843 const uint64_t lower = _lower + other._lower;
844 const uint64_t carry = lower < _lower ? 1 : 0;
845 return { _upper + other._upper + carry, lower };
846 }
847
848 /**
849 * Subtraction operator with another `uint128_t` instance.
850 *
851 * Subtracts the value of another `uint128_t` instance from this instance and returns a new `uint128_t` instance with the result.
852 *
853 * @param[in] other The `uint128_t` instance to subtract.
854 * @return A new `uint128_t` instance representing the difference.
855 */
857 const uint64_t lower = _lower - other._lower;
858 const uint64_t borrow = lower > _lower ? 1 : 0;
859 return { _upper - other._upper - borrow, lower };
860 }
861
862 /**
863 * Multiplication operator with another `uint128_t` instance.
864 *
865 * Multiplies this instance by another `uint128_t` instance and returns a new `uint128_t` instance with the result.
866 *
867 * @param[in] other The `uint128_t` instance to multiply by.
868 * @return A new `uint128_t` instance representing the product.
869 */
871 uint64_t lower = 0;
872 uint64_t upper = big_mul(_lower, other._lower, lower);
873 upper += (_upper * other._lower) + (_lower * other._upper);
874 return { upper, lower };
875 }
876
877 /**
878 * Division operator with another `uint128_t` instance.
879 *
880 * Divides this instance by another `uint128_t` instance and returns a new `uint128_t` instance with the result.
881 *
882 * @param[in] other The `uint128_t` instance to divide by.
883 * @return A new `uint128_t` instance representing the quotient.
884 */
886 return divide(*this, other);
887 }
888
889 /**
890 * Remainder operator with another `uint128_t` instance.
891 *
892 * Calculates the remainder of this instance divided by another `uint128_t` instance and returns a new `uint128_t` instance with the result.
893 *
894 * @param[in] other The `uint128_t` instance to divide by.
895 * @return A new `uint128_t` instance representing the remainder.
896 */
898 const auto quotient = divide(*this, other);
899 return *this - quotient * other;
900 }
901
902 /**
903 * Bitwise AND operator with another `uint128_t` instance.
904 *
905 * Performs a bitwise AND operation between this instance and another `uint128_t` instance and returns a new `uint128_t` instance with the result.
906 *
907 * @param[in] other The `uint128_t` instance to perform the bitwise AND with.
908 * @return A new `uint128_t` instance representing the result of the bitwise AND operation.
909 */
911 return { _upper & other._upper, _lower & other._lower };
912 }
913
914 /**
915 * Bitwise OR operator with another `uint128_t` instance.
916 *
917 * Performs a bitwise OR operation between this instance and another `uint128_t` instance and returns a new `uint128_t` instance with the result.
918 *
919 * @param[in] other The `uint128_t` instance to perform the bitwise OR with.
920 * @return A new `uint128_t` instance representing the result of the bitwise OR operation.
921 */
923 return { _upper | other._upper, _lower | other._lower };
924 }
925
926 /**
927 * Bitwise XOR operator with another `uint128_t` instance.
928 *
929 * Performs a bitwise XOR operation between this instance and another `uint128_t` instance and returns a new `uint128_t` instance with the result.
930 *
931 * @param[in] other The `uint128_t` instance to perform the bitwise XOR with.
932 * @return A new `uint128_t` instance representing the result of the bitwise XOR operation.
933 */
935 return { _upper ^ other._upper, _lower ^ other._lower };
936 }
937
938 /**
939 * Bitwise left shift operator with an integral type.
940 *
941 * Shifts the bits of this instance to the left by the specified number of places and returns a new `uint128_t` instance with the result.
942 *
943 * @tparam T An integral type representing the number of places to shift.
944 * @param[in] shift The number of bits to shift to the left.
945 * @return A new `uint128_t` instance representing the result of the left shift operation.
946 */
947 template <typename T, typename = typename std::enable_if<std::is_integral<T>::value, T>::type>
948 IPADDRESS_NODISCARD IPADDRESS_CONSTEXPR IPADDRESS_FORCE_INLINE uint128_t operator<<(T shift) const IPADDRESS_NOEXCEPT {
949 if (!shift) {
950 return *this;
951 }
952 if (shift >= 64 && shift <= 128) {
953 return { _lower << (shift - 64), 0 };
954 }
955 if (shift < 64 && shift > 0) {
956 return { (_upper << shift) + (_lower >> (64 - shift)), _lower << shift };
957 }
958 return { 0, 0 };
959 }
960
961 /**
962 * Bitwise right shift operator with an integral type.
963 *
964 * Shifts the bits of this instance to the right by the specified number of places and returns a new `uint128_t` instance with the result.
965 *
966 * @tparam T An integral type representing the number of places to shift.
967 * @param[in] shift The number of bits to shift to the right.
968 * @return A new `uint128_t` instance representing the result of the right shift operation.
969 */
970 template <typename T, typename = typename std::enable_if<std::is_integral<T>::value, T>::type>
972 if (!shift) {
973 return *this;
974 }
975 if (shift >= 64 && shift <= 128) {
976 return { 0, _upper >> (shift - 64) };
977 }
978 if (shift < 64 && shift > 0) {
979 return { _upper >> shift, (_lower >> shift) + (_upper << (64 - shift)) };
980 }
981 return { 0, 0 };
982 }
983
984 /**
985 * Pre-increment operator.
986 *
987 * Increments this instance by one and returns a reference to this instance.
988 *
989 * @return A reference to this instance after the increment.
990 */
992 *this += 1;
993 return *this;
994 }
995
996 /**
997 * Pre-decrement operator.
998 *
999 * Decrements this instance by one and returns a reference to this instance.
1000 *
1001 * @return A reference to this instance after the decrement.
1002 */
1004 *this -= 1;
1005 return *this;
1006 }
1007
1008 /**
1009 * Post-increment operator.
1010 *
1011 * Increments this instance by one and returns the value of the instance before the increment.
1012 *
1013 * @return The value of this instance before the increment.
1014 */
1016 auto tmp = *this;
1017 ++*this;
1018 return tmp;
1019 }
1020
1021 /**
1022 * Post-decrement operator.
1023 *
1024 * Decrements this instance by one and returns the value of the instance before the decrement.
1025 *
1026 * @return The value of this instance before the decrement.
1027 */
1029 auto tmp = *this;
1030 --*this;
1031 return tmp;
1032 }
1033
1034 /**
1035 * Logical NOT operator.
1036 *
1037 * Returns `true` if this instance is zero, otherwise returns `false`.
1038 *
1039 * @return `true` if this instance is zero, `false` otherwise.
1040 */
1042 return !_upper && !_lower;
1043 }
1044
1045 /**
1046 * Logical AND operator.
1047 *
1048 * Returns `true` if both this instance and another `uint128_t` instance are non-zero, otherwise returns `false`.
1049 *
1050 * @param[in] other The `uint128_t` instance to compare with.
1051 * @return `true` if both instances are non-zero, `false` otherwise.
1052 */
1053 IPADDRESS_NODISCARD IPADDRESS_CONSTEXPR IPADDRESS_FORCE_INLINE bool operator&&(const uint128_t& other) const IPADDRESS_NOEXCEPT {
1054 return (_upper || _lower) && (other._upper || other._lower);
1055 }
1056
1057 /**
1058 * Logical OR operator.
1059 *
1060 * Returns `true` if either this instance or another `uint128_t` instance is non-zero, otherwise returns `false`.
1061 *
1062 * @param[in] other The `uint128_t` instance to compare with.
1063 * @return `true` if either instance is non-zero, `false` otherwise.
1064 */
1065 IPADDRESS_NODISCARD IPADDRESS_CONSTEXPR IPADDRESS_FORCE_INLINE bool operator||(const uint128_t& other) const IPADDRESS_NOEXCEPT {
1066 return (_upper || _lower) || (other._upper || other._lower);
1067 }
1068
1069 /**
1070 * Equality operator with an integral type.
1071 *
1072 * Compares this instance to an integral value for equality.
1073 *
1074 * @tparam T An integral type to compare with.
1075 * @param[in] lower The integral value to compare with.
1076 * @return `true` if this instance is equal to the integral value, `false` otherwise.
1077 */
1078 template <typename T, typename = typename std::enable_if<std::is_integral<T>::value, T>::type>
1079 IPADDRESS_NODISCARD IPADDRESS_CONSTEXPR IPADDRESS_FORCE_INLINE bool operator==(T lower) const IPADDRESS_NOEXCEPT {
1080 return *this == uint128_t(lower);
1081 }
1082
1083 /**
1084 * Equality operator with another `uint128_t` instance.
1085 *
1086 * Compares this instance to another `uint128_t` instance for equality.
1087 *
1088 * @param[in] other The `uint128_t` instance to compare with.
1089 * @return `true` if this instance is equal to the other instance, `false` otherwise.
1090 */
1091 IPADDRESS_NODISCARD IPADDRESS_CONSTEXPR IPADDRESS_FORCE_INLINE bool operator==(const uint128_t& other) const IPADDRESS_NOEXCEPT {
1092 return _upper == other._upper && _lower == other._lower;
1093 }
1094
1095 /**
1096 * Inequality operator with an integral type.
1097 *
1098 * Compares this instance to an integral value for inequality.
1099 *
1100 * @tparam T An integral type to compare with.
1101 * @param[in] lower The integral value to compare with.
1102 * @return `true` if this instance is not equal to the integral value, `false` otherwise.
1103 */
1104 template <typename T, typename = typename std::enable_if<std::is_integral<T>::value, T>::type>
1105 IPADDRESS_NODISCARD IPADDRESS_CONSTEXPR IPADDRESS_FORCE_INLINE bool operator!=(T lower) const IPADDRESS_NOEXCEPT {
1106 return *this != uint128_t(lower);
1107 }
1108
1109 /**
1110 * Inequality operator with another `uint128_t` instance.
1111 *
1112 * Compares this instance to another `uint128_t` instance for inequality.
1113 *
1114 * @param[in] other The `uint128_t` instance to compare with.
1115 * @return `true` if this instance is not equal to the other instance, `false` otherwise.
1116 */
1117 IPADDRESS_NODISCARD IPADDRESS_CONSTEXPR IPADDRESS_FORCE_INLINE bool operator!=(const uint128_t& other) const IPADDRESS_NOEXCEPT {
1118 return !(*this == other);
1119 }
1120
1121#ifdef IPADDRESS_HAS_SPACESHIP_OPERATOR
1122
1123 /**
1124 * Three-way comparison operator with an integral type.
1125 *
1126 * Compares this instance to an integral value to determine the ordering relationship.
1127 *
1128 * @tparam T An integral type to compare with.
1129 * @param[in] lower The integral value to compare with.
1130 * @return An `std::strong_ordering` value indicating the ordering relationship.
1131 */
1132 template <typename T, typename = typename std::enable_if<std::is_integral<T>::value, T>::type>
1134 return *this <=> uint128_t(lower);
1135 }
1136
1137 /**
1138 * Three-way comparison operator with another `uint128_t` instance.
1139 *
1140 * Compares this instance to another `uint128_t` instance to determine the ordering relationship.
1141 *
1142 * @param[in] other The `uint128_t` instance to compare with.
1143 * @return An `std::strong_ordering` value indicating the ordering relationship.
1144 */
1146 if (const auto result = _upper <=> other._upper; result == std::strong_ordering::equivalent) {
1147 return _lower <=> other._lower;
1148 } else {
1149 return result;
1150 }
1151 }
1152
1153#else // !IPADDRESS_HAS_SPACESHIP_OPERATOR
1154
1155 /**
1156 * Less than operator with an integral type.
1157 *
1158 * Checks if the value of this instance is lexicographically less than the provided integral value.
1159 *
1160 * @tparam T An integral type to compare with.
1161 * @param[in] lower The integral value to compare with.
1162 * @return `true` if this instance is less than the integral value, `false` otherwise.
1163 */
1164 template <typename T, typename = typename std::enable_if<std::is_integral<T>::value, T>::type>
1166 return *this < uint128_t(lower);
1167 }
1168
1169 /**
1170 * Less than operator with another `uint128_t` instance.
1171 *
1172 * Checks if the value of this instance is lexicographically less than the provided `uint128_t` instance.
1173 *
1174 * @param[in] other The `uint128_t` instance to compare with.
1175 * @return `true` if this instance is less than the other instance, `false` otherwise.
1176 */
1178 return _upper < other._upper || (_upper == other._upper && _lower < other._lower);
1179 }
1180
1181 /**
1182 * Greater than operator with an integral type.
1183 *
1184 * Checks if the value of this instance is lexicographically greater than the provided integral value.
1185 *
1186 * @tparam T An integral type to compare with.
1187 * @param[in] lower The integral value to compare with.
1188 * @return `true` if this instance is greater than the integral value, `false` otherwise.
1189 */
1190 template <typename T, typename = typename std::enable_if<std::is_integral<T>::value, T>::type>
1192 return *this > uint128_t(lower);
1193 }
1194
1195 /**
1196 * Greater than operator with another `uint128_t` instance.
1197 *
1198 * Checks if the value of this instance is lexicographically greater than the provided `uint128_t` instance.
1199 *
1200 * @param[in] other The `uint128_t` instance to compare with.
1201 * @return `true` if this instance is greater than the other instance, `false` otherwise.
1202 */
1204 return other < *this;
1205 }
1206
1207 /**
1208 * Less than or equal to operator with an integral type.
1209 *
1210 * Checks if the value of this instance is lexicographically less than or equal to the provided integral value.
1211 *
1212 * @tparam T An integral type to compare with.
1213 * @param[in] lower The integral value to compare with.
1214 * @return `true` if this instance is less than or equal to the integral value, `false` otherwise.
1215 */
1216 template <typename T, typename = typename std::enable_if<std::is_integral<T>::value, T>::type>
1217 IPADDRESS_NODISCARD IPADDRESS_CONSTEXPR IPADDRESS_FORCE_INLINE bool operator<=(T lower) const IPADDRESS_NOEXCEPT {
1218 return *this <= uint128_t(lower);
1219 }
1220
1221 /**
1222 * Less than or equal to operator with another `uint128_t` instance.
1223 *
1224 * Checks if the value of this instance is lexicographically less than or equal to the provided `uint128_t` instance.
1225 *
1226 * @param[in] other The `uint128_t` instance to compare with.
1227 * @return `true` if this instance is less than or equal to the other instance, `false` otherwise.
1228 */
1229 IPADDRESS_NODISCARD IPADDRESS_CONSTEXPR IPADDRESS_FORCE_INLINE bool operator<=(const uint128_t& other) const IPADDRESS_NOEXCEPT {
1230 return !(other < *this);
1231 }
1232
1233 /**
1234 * Greater than or equal to operator with an integral type.
1235 *
1236 * Checks if the value of this instance is lexicographically greater than or equal to the provided integral value.
1237 *
1238 * @tparam T An integral type to compare with.
1239 * @param[in] lower The integral value to compare with.
1240 * @return `true` if this instance is greater than or equal to the integral value, `false` otherwise.
1241 */
1242 template <typename T, typename = typename std::enable_if<std::is_integral<T>::value, T>::type>
1243 IPADDRESS_NODISCARD IPADDRESS_CONSTEXPR IPADDRESS_FORCE_INLINE bool operator>=(T lower) const IPADDRESS_NOEXCEPT {
1244 return *this >= uint128_t(lower);
1245 }
1246
1247 /**
1248 * Greater than or equal to operator with another `uint128_t` instance.
1249 *
1250 * Checks if the value of this instance is lexicographically greater than or equal to the provided `uint128_t` instance.
1251 *
1252 * @param[in] other The `uint128_t` instance to compare with.
1253 * @return `true` if this instance is greater than or equal to the other instance, `false` otherwise.
1254 */
1255 IPADDRESS_NODISCARD IPADDRESS_CONSTEXPR IPADDRESS_FORCE_INLINE bool operator>=(const uint128_t& other) const IPADDRESS_NOEXCEPT {
1256 return !(*this < other);
1257 }
1258
1259#endif // !IPADDRESS_HAS_SPACESHIP_OPERATOR
1260
1261private:
1262 IPADDRESS_NODISCARD static IPADDRESS_CONSTEXPR IPADDRESS_FORCE_INLINE uint64_t big_mul(uint64_t a, uint64_t b, uint64_t& lower) IPADDRESS_NOEXCEPT {
1263 auto al = uint32_t(a);
1264 auto ah = uint32_t(a >> 32);
1265 auto bl = uint32_t(b);
1266 auto bh = uint32_t(b >> 32);
1267
1268 uint64_t mull = uint64_t(al) * bl;
1269 uint64_t t = uint64_t(ah) * bl + (mull >> 32);
1270 uint64_t tl = uint64_t(al) * bh + uint32_t(t);
1271
1272 lower = tl << 32 | uint32_t(mull);
1273
1274 return uint64_t(ah) * bh + (t >> 32) + (tl >> 32);
1275 }
1276
1277 IPADDRESS_NODISCARD static IPADDRESS_CONSTEXPR IPADDRESS_FORCE_INLINE uint128_t divide(const uint128_t& lhs, const uint128_t& rhs) IPADDRESS_NOEXCEPT {
1278 if (rhs._upper == 0) {
1279 if (rhs._lower == 0) {
1280 return {};
1281 }
1282
1283 if (lhs._upper == 0) {
1284 return lhs._lower / rhs._lower;
1285 }
1286 }
1287
1288 if (rhs >= lhs) {
1289 return rhs == lhs ? 1 : 0;
1290 }
1291
1292 return divide_slow(lhs, rhs);
1293 }
1294
1295 IPADDRESS_NODISCARD static IPADDRESS_CONSTEXPR IPADDRESS_FORCE_INLINE uint128_t divide_slow(const uint128_t& quotient, const uint128_t& divisor) IPADDRESS_NOEXCEPT {
1296 uint32_t left[4] {
1297 uint32_t(quotient._lower),
1298 uint32_t(quotient._lower >> 32),
1299 uint32_t(quotient._upper),
1300 uint32_t(quotient._upper >> 32)
1301 };
1302 int32_t left_size = 4 - int32_t(leading_zero_count(quotient)) / 32;
1303
1304 uint32_t right[4] {
1305 uint32_t(divisor._lower),
1306 uint32_t(divisor._lower >> 32),
1307 uint32_t(divisor._upper),
1308 uint32_t(divisor._upper >> 32)
1309 };
1310 int32_t right_size = 4 - int32_t(leading_zero_count(divisor)) / 32;
1311
1312 uint32_t bits[4]{};
1313 int32_t bits_size = left_size - right_size + 1;
1314
1315 assert(left_size >= 1);
1316 assert(right_size >= 1);
1317 assert(left_size >= right_size);
1318
1319 uint32_t div_hi = right[right_size - 1];
1320 uint32_t div_lo = right_size > 1 ? right[right_size - 2] : 0;
1321
1322 uint32_t shift = leading_zero_count(div_hi);
1323 uint32_t back_shift = 32 - shift;
1324
1325 if (shift > 0) {
1326 uint32_t div_nx = right_size > 2 ? right[right_size - 3] : 0;
1327 div_hi = (div_hi << shift) | (div_lo >> back_shift);
1328 div_lo = (div_lo << shift) | (div_nx >> back_shift);
1329 }
1330
1331 for (int32_t i = left_size; i >= right_size; --i) {
1332 int32_t n = i - right_size;
1333 uint32_t t = uint32_t(i) < uint32_t(left_size) ? left[i] : 0;
1334
1335 uint64_t val_hi = (uint64_t(t) << 32) | left[i - 1];
1336 uint32_t val_lo = (i > 1) ? left[i - 2] : 0; // NOLINT(clang-analyzer-core.uninitialized.Assign)
1337
1338 if (shift > 0) {
1339 uint32_t val_nx = i > 2 ? left[i - 3] : 0;
1340 val_hi = (val_hi << shift) | (val_lo >> back_shift);
1341 val_lo = (val_lo << shift) | (val_nx >> back_shift);
1342 }
1343
1344 uint64_t digit = val_hi / div_hi;
1345
1346 if (digit > 0xFFFFFFFF) {
1347 digit = 0xFFFFFFFF;
1348 }
1349
1350 while (divide_guess_too_big(digit, val_hi, val_lo, div_hi, div_lo)) {
1351 --digit;
1352 }
1353
1354 if (digit > 0) {
1355 uint32_t carry = subtract_divisor(left + n, left_size - n, right, right_size, digit);
1356
1357 if (carry != t) {
1358 assert(carry == t + 1);
1359
1360 // NOLINTNEXTLINE(clang-analyzer-deadcode.DeadStores): carry is not used in the release build
1361 carry = add_divisor(left + n, left_size - n, right, right_size);
1362
1363 --digit;
1364 assert(carry == 1);
1365 }
1366 }
1367
1368 if (uint32_t(n) < uint32_t(bits_size)) {
1369 bits[n] = uint32_t(digit);
1370 }
1371
1372 if (uint32_t(i) < uint32_t(left_size)) {
1373 left[i] = 0;
1374 }
1375 }
1376
1377 return { uint64_t(bits[3]) << 32 | bits[2], uint64_t(bits[1]) << 32 | bits[0] };
1378 }
1379
1380 IPADDRESS_NODISCARD static IPADDRESS_CONSTEXPR IPADDRESS_FORCE_INLINE bool divide_guess_too_big(uint64_t q, uint64_t val_hi, uint32_t val_lo, uint32_t div_hi, uint32_t div_lo) IPADDRESS_NOEXCEPT {
1381 assert(q <= 0xFFFFFFFF);
1382
1383 uint64_t chk_hi = div_hi * q;
1384 uint64_t chk_lo = div_lo * q;
1385
1386 chk_hi += chk_lo >> 32;
1387 chk_lo = uint32_t(chk_lo);
1388
1389 return (chk_hi > val_hi) || (chk_hi == val_hi && chk_lo > val_lo);
1390 }
1391
1392 IPADDRESS_NODISCARD static IPADDRESS_CONSTEXPR IPADDRESS_FORCE_INLINE uint32_t subtract_divisor(uint32_t* left, int32_t ls /* NOLINT(misc-unused-parameters) */, const uint32_t (&right)[4], int32_t rs, uint64_t q) IPADDRESS_NOEXCEPT {
1393 assert(ls >= rs);
1394 assert(q <= 0xFFFFFFFF);
1395
1396 uint64_t carry = 0;
1397
1398 for (int32_t i = 0; i < rs; ++i) {
1399 carry += right[i] * q;
1400
1401 auto digit = uint32_t(carry);
1402 carry >>= 32;
1403
1404 if (left[i] < digit) {
1405 ++carry;
1406 }
1407 left[i] -= digit;
1408 }
1409
1410 return uint32_t(carry);
1411 }
1412
1413 IPADDRESS_NODISCARD static IPADDRESS_CONSTEXPR IPADDRESS_FORCE_INLINE uint32_t add_divisor(uint32_t* left, int32_t ls /* NOLINT(misc-unused-parameters) */, const uint32_t (&right)[4], int32_t rs) IPADDRESS_NOEXCEPT {
1414 assert(ls >= rs);
1415
1416 uint64_t carry = 0;
1417
1418 for (int32_t i = 0; i < rs; ++i) {
1419 uint64_t digit = left[i] + carry + right[i];
1420 left[i] = uint32_t(digit);
1421 carry = digit >> 32;
1422 }
1423
1424 return uint32_t(carry);
1425 }
1426
1428 constexpr double two_pow_128 = 340282366920938463463374607431768211456.0;
1429
1430 if (value < 0 || std::isnan(value)) {
1431 return uint128_t(0, 0);
1432 }
1433
1434 if (value >= two_pow_128) {
1435 return uint128_t(0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF);
1436 }
1437
1438 if (value >= 1.0) {
1439 uint64_t bits = double_to_uint64_bits(value);
1440 uint128_t result((bits << 12) >> 1 | 0x8000000000000000, 0x0000000000000000);
1441 result >>= (1023 + 128 - 1 - int32_t(bits >> 52));
1442 return result;
1443 }
1444
1445 return uint128_t(0, 0);
1446 }
1447
1449 constexpr double two_pow_52 = 4503599627370496.0;
1450 constexpr double two_pow_76 = 75557863725914323419136.0;
1451 constexpr double two_pow_104 = 20282409603651670423947251286016.0;
1452 constexpr double two_pow_128 = 340282366920938463463374607431768211456.0;
1453
1454 constexpr uint64_t two_pow_52_bits = 0x4330000000000000;
1455 constexpr uint64_t two_pow_76_bits = 0x44B0000000000000;
1456 constexpr uint64_t two_pow_104_bits = 0x4670000000000000;
1457 constexpr uint64_t two_pow_128_bits = 0x47F0000000000000;
1458
1459 if (value._upper == 0) {
1460 return double(value._lower);
1461 }
1462
1463 if ((value._upper >> 24) == 0) {
1464 double lower = uint64_bits_to_double(two_pow_52_bits | ((value._lower << 12) >> 12)) - two_pow_52;
1465 double upper = uint64_bits_to_double(two_pow_104_bits | (uint64_t)(value >> 52)) - two_pow_104;
1466 return double(lower + upper);
1467 }
1468
1469 double lower = uint64_bits_to_double(two_pow_76_bits | ((uint64_t)(value >> 12) >> 12) | (value._lower & 0xFFFFFF)) - two_pow_76;
1470 double upper = uint64_bits_to_double(two_pow_128_bits | (uint64_t)(value >> 76)) - two_pow_128;
1471 return double(lower + upper);
1472 }
1473
1474 IPADDRESS_NODISCARD static IPADDRESS_FORCE_INLINE double uint64_bits_to_double(uint64_t bits) IPADDRESS_NOEXCEPT {
1475 double result; // NOLINT(cppcoreguidelines-init-variables)
1476 std::memcpy(&result, &bits, sizeof(double));
1477 return result;
1478 }
1479
1480 IPADDRESS_NODISCARD static IPADDRESS_FORCE_INLINE uint64_t double_to_uint64_bits(double value) IPADDRESS_NOEXCEPT {
1481 uint64_t result; // NOLINT(cppcoreguidelines-init-variables)
1482 std::memcpy(&result, &value, sizeof(uint64_t));
1483 return result;
1484 }
1485
1486 IPADDRESS_NODISCARD static IPADDRESS_CONSTEXPR IPADDRESS_FORCE_INLINE uint32_t leading_zero_count(const uint128_t& value) IPADDRESS_NOEXCEPT {
1487 if (value._upper != 0) {
1488 for (uint32_t i = 0; i < 64; ++i) {
1489 if (value._upper & (1ULL << (63 - i))) {
1490 return i;
1491 }
1492 }
1493 }
1494 if (value._lower != 0) {
1495 for (uint32_t i = 0; i < 64; ++i) {
1496 if (value._lower & (1ULL << (63 - i))) {
1497 return 64 + i;
1498 }
1499 }
1500 }
1501 return 128;
1502 }
1503
1504 IPADDRESS_NODISCARD static IPADDRESS_CONSTEXPR IPADDRESS_FORCE_INLINE uint32_t leading_zero_count(uint32_t value) IPADDRESS_NOEXCEPT {
1505 int32_t shift = 32;
1506 if (value != 0) {
1507 for (shift = 0; shift < 32; ++shift) {
1508 if (value & (1ULL << (31 - shift))) {
1509 break;
1510 }
1511 }
1512 }
1513 return shift;
1514 }
1515
1516 IPADDRESS_NODISCARD static IPADDRESS_FORCE_INLINE std::string uint128_to_dec_str(uint128_t value) {
1517 std::ostringstream ss;
1518
1519 do {
1520 const auto q = value / 10;
1521 const auto r = value - q * 10;
1522
1523 ss << r._lower;
1524
1525 value = q;
1526 } while (value);
1527
1528 auto result = ss.str();
1529 std::reverse(result.begin(), result.end());
1530 return result;
1531 }
1532
1533 IPADDRESS_NODISCARD static IPADDRESS_FORCE_INLINE std::string uint128_to_oct_str(uint128_t value) {
1534 std::ostringstream ss;
1535
1536 do {
1537 const auto q = value / 8;
1538 const auto r = value - q * 8;
1539
1540 ss << r._lower;
1541
1542 value = q;
1543 } while (value);
1544
1545 auto result = ss.str();
1546 std::reverse(result.begin(), result.end());
1547 return result;
1548 }
1549
1550 IPADDRESS_NODISCARD static IPADDRESS_FORCE_INLINE std::string uint128_to_hex_str(uint128_t value) {
1551 constexpr char digits[] = "0123456789abcdef";
1552
1553 std::ostringstream ss;
1554 do {
1555 const auto q = value / 16;
1556 const auto r = value - q * 16;
1557
1558 ss << digits[r._lower];
1559
1560 value = q;
1561 } while (value);
1562
1563 auto result = ss.str();
1564 std::reverse(result.begin(), result.end());
1565 return result;
1566 }
1567
1568#pragma warning(push, 3)
1569#ifdef __clang__
1570 _Pragma("clang diagnostic push")
1571 _Pragma("clang diagnostic ignored \"-Wundefined-inline\"")
1572#endif
1573 template <typename T>
1574 IPADDRESS_NODISCARD static IPADDRESS_CONSTEXPR IPADDRESS_FORCE_INLINE optional<uint128_t> str_to_uint128(const T* begin, const T* end, format fmt) IPADDRESS_NOEXCEPT {
1575 switch (fmt) {
1576 case format::octal:
1577 return oct_str_to_uint128(begin, end);
1579 return hex_str_to_uint128(begin, end);
1580 default:
1581 return dec_str_to_uint128(begin, end);
1582 }
1583 }
1584#ifdef __clang__
1585 _Pragma("clang diagnostic pop")
1586#endif
1587#pragma warning(pop)
1588
1589 template <typename T>
1590 IPADDRESS_NODISCARD static IPADDRESS_CONSTEXPR IPADDRESS_FORCE_INLINE optional<uint128_t> dec_str_to_uint128(const T* begin, const T* end) IPADDRESS_NOEXCEPT {
1591 error_code code = error_code::no_error;
1592 uint32_t error_symbol = 0;
1593 uint128_t result = 0;
1594 const T* it = begin;
1595 while (it < end) {
1596 const auto c = internal::next_char_or_error(it, end, code, error_symbol);
1597 if (code != error_code::no_error) { // NOLINT(bugprone-branch-clone)
1598 return nullptr;
1599 } else if (c == '\0') {
1600 break;
1601 } else if (c < '0' || c > '9') {
1602 return nullptr;
1603 }
1604 result = result * 10 + (c - '0');
1605 }
1606 return result;
1607 }
1608
1609 template <typename T>
1610 IPADDRESS_NODISCARD static IPADDRESS_CONSTEXPR IPADDRESS_FORCE_INLINE optional<uint128_t> oct_str_to_uint128(const T* begin, const T* end) IPADDRESS_NOEXCEPT {
1611 error_code code = error_code::no_error;
1612 uint32_t error_symbol = 0;
1613 uint128_t result = 0;
1614 const T* it = begin;
1615 while (it < end) {
1616 const auto c = internal::next_char_or_error(it, end, code, error_symbol);
1617 if (code != error_code::no_error) { // NOLINT(bugprone-branch-clone)
1618 return nullptr;
1619 } else if (c == '\0') {
1620 break;
1621 } else if (c < '0' || c > '7') {
1622 return nullptr;
1623 }
1624 result = result * 8 + (c - '0');
1625 }
1626 return result;
1627 }
1628
1629 template <typename T>
1630 IPADDRESS_NODISCARD static IPADDRESS_CONSTEXPR IPADDRESS_FORCE_INLINE optional<uint128_t> hex_str_to_uint128(const T* begin, const T* end) IPADDRESS_NOEXCEPT {
1631 error_code code = error_code::no_error;
1632 uint32_t error_symbol = 0;
1633 uint128_t result = 0;
1634 int digit = 0;
1635 const T* it = begin;
1636 while (it < end) {
1637 const auto c = internal::next_char_or_error(it, end, code, error_symbol);
1638 if (code != error_code::no_error) { // NOLINT(bugprone-branch-clone)
1639 return nullptr;
1640 } else if (c == '\0') {
1641 break;
1642 } else if (c >= '0' && c <= '9') {
1643 digit = c - '0';
1644 } else if (c >= 'A' && c <= 'F') {
1645 digit = c - 55;
1646 } else if (c >= 'a' && c <= 'f') {
1647 digit = c - 87;
1648 } else {
1649 return nullptr;
1650 }
1651 result = result * 16 + digit;
1652 }
1653 return result;
1654 }
1655
1656#if IPADDRESS_ENDIAN == IPADDRESS_BIG_ENDIAN
1657
1658 uint64_t _upper{};
1659 uint64_t _lower{};
1660
1661#else // IPADDRESS_ENDIAN != IPADDRESS_BIG_ENDIAN
1662
1663 uint64_t _lower{};
1664 uint64_t _upper{};
1665
1666#endif // IPADDRESS_ENDIAN != IPADDRESS_BIG_ENDIAN
1667};
1668
1669/**
1670 * Performs addition between an integer and a uint128_t value.
1671 *
1672 * @tparam T Integer type.
1673 * @param[in] lower The integer value to be added.
1674 * @param[in] value The uint128_t value to be added.
1675 * @return uint128_t the result of the addition.
1676 */
1677IPADDRESS_EXPORT template <typename T, typename = typename std::enable_if<std::is_arithmetic<T>::value, T>::type>
1679 return uint128_t(lower) + value;
1680}
1681
1682/**
1683 * Performs subtraction of a uint128_t value from an integer.
1684 *
1685 * @tparam T Integer type.
1686 * @param[in] lower The integer value from which the uint128_t value is subtracted.
1687 * @param[in] value The uint128_t value to be subtracted.
1688 * @return uint128_t the result of the subtraction.
1689 */
1690IPADDRESS_EXPORT template <typename T, typename = typename std::enable_if<std::is_arithmetic<T>::value, T>::type>
1692 return uint128_t(lower) - value;
1693}
1694
1695/**
1696 * Performs multiplication between an integer and a uint128_t value.
1697 *
1698 * @tparam T Integer type.
1699 * @param[in] lower The integer value to be multiplied.
1700 * @param[in] value The uint128_t value to be multiplied.
1701 * @return uint128_t the result of the multiplication.
1702 */
1703IPADDRESS_EXPORT template <typename T, typename = typename std::enable_if<std::is_arithmetic<T>::value, T>::type>
1705 return uint128_t(lower) * value;
1706}
1707
1708/**
1709 * Performs division of an integer by a uint128_t value.
1710 *
1711 * @tparam T Integer type.
1712 * @param[in] lower The integer value to be divided.
1713 * @param[in] value The uint128_t value that divides the integer.
1714 * @return uint128_t the result of the division.
1715 */
1716IPADDRESS_EXPORT template <typename T, typename = typename std::enable_if<std::is_arithmetic<T>::value, T>::type>
1718 return uint128_t(lower) / value;
1719}
1720
1721/**
1722 * Calculates the remainder of division of an integer by a uint128_t value.
1723 *
1724 * @tparam T Integer type.
1725 * @param[in] lower The integer value to be divided.
1726 * @param[in] value The uint128_t value that divides the integer.
1727 * @return uint128_t the remainder of the division.
1728 */
1729IPADDRESS_EXPORT template <typename T, typename = typename std::enable_if<std::is_arithmetic<T>::value, T>::type>
1731 return uint128_t(lower) % value;
1732}
1733
1734/**
1735 * Performs bitwise AND operation between an integer and a uint128_t value.
1736 *
1737 * @tparam T Integer type.
1738 * @param[in] lower The integer value.
1739 * @param[in] value The uint128_t value.
1740 * @return uint128_t the result of the bitwise AND operation.
1741 */
1742IPADDRESS_EXPORT template <typename T, typename = typename std::enable_if<std::is_arithmetic<T>::value, T>::type>
1744 return uint128_t(lower) & value;
1745}
1746
1747/**
1748 * Performs bitwise OR operation between an integer and a uint128_t value.
1749 *
1750 * @tparam T Integer type.
1751 * @param[in] lower The integer value.
1752 * @param[in] value The uint128_t value.
1753 * @return uint128_t the result of the bitwise OR operation.
1754 */
1755IPADDRESS_EXPORT template <typename T, typename = typename std::enable_if<std::is_arithmetic<T>::value, T>::type>
1757 return uint128_t(lower) | value;
1758}
1759
1760/**
1761 * Performs bitwise XOR operation between an integer and a uint128_t value.
1762 *
1763 * @tparam T Integer type.
1764 * @param[in] lower The integer value.
1765 * @param[in] value The uint128_t value.
1766 * @return uint128_t the result of the bitwise XOR operation.
1767 */
1768IPADDRESS_EXPORT template <typename T, typename = typename std::enable_if<std::is_arithmetic<T>::value, T>::type>
1770 return uint128_t(lower) ^ value;
1771}
1772
1773/**
1774 * Checks if an integer value is equal to a uint128_t value.
1775 *
1776 * @tparam T Integral type.
1777 * @param[in] lower The integer value to compare.
1778 * @param[in] other The uint128_t value to compare.
1779 * @return `true` if the integer value is equal to the uint128_t value, `false` otherwise.
1780 */
1781IPADDRESS_EXPORT template <typename T, typename = typename std::enable_if<std::is_integral<T>::value, T>::type>
1782IPADDRESS_NODISCARD IPADDRESS_CONSTEXPR IPADDRESS_FORCE_INLINE bool operator==(T lower, const uint128_t& other) IPADDRESS_NOEXCEPT {
1783 return uint128_t(lower) == other;
1784}
1785
1786/**
1787 * Checks if an integer value is not equal to a uint128_t value.
1788 *
1789 * @tparam T Integral type.
1790 * @param[in] lower The integer value to compare.
1791 * @param[in] other The uint128_t value to compare.
1792 * @return `true` if the integer value is not equal to the uint128_t value, `false` otherwise.
1793 */
1794IPADDRESS_EXPORT template <typename T, typename = typename std::enable_if<std::is_integral<T>::value, T>::type>
1795IPADDRESS_NODISCARD IPADDRESS_CONSTEXPR IPADDRESS_FORCE_INLINE bool operator!=(T lower, const uint128_t& other) IPADDRESS_NOEXCEPT {
1796 return uint128_t(lower) != other;
1797}
1798
1799#ifdef IPADDRESS_HAS_SPACESHIP_OPERATOR
1800
1801/**
1802 * Performs a three-way comparison between an integer and a uint128_t value.
1803 *
1804 * This function template overloads the spaceship operator (<=>) to provide a three-way comparison
1805 * between a value of an integral type T and a uint128_t value. It returns the ordering category
1806 * according to the C++20 standard library definition of std::strong_ordering.
1807 *
1808 * @tparam T An integral type parameter that is checked at compile-time to ensure it is an integer type.
1809 * @param[in] lower The value of type T to be compared.
1810 * @param[in] other The uint128_t value to be compared with.
1811 * @return The result of the comparison: less, equal, or greater.
1812 */
1813IPADDRESS_EXPORT template <typename T, typename = typename std::enable_if<std::is_integral<T>::value, T>::type>
1814IPADDRESS_NODISCARD IPADDRESS_CONSTEXPR IPADDRESS_FORCE_INLINE std::strong_ordering operator<=>(T lower, const uint128_t& other) IPADDRESS_NOEXCEPT {
1815 return uint128_t(lower) <=> other;
1816}
1817
1818#else // !IPADDRESS_HAS_SPACESHIP_OPERATOR
1819
1820/**
1821 * Compares if an integer value is less than a uint128_t value.
1822 *
1823 * This function template overloads the less than operator (<) to compare an integer of type T with a uint128_t value.
1824 * It checks if the integer value is lexicographically less than the uint128_t value.
1825 *
1826 * @tparam T An integral type parameter that is checked at compile-time to ensure it is an integer type.
1827 * @param[in] lower The integer value of type T to be compared.
1828 * @param[in] other The uint128_t value to compare against.
1829 * @return `true` if \a lower is less than \a other, `false` otherwise.
1830 */
1831IPADDRESS_EXPORT template <typename T, typename = typename std::enable_if<std::is_integral<T>::value, T>::type>
1832IPADDRESS_NODISCARD IPADDRESS_CONSTEXPR IPADDRESS_FORCE_INLINE bool operator<(T lower, const uint128_t& other) IPADDRESS_NOEXCEPT {
1833 return uint128_t(lower) < other;
1834}
1835
1836/**
1837 * Compares if an integer value is greater than a uint128_t value.
1838 *
1839 * This function template overloads the greater than operator (>) to compare an integer of type T with a uint128_t value.
1840 * It checks if the integer value is lexicographically greater than the uint128_t value.
1841 *
1842 * @tparam T An integral type parameter that is checked at compile-time to ensure it is an integer type.
1843 * @param[in] lower The integer value of type T to be compared.
1844 * @param[in] other The uint128_t value to compare against.
1845 * @return `true` if \a lower is greater than \a other, `false` otherwise.
1846 */
1847IPADDRESS_EXPORT template <typename T, typename = typename std::enable_if<std::is_integral<T>::value, T>::type>
1848IPADDRESS_NODISCARD IPADDRESS_CONSTEXPR IPADDRESS_FORCE_INLINE bool operator>(T lower, const uint128_t& other) IPADDRESS_NOEXCEPT {
1849 return uint128_t(lower) > other;
1850}
1851
1852/**
1853 * Compares if an integer value is less than or equal to a uint128_t value.
1854 *
1855 * This function template overloads the less than or equal to operator (<=) to compare an integer of type T with a uint128_t value.
1856 * It checks if the integer value is lexicographically less than or equal to the uint128_t value.
1857 *
1858 * @tparam T An integral type parameter that is checked at compile-time to ensure it is an integer type.
1859 * @param[in] lower The integer value of type T to be compared.
1860 * @param[in] other The uint128_t value to compare against.
1861 * @return `true` if \a lower is less than or equal to \a other, `false` otherwise.
1862 */
1863IPADDRESS_EXPORT template <typename T, typename = typename std::enable_if<std::is_integral<T>::value, T>::type>
1864IPADDRESS_NODISCARD IPADDRESS_CONSTEXPR IPADDRESS_FORCE_INLINE bool operator<=(T lower, const uint128_t& other) IPADDRESS_NOEXCEPT {
1865 return uint128_t(lower) <= other;
1866}
1867
1868/**
1869 * Compares if an integer value is greater than or equal to a uint128_t value.
1870 *
1871 * This function template overloads the greater than or equal to operator (>=) to compare an integer of type T with a uint128_t value.
1872 * It checks if the integer value is lexicographically greater than or equal to the uint128_t value.
1873 *
1874 * @tparam T An integral type parameter that is checked at compile-time to ensure it is an integer type.
1875 * @param[in] lower The integer value of type T to be compared.
1876 * @param[in] other The uint128_t value to compare against.
1877 * @return `true` if \a lower is greater than or equal to \a other, `false` otherwise.
1878 */
1879IPADDRESS_EXPORT template <typename T, typename = typename std::enable_if<std::is_integral<T>::value, T>::type>
1880IPADDRESS_NODISCARD IPADDRESS_CONSTEXPR IPADDRESS_FORCE_INLINE bool operator>=(T lower, const uint128_t& other) IPADDRESS_NOEXCEPT {
1881 return uint128_t(lower) >= other;
1882}
1883
1884#endif // !IPADDRESS_HAS_SPACESHIP_OPERATOR
1885
1886} // namespace IPADDRESS_NAMESPACE
1887
1888#ifndef IPADDRESS_NO_OVERLOAD_STD
1889
1890namespace std {
1891
1892#pragma warning(push, 3)
1893#if defined(_MSC_VER)
1894# pragma warning(disable:4996)
1895#elif defined(__GNUC__)
1896# pragma GCC diagnostic push
1897# pragma GCC diagnostic ignored "-Wdeprecated-declarations"
1898#elif defined(__clang__)
1899 _Pragma("clang diagnostic push")
1900 _Pragma("clang diagnostic ignored \"-Wdeprecated\"")
1901#endif
1902
1903template <typename T>
1904struct _numeric_limits_uint128 {
1905 static constexpr bool is_bounded = true;
1906 static constexpr bool is_exact = true;
1907 static constexpr bool is_integer = true;
1908 static constexpr bool is_modulo = true;
1909 static constexpr bool is_specialized = true;
1910 static constexpr bool is_iec559 = false;
1911 static constexpr bool is_signed = false;
1912 static constexpr bool has_denorm_loss = false;
1913 static constexpr bool has_infinity = false;
1914 static constexpr bool has_quiet_NaN = false;
1915 static constexpr bool has_signaling_NaN = false;
1916 static constexpr bool tinyness_before = false;
1917 static constexpr bool traps = false;
1918 static constexpr int max_digits10 = 0;
1919 static constexpr int max_exponent = 0;
1920 static constexpr int max_exponent10 = 0;
1921 static constexpr int min_exponent = 0;
1922 static constexpr int min_exponent10 = 0;
1923 static constexpr int digits = 128;
1924 static constexpr int digits10 = 38;
1925 static constexpr int radix = 2;
1926 static constexpr std::float_denorm_style has_denorm = std::denorm_absent;
1927 static constexpr std::float_round_style round_style = std::round_toward_zero;
1928
1929 IPADDRESS_NODISCARD static IPADDRESS_CONSTEXPR IPADDRESS_FORCE_INLINE T (min)() IPADDRESS_NOEXCEPT {
1930 return 0;
1931 }
1932
1933 IPADDRESS_NODISCARD static IPADDRESS_CONSTEXPR IPADDRESS_FORCE_INLINE T (max)() IPADDRESS_NOEXCEPT {
1934 return T(0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF);
1935 }
1936
1937 IPADDRESS_NODISCARD static IPADDRESS_CONSTEXPR IPADDRESS_FORCE_INLINE T lowest() IPADDRESS_NOEXCEPT {
1938 return (min)();
1939 }
1940
1941 IPADDRESS_NODISCARD static IPADDRESS_CONSTEXPR IPADDRESS_FORCE_INLINE T epsilon() IPADDRESS_NOEXCEPT {
1942 return 0;
1943 }
1944
1945 IPADDRESS_NODISCARD static IPADDRESS_CONSTEXPR IPADDRESS_FORCE_INLINE T round_error() IPADDRESS_NOEXCEPT {
1946 return 0;
1947 }
1948
1949 IPADDRESS_NODISCARD static IPADDRESS_CONSTEXPR IPADDRESS_FORCE_INLINE T denorm_min() IPADDRESS_NOEXCEPT {
1950 return 0;
1951 }
1952
1953 IPADDRESS_NODISCARD static IPADDRESS_CONSTEXPR IPADDRESS_FORCE_INLINE T infinity() IPADDRESS_NOEXCEPT {
1954 return 0;
1955 }
1956
1957 IPADDRESS_NODISCARD static IPADDRESS_CONSTEXPR IPADDRESS_FORCE_INLINE T quiet_NaN() IPADDRESS_NOEXCEPT {
1958 return 0;
1959 }
1960
1961 IPADDRESS_NODISCARD static IPADDRESS_CONSTEXPR IPADDRESS_FORCE_INLINE T signaling_NaN() IPADDRESS_NOEXCEPT {
1962 return 0;
1963 }
1964};
1965
1966template <typename T>
1967constexpr bool _numeric_limits_uint128<T>::is_bounded;
1968
1969template <typename T>
1970constexpr bool _numeric_limits_uint128<T>::is_exact;
1971
1972template <typename T>
1973constexpr bool _numeric_limits_uint128<T>::is_integer;
1974
1975template <typename T>
1976constexpr bool _numeric_limits_uint128<T>::is_modulo;
1977
1978template <typename T>
1979constexpr bool _numeric_limits_uint128<T>::is_specialized;
1980
1981template <typename T>
1982constexpr bool _numeric_limits_uint128<T>::is_iec559;
1983
1984template <typename T>
1985constexpr bool _numeric_limits_uint128<T>::is_signed;
1986
1987template <typename T>
1988constexpr bool _numeric_limits_uint128<T>::has_denorm_loss;
1989
1990template <typename T>
1991constexpr bool _numeric_limits_uint128<T>::has_infinity;
1992
1993template <typename T>
1994constexpr bool _numeric_limits_uint128<T>::has_quiet_NaN;
1995
1996template <typename T>
1997constexpr bool _numeric_limits_uint128<T>::has_signaling_NaN;
1998
1999template <typename T>
2000constexpr bool _numeric_limits_uint128<T>::tinyness_before;
2001
2002template <typename T>
2003constexpr bool _numeric_limits_uint128<T>::traps;
2004
2005template <typename T>
2006constexpr int _numeric_limits_uint128<T>::max_digits10;
2007
2008template <typename T>
2009constexpr int _numeric_limits_uint128<T>::max_exponent;
2010
2011template <typename T>
2012constexpr int _numeric_limits_uint128<T>::max_exponent10;
2013
2014template <typename T>
2015constexpr int _numeric_limits_uint128<T>::min_exponent;
2016
2017template <typename T>
2018constexpr int _numeric_limits_uint128<T>::min_exponent10;
2019
2020template <typename T>
2021constexpr int _numeric_limits_uint128<T>::digits;
2022
2023template <typename T>
2024constexpr int _numeric_limits_uint128<T>::digits10;
2025
2026template <typename T>
2027constexpr int _numeric_limits_uint128<T>::radix;
2028
2029template <typename T>
2030constexpr std::float_denorm_style _numeric_limits_uint128<T>::has_denorm;
2031
2032template <typename T>
2033constexpr std::float_round_style _numeric_limits_uint128<T>::round_style;
2034
2035#if defined(_MSC_VER)
2036# pragma warning(default:4996)
2037#elif defined(__GNUC__)
2038# pragma GCC diagnostic pop
2039#elif defined(__clang__)
2040 _Pragma("clang diagnostic pop")
2041#endif
2042#pragma warning(pop)
2043
2044IPADDRESS_EXPORT template <>
2045struct numeric_limits<IPADDRESS_NAMESPACE::uint128_t> : _numeric_limits_uint128<IPADDRESS_NAMESPACE::uint128_t> {
2046};
2047
2048IPADDRESS_EXPORT template <>
2049struct hash<IPADDRESS_NAMESPACE::uint128_t> {
2050 IPADDRESS_NODISCARD IPADDRESS_CONSTEXPR IPADDRESS_FORCE_INLINE size_t operator()(const IPADDRESS_NAMESPACE::uint128_t& value) const IPADDRESS_NOEXCEPT {
2051 return value.hash();
2052 }
2053};
2054
2056 const auto tmp = value1;
2057 value1 = value2;
2058 value2 = tmp;
2059}
2060
2062 return value;
2063}
2064
2066 return value.to_string();
2067}
2068
2070 return value.to_wstring();
2071}
2072
2073IPADDRESS_EXPORT template <typename T>
2074IPADDRESS_FORCE_INLINE std::basic_ostream<T, std::char_traits<T>>& operator<<(std::basic_ostream<T, std::char_traits<T>>& stream, const IPADDRESS_NAMESPACE::uint128_t& value) {
2076 if (stream.flags() & ios_base::hex) {
2078 } else if (stream.flags() & ios_base::oct) {
2080 }
2081 auto str = value.to_string(fmt);
2082 if (stream.flags() & ios_base::uppercase) {
2083 std::transform(str.cbegin(), str.cend(), str.begin(), [](char c){
2084 return std::toupper(c);
2085 });
2086 }
2087 return stream << IPADDRESS_NAMESPACE::internal::string_converter<T>::convert(str);
2088}
2089
2090IPADDRESS_EXPORT template <typename T>
2091IPADDRESS_FORCE_INLINE std::basic_istream<T, std::char_traits<T>>& operator>>(std::basic_istream<T, std::char_traits<T>>& stream, IPADDRESS_NAMESPACE::uint128_t& value) {
2093 if (stream.flags() & ios_base::hex) {
2095 } else if (stream.flags() & ios_base::oct) {
2097 }
2098 std::basic_string<T, std::char_traits<T>, std::allocator<T>> str;
2099 stream >> str;
2100 const auto result = IPADDRESS_NAMESPACE::uint128_t::from_string(str, fmt);
2101 if (result) {
2102 value = result.value();
2103 } else {
2104 stream.setstate(std::ios_base::failbit);
2105 }
2106 return stream;
2107}
2108
2109} // namespace std
2110
2111#endif // IPADDRESS_NO_OVERLOAD_STD
2112
2113#endif // IPADDRESS_UINT128_HPP
A template class to manage an optional contained value.
Definition optional.hpp:35
constexpr inline uint128_t() noexcept=default
Default constructor.
constexpr inline uint128_t operator~() const noexcept
Bitwise NOT operator.
Definition uint128.hpp:830
constexpr inline uint128_t & operator++() noexcept
Pre-increment operator.
Definition uint128.hpp:991
constexpr inline uint128_t & operator-=(const uint128_t &other) noexcept
Subtraction assignment operator.
Definition uint128.hpp:685
constexpr inline uint128_t(short lower) noexcept
Constructs a uint128_t instance from a signed integer.
Definition uint128.hpp:227
constexpr inline operator char() const noexcept
Casts the uint128_t value to an integral type.
Definition uint128.hpp:616
constexpr inline uint64_t lower() const noexcept
Retrieves the lower 64 bits of the uint128_t value.
Definition uint128.hpp:273
constexpr inline operator unsigned char() const noexcept
Casts the uint128_t value to an integral type.
Definition uint128.hpp:605
constexpr inline operator unsigned short() const noexcept
Casts the uint128_t value to an integral type.
Definition uint128.hpp:583
constexpr inline uint128_t(unsigned short lower) noexcept
Constructs a uint128_t instance from an unsigned integer.
Definition uint128.hpp:173
constexpr inline uint128_t & operator|=(const uint128_t &other) noexcept
Bitwise OR assignment operator.
Definition uint128.hpp:751
constexpr inline uint128_t operator++(int) noexcept
Post-increment operator.
Definition uint128.hpp:1015
constexpr inline uint128_t operator^(const uint128_t &other) const noexcept
Bitwise XOR operator with another uint128_t instance.
Definition uint128.hpp:934
constexpr inline void swap(uint128_t &other) noexcept
Swaps the values of two uint128_t instances.
Definition uint128.hpp:309
constexpr inline uint128_t & operator>>=(T shift) noexcept
Bitwise right shift assignment operator.
Definition uint128.hpp:796
constexpr inline bool operator<(const uint128_t &other) const noexcept
Less than operator with another uint128_t instance.
Definition uint128.hpp:1177
constexpr inline uint128_t(long long lower) noexcept
Constructs a uint128_t instance from a signed integer.
Definition uint128.hpp:184
constexpr inline uint128_t operator|(const uint128_t &other) const noexcept
Bitwise OR operator with another uint128_t instance.
Definition uint128.hpp:922
constexpr inline bool operator>=(T lower) const noexcept
Greater than or equal to operator with an integral type.
Definition uint128.hpp:1243
constexpr inline bool operator>(const uint128_t &other) const noexcept
Greater than operator with another uint128_t instance.
Definition uint128.hpp:1203
format
Enumerates the string formats available for uint128_t.
Definition uint128.hpp:60
@ hexadecimal
Represents the number in hexadecimal format.
@ octal
Represents the number in octal format.
@ decimal
Represents the number in decimal format.
constexpr inline bool operator||(const uint128_t &other) const noexcept
Logical OR operator.
Definition uint128.hpp:1065
constexpr inline bool operator==(T lower) const noexcept
Equality operator with an integral type.
Definition uint128.hpp:1079
constexpr inline bool operator!=(const uint128_t &other) const noexcept
Inequality operator with another uint128_t instance.
Definition uint128.hpp:1117
constexpr inline uint128_t & operator%=(const uint128_t &other) noexcept
Remainder assignment operator.
Definition uint128.hpp:724
inline std::string to_string(format fmt=format::decimal) const
Converts the uint128_t value to a string representation.
Definition uint128.hpp:324
constexpr inline uint64_t upper() const noexcept
Retrieves the upper 64 bits of the uint128_t value.
Definition uint128.hpp:284
inline uint128_t(long double value) noexcept
Constructs a uint128_t instance from a floating-point value.
Definition uint128.hpp:252
constexpr inline operator signed char() const noexcept
Casts the uint128_t value to an integral type.
Definition uint128.hpp:627
constexpr inline operator unsigned int() const noexcept
Casts the uint128_t value to an integral type.
Definition uint128.hpp:561
constexpr inline uint128_t(unsigned long lower) noexcept
Constructs a uint128_t instance from an unsigned integer.
Definition uint128.hpp:151
constexpr inline operator int() const noexcept
Casts the uint128_t value to an integral type.
Definition uint128.hpp:572
constexpr inline uint128_t(const uint128_t &other) noexcept=default
Copy constructor.
static inline optional< uint128_t > from_string(const std::string &str, format fmt=format::decimal) noexcept
Parses a string to a uint128_t instance.
Definition uint128.hpp:418
constexpr inline bool operator&&(const uint128_t &other) const noexcept
Logical AND operator.
Definition uint128.hpp:1053
constexpr inline bool operator<=(const uint128_t &other) const noexcept
Less than or equal to operator with another uint128_t instance.
Definition uint128.hpp:1229
constexpr inline uint128_t operator+() const noexcept
Unary plus operator.
Definition uint128.hpp:808
inline std::u32string to_u32string(format fmt=format::decimal) const
Converts the uint128_t value to a string representation.
Definition uint128.hpp:387
constexpr inline uint128_t operator+(const uint128_t &other) const noexcept
Addition operator with another uint128_t instance.
Definition uint128.hpp:842
inline std::u16string to_u16string(format fmt=format::decimal) const
Converts the uint128_t value to a string representation.
Definition uint128.hpp:374
constexpr inline bool operator!() const noexcept
Logical NOT operator.
Definition uint128.hpp:1041
constexpr inline uint128_t & operator*=(const uint128_t &other) noexcept
Multiplication assignment operator.
Definition uint128.hpp:698
constexpr inline uint128_t(long lower) noexcept
Constructs a uint128_t instance from a signed integer.
Definition uint128.hpp:205
constexpr inline operator long() const noexcept
Casts the uint128_t value to an integral type.
Definition uint128.hpp:550
constexpr inline operator long long() const noexcept
Casts the uint128_t value to an integral type.
Definition uint128.hpp:528
constexpr inline uint128_t & operator^=(const uint128_t &other) noexcept
Bitwise XOR assignment operator.
Definition uint128.hpp:765
inline operator float() const noexcept
Casts the uint128_t value to a floating-point type.
Definition uint128.hpp:660
inline operator double() const noexcept
Casts the uint128_t value to a floating-point type.
Definition uint128.hpp:649
inline uint128_t(double value) noexcept
Constructs a uint128_t instance from a floating-point value.
Definition uint128.hpp:238
constexpr inline uint128_t & operator=(uint128_t &&other) noexcept=default
Move assignment operator.
constexpr inline operator short() const noexcept
Casts the uint128_t value to an integral type.
Definition uint128.hpp:594
constexpr inline uint128_t(int lower) noexcept
Constructs a uint128_t instance from a signed integer.
Definition uint128.hpp:216
constexpr inline bool operator==(const uint128_t &other) const noexcept
Equality operator with another uint128_t instance.
Definition uint128.hpp:1091
inline operator long double() const noexcept
Casts the uint128_t value to a floating-point type.
Definition uint128.hpp:638
constexpr inline uint128_t & operator&=(const uint128_t &other) noexcept
Bitwise AND assignment operator.
Definition uint128.hpp:737
constexpr inline uint128_t & operator=(const uint128_t &other) noexcept=default
Assignment operator.
constexpr inline uint128_t(uint128_t &&other) noexcept=default
Move constructor.
constexpr inline uint128_t operator-() const noexcept
Unary minus operator.
Definition uint128.hpp:819
constexpr inline operator unsigned long() const noexcept
Casts the uint128_t value to an integral type.
Definition uint128.hpp:539
constexpr inline size_t hash() const noexcept
Computes the hash value of the uint128_t instance.
Definition uint128.hpp:295
constexpr inline uint128_t(unsigned int lower) noexcept
Constructs a uint128_t instance from an unsigned integer.
Definition uint128.hpp:162
constexpr inline bool operator<(T lower) const noexcept
Less than operator with an integral type.
Definition uint128.hpp:1165
constexpr inline uint128_t & operator--() noexcept
Pre-decrement operator.
Definition uint128.hpp:1003
static constexpr inline optional< uint128_t > from_string(const T(&str)[N], format fmt=format::decimal) noexcept
Parses a string to a uint128_t instance.
Definition uint128.hpp:495
constexpr inline operator unsigned long long() const noexcept
Casts the uint128_t value to an integral type.
Definition uint128.hpp:517
constexpr inline uint128_t operator*(const uint128_t &other) const noexcept
Multiplication operator with another uint128_t instance.
Definition uint128.hpp:870
constexpr inline uint128_t operator&(const uint128_t &other) const noexcept
Bitwise AND operator with another uint128_t instance.
Definition uint128.hpp:910
inline uint128_t(float value) noexcept
Constructs a uint128_t instance from a floating-point value.
Definition uint128.hpp:263
constexpr inline bool operator!=(T lower) const noexcept
Inequality operator with an integral type.
Definition uint128.hpp:1105
constexpr inline uint128_t & operator+=(const uint128_t &other) noexcept
Addition assignment operator.
Definition uint128.hpp:672
constexpr inline uint128_t operator-(const uint128_t &other) const noexcept
Subtraction operator with another uint128_t instance.
Definition uint128.hpp:856
constexpr inline uint128_t & operator/=(const uint128_t &other) noexcept
Division assignment operator.
Definition uint128.hpp:711
constexpr inline uint128_t operator>>(T shift) const noexcept
Bitwise right shift operator with an integral type.
Definition uint128.hpp:971
constexpr inline bool operator>=(const uint128_t &other) const noexcept
Greater than or equal to operator with another uint128_t instance.
Definition uint128.hpp:1255
constexpr inline uint128_t operator%(const uint128_t &other) const noexcept
Remainder operator with another uint128_t instance.
Definition uint128.hpp:897
constexpr inline operator bool() const noexcept
Checks if the uint128_t value is non-zero.
Definition uint128.hpp:506
constexpr inline uint128_t(uint64_t upper, uint64_t lower) noexcept
Constructs a uint128_t instance from upper and lower parts.
Definition uint128.hpp:119
constexpr inline uint128_t operator--(int) noexcept
Post-decrement operator.
Definition uint128.hpp:1028
inline std::wstring to_wstring(format fmt=format::decimal) const
Converts the uint128_t value to a string representation.
Definition uint128.hpp:361
constexpr inline uint128_t operator/(const uint128_t &other) const noexcept
Division operator with another uint128_t instance.
Definition uint128.hpp:885
constexpr inline bool operator<=(T lower) const noexcept
Less than or equal to operator with an integral type.
Definition uint128.hpp:1217
constexpr inline bool operator>(T lower) const noexcept
Greater than operator with an integral type.
Definition uint128.hpp:1191
inline std::u8string to_u8string(format fmt=format::decimal) const
Converts the uint128_t value to a string representation.
Definition uint128.hpp:402
constexpr inline uint128_t(unsigned long long lower) noexcept
Constructs a uint128_t instance from an unsigned integer.
Definition uint128.hpp:140
#define IPADDRESS_EXPORT
Definition config.hpp:42
#define IPADDRESS_NODISCARD
Definition config.hpp:98
#define IPADDRESS_FORCE_INLINE
Definition config.hpp:112
#define IPADDRESS_NAMESPACE
Definition config.hpp:38
#define IPADDRESS_NOEXCEPT
Definition config.hpp:89
constexpr inline uint128_t operator^(T lower, const uint128_t &value) noexcept
Performs bitwise XOR operation between an integer and a uint128_t value.
Definition uint128.hpp:1769
constexpr inline uint128_t operator|(T lower, const uint128_t &value) noexcept
Performs bitwise OR operation between an integer and a uint128_t value.
Definition uint128.hpp:1756
constexpr inline uint128_t operator+(T lower, const uint128_t &value) noexcept
Performs addition between an integer and a uint128_t value.
Definition uint128.hpp:1678
constexpr inline bool operator>(T lower, const uint128_t &other) noexcept
Compares if an integer value is greater than a uint128_t value.
Definition uint128.hpp:1848
constexpr inline bool operator<(T lower, const uint128_t &other) noexcept
Compares if an integer value is less than a uint128_t value.
Definition uint128.hpp:1832
constexpr inline uint128_t operator-(T lower, const uint128_t &value) noexcept
Performs subtraction of a uint128_t value from an integer.
Definition uint128.hpp:1691
constexpr inline uint128_t operator&(T lower, const uint128_t &value) noexcept
Performs bitwise AND operation between an integer and a uint128_t value.
Definition uint128.hpp:1743
constexpr inline uint128_t operator%(T lower, const uint128_t &value) noexcept
Calculates the remainder of division of an integer by a uint128_t value.
Definition uint128.hpp:1730
constexpr inline bool operator==(T lower, const uint128_t &other) noexcept
Checks if an integer value is equal to a uint128_t value.
Definition uint128.hpp:1782
constexpr inline bool operator>=(T lower, const uint128_t &other) noexcept
Compares if an integer value is greater than or equal to a uint128_t value.
Definition uint128.hpp:1880
constexpr inline bool operator!=(T lower, const uint128_t &other) noexcept
Checks if an integer value is not equal to a uint128_t value.
Definition uint128.hpp:1795
constexpr inline bool operator<=(T lower, const uint128_t &other) noexcept
Compares if an integer value is less than or equal to a uint128_t value.
Definition uint128.hpp:1864
constexpr inline uint128_t operator*(T lower, const uint128_t &value) noexcept
Performs multiplication between an integer and a uint128_t value.
Definition uint128.hpp:1704
constexpr inline uint128_t operator/(T lower, const uint128_t &value) noexcept
Performs division of an integer by a uint128_t value.
Definition uint128.hpp:1717