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