Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-04-19 08:19:40

0001 // Copyright 2020-2023 Daniel Lemire
0002 // Copyright 2023 Matt Borland
0003 // Distributed under the Boost Software License, Version 1.0.
0004 // https://www.boost.org/LICENSE_1_0.txt
0005 //
0006 // If the architecture (e.g. Apple ARM) does not have __int128 we need to emulate it
0007 
0008 #ifndef BOOST_CHARCONV_DETAIL_EMULATED128_HPP
0009 #define BOOST_CHARCONV_DETAIL_EMULATED128_HPP
0010 
0011 #include <boost/charconv/detail/config.hpp>
0012 #include <boost/charconv/config.hpp>
0013 #include <boost/core/bit.hpp>
0014 #include <type_traits>
0015 #include <limits>
0016 #include <cstdint>
0017 #include <cassert>
0018 #include <cmath>
0019 
0020 namespace boost { namespace charconv { namespace detail {
0021 
0022 // Compilers might support built-in 128-bit integer types. However, it seems that
0023 // emulating them with a pair of 64-bit integers actually produces a better code,
0024 // so we avoid using those built-ins. That said, they are still useful for
0025 // implementing 64-bit x 64-bit -> 128-bit multiplication.
0026 
0027 // Memcpy-able temp class for uint128
0028 struct trivial_uint128
0029 {
0030     #if BOOST_CHARCONV_ENDIAN_LITTLE_BYTE
0031     std::uint64_t low;
0032     std::uint64_t high;
0033     #else
0034     std::uint64_t high;
0035     std::uint64_t low;
0036     #endif
0037 };
0038 
0039 // Macro replacement lists can not be enclosed in parentheses
0040 struct uint128
0041 {
0042     std::uint64_t high;
0043     std::uint64_t low;
0044 
0045     // Constructors
0046     constexpr uint128() noexcept : high {}, low {} {}
0047 
0048     constexpr uint128(const uint128& v) noexcept = default;
0049 
0050     constexpr uint128(uint128&& v) noexcept = default;
0051 
0052     constexpr uint128(std::uint64_t high_, std::uint64_t low_) noexcept : high {high_}, low {low_} {}
0053 
0054     constexpr uint128(const trivial_uint128& v) noexcept : high {v.high}, low {v.low} {} // NOLINT
0055 
0056     constexpr uint128(trivial_uint128&& v) noexcept : high {v.high}, low {v.low} {} // NOLINT
0057 
0058     #define SIGNED_CONSTRUCTOR(expr) constexpr uint128(expr v) noexcept : high {v < 0 ? UINT64_MAX : UINT64_C(0)}, low {static_cast<std::uint64_t>(v)} {} // NOLINT
0059     #define UNSIGNED_CONSTRUCTOR(expr) constexpr uint128(expr v) noexcept : high {}, low {static_cast<std::uint64_t>(v)} {} // NOLINT
0060 
0061     SIGNED_CONSTRUCTOR(char)                    // NOLINT
0062     SIGNED_CONSTRUCTOR(signed char)             // NOLINT
0063     SIGNED_CONSTRUCTOR(short)                   // NOLINT
0064     SIGNED_CONSTRUCTOR(int)                     // NOLINT
0065     SIGNED_CONSTRUCTOR(long)                    // NOLINT
0066     SIGNED_CONSTRUCTOR(long long)               // NOLINT
0067 
0068     UNSIGNED_CONSTRUCTOR(unsigned char)         // NOLINT
0069     UNSIGNED_CONSTRUCTOR(unsigned short)        // NOLINT
0070     UNSIGNED_CONSTRUCTOR(unsigned)              // NOLINT
0071     UNSIGNED_CONSTRUCTOR(unsigned long)         // NOLINT
0072     UNSIGNED_CONSTRUCTOR(unsigned long long)    // NOLINT
0073 
0074     #ifdef BOOST_CHARCONV_HAS_INT128
0075     constexpr uint128(boost::int128_type v) noexcept :  // NOLINT : Allow implicit conversions
0076         high {static_cast<std::uint64_t>(v >> 64)},
0077          low {static_cast<std::uint64_t>(static_cast<boost::uint128_type>(v) & ~UINT64_C(0))} {}
0078 
0079     constexpr uint128(boost::uint128_type v) noexcept : // NOLINT : Allow implicit conversions
0080         high {static_cast<std::uint64_t>(v >> 64)},
0081          low {static_cast<std::uint64_t>(v & ~UINT64_C(0))} {}
0082     #endif
0083 
0084     #undef SIGNED_CONSTRUCTOR
0085     #undef UNSIGNED_CONSTRUCTOR
0086 
0087     // Assignment Operators
0088     #define SIGNED_ASSIGNMENT_OPERATOR(expr) BOOST_CHARCONV_CXX14_CONSTEXPR uint128 &operator=(const expr& v) noexcept { high = v < 0 ? UINT64_MAX : UINT64_C(0); low = static_cast<std::uint64_t>(v); return *this; } // NOLINT
0089     #define UNSIGNED_ASSIGNMENT_OPERATOR(expr) BOOST_CHARCONV_CXX14_CONSTEXPR uint128 &operator=(const expr& v) noexcept { high = 0U; low = static_cast<std::uint64_t>(v); return *this; } // NOLINT
0090 
0091     SIGNED_ASSIGNMENT_OPERATOR(char)                    // NOLINT
0092     SIGNED_ASSIGNMENT_OPERATOR(signed char)             // NOLINT
0093     SIGNED_ASSIGNMENT_OPERATOR(short)                   // NOLINT
0094     SIGNED_ASSIGNMENT_OPERATOR(int)                     // NOLINT
0095     SIGNED_ASSIGNMENT_OPERATOR(long)                    // NOLINT
0096     SIGNED_ASSIGNMENT_OPERATOR(long long)               // NOLINT
0097 
0098     UNSIGNED_ASSIGNMENT_OPERATOR(unsigned char)         // NOLINT
0099     UNSIGNED_ASSIGNMENT_OPERATOR(unsigned short)        // NOLINT
0100     UNSIGNED_ASSIGNMENT_OPERATOR(unsigned)              // NOLINT
0101     UNSIGNED_ASSIGNMENT_OPERATOR(unsigned long)         // NOLINT
0102     UNSIGNED_ASSIGNMENT_OPERATOR(unsigned long long)    // NOLINT
0103 
0104     #ifdef BOOST_CHARCONV_HAS_INT128
0105     BOOST_CHARCONV_CXX14_CONSTEXPR uint128 &operator=(const boost::int128_type&  v) noexcept { *this = uint128(v); return *this; }
0106     BOOST_CHARCONV_CXX14_CONSTEXPR uint128 &operator=(const boost::uint128_type& v) noexcept { *this = uint128(v); return *this; }
0107     #endif
0108 
0109     BOOST_CHARCONV_CXX14_CONSTEXPR uint128 &operator=(const trivial_uint128& v) noexcept { this->low = v.low; this->high = v.high; return *this; }
0110 
0111     BOOST_CHARCONV_CXX14_CONSTEXPR uint128 &operator=(const uint128&) noexcept;
0112 
0113     #undef SIGNED_ASSIGNMENT_OPERATOR
0114     #undef UNSIGNED_ASSIGNMENT_OPERATOR
0115 
0116     // Conversion Operators
0117     #define INTEGER_CONVERSION_OPERATOR(expr) explicit constexpr operator expr() const noexcept { return static_cast<expr>(low); } // NOLINT
0118     #define FLOAT_CONVERSION_OPERATOR(expr) explicit operator expr() const noexcept { return std::ldexp(static_cast<expr>(high), 64) + static_cast<expr>(low); } // NOLINT
0119 
0120     INTEGER_CONVERSION_OPERATOR(char)                   // NOLINT
0121     INTEGER_CONVERSION_OPERATOR(signed char)            // NOLINT
0122     INTEGER_CONVERSION_OPERATOR(short)                  // NOLINT
0123     INTEGER_CONVERSION_OPERATOR(int)                    // NOLINT
0124     INTEGER_CONVERSION_OPERATOR(long)                   // NOLINT
0125     INTEGER_CONVERSION_OPERATOR(long long)              // NOLINT
0126     INTEGER_CONVERSION_OPERATOR(unsigned char)          // NOLINT
0127     INTEGER_CONVERSION_OPERATOR(unsigned short)         // NOLINT
0128     INTEGER_CONVERSION_OPERATOR(unsigned)               // NOLINT
0129     INTEGER_CONVERSION_OPERATOR(unsigned long)          // NOLINT
0130     INTEGER_CONVERSION_OPERATOR(unsigned long long)     // NOLINT
0131 
0132     explicit constexpr operator bool() const noexcept { return high || low; }
0133 
0134     #ifdef BOOST_CHARCONV_HAS_INT128
0135     explicit constexpr operator boost::int128_type()  const noexcept { return (static_cast<boost::int128_type>(high) << 64) + low; }
0136     explicit constexpr operator boost::uint128_type() const noexcept { return (static_cast<boost::uint128_type>(high) << 64) + low; }
0137     #endif
0138 
0139     FLOAT_CONVERSION_OPERATOR(float)        // NOLINT
0140     FLOAT_CONVERSION_OPERATOR(double)       // NOLINT
0141     FLOAT_CONVERSION_OPERATOR(long double)  // NOLINT
0142 
0143     #undef INTEGER_CONVERSION_OPERATOR
0144     #undef FLOAT_CONVERSION_OPERATOR
0145 
0146     // Unary Operators
0147     constexpr friend uint128 operator-(uint128 val) noexcept;
0148     constexpr friend uint128 operator+(uint128 val) noexcept;
0149 
0150     // Comparison Operators
0151 
0152     // Equality
0153     #define INTEGER_OPERATOR_EQUAL(expr) constexpr friend bool operator==(uint128 lhs, expr rhs) noexcept { return lhs.high == 0 && rhs >= 0 && lhs.low == static_cast<std::uint64_t>(rhs); } // NOLINT
0154     #define UNSIGNED_INTEGER_OPERATOR_EQUAL(expr) constexpr friend bool operator==(uint128 lhs, expr rhs) noexcept { return lhs.high == 0 && lhs.low == static_cast<std::uint64_t>(rhs); } // NOLINT
0155 
0156     INTEGER_OPERATOR_EQUAL(char)                        // NOLINT
0157     INTEGER_OPERATOR_EQUAL(signed char)                 // NOLINT
0158     INTEGER_OPERATOR_EQUAL(short)                       // NOLINT
0159     INTEGER_OPERATOR_EQUAL(int)                         // NOLINT
0160     INTEGER_OPERATOR_EQUAL(long)                        // NOLINT
0161     INTEGER_OPERATOR_EQUAL(long long)                   // NOLINT
0162     UNSIGNED_INTEGER_OPERATOR_EQUAL(unsigned char)      // NOLINT
0163     UNSIGNED_INTEGER_OPERATOR_EQUAL(unsigned short)     // NOLINT
0164     UNSIGNED_INTEGER_OPERATOR_EQUAL(unsigned)           // NOLINT
0165     UNSIGNED_INTEGER_OPERATOR_EQUAL(unsigned long)      // NOLINT
0166     UNSIGNED_INTEGER_OPERATOR_EQUAL(unsigned long long) // NOLINT
0167 
0168     #ifdef BOOST_CHARCONV_HAS_INT128
0169     constexpr friend bool operator==(uint128 lhs, boost::int128_type  rhs) noexcept { return lhs == uint128(rhs); }
0170     constexpr friend bool operator==(uint128 lhs, boost::uint128_type rhs) noexcept { return lhs == uint128(rhs); }
0171     #endif
0172 
0173     constexpr friend bool operator==(uint128 lhs, uint128 rhs) noexcept;
0174 
0175     #undef INTEGER_OPERATOR_EQUAL
0176     #undef UNSIGNED_INTEGER_OPERATOR_EQUAL
0177 
0178     // Inequality
0179     #define INTEGER_OPERATOR_NOTEQUAL(expr) constexpr friend bool operator!=(uint128 lhs, expr rhs) noexcept { return !(lhs == rhs); } // NOLINT
0180 
0181     INTEGER_OPERATOR_NOTEQUAL(char)                 // NOLINT
0182     INTEGER_OPERATOR_NOTEQUAL(signed char)          // NOLINT
0183     INTEGER_OPERATOR_NOTEQUAL(short)                // NOLINT
0184     INTEGER_OPERATOR_NOTEQUAL(int)                  // NOLINT
0185     INTEGER_OPERATOR_NOTEQUAL(long)                 // NOLINT
0186     INTEGER_OPERATOR_NOTEQUAL(long long)            // NOLINT
0187     INTEGER_OPERATOR_NOTEQUAL(unsigned char)        // NOLINT
0188     INTEGER_OPERATOR_NOTEQUAL(unsigned short)       // NOLINT
0189     INTEGER_OPERATOR_NOTEQUAL(unsigned)             // NOLINT
0190     INTEGER_OPERATOR_NOTEQUAL(unsigned long)        // NOLINT
0191     INTEGER_OPERATOR_NOTEQUAL(unsigned long long)   // NOLINT
0192 
0193     #ifdef BOOST_CHARCONV_HAS_INT128
0194     constexpr friend bool operator!=(uint128 lhs, boost::int128_type  rhs) noexcept { return !(lhs == rhs); }
0195     constexpr friend bool operator!=(uint128 lhs, boost::uint128_type rhs) noexcept { return !(lhs == rhs); }
0196     #endif
0197 
0198     constexpr friend bool operator!=(uint128 lhs, uint128 rhs) noexcept;
0199 
0200     #undef INTEGER_OPERATOR_NOTEQUAL
0201 
0202     // Less than
0203     #define INTEGER_OPERATOR_LESS_THAN(expr) constexpr friend bool operator<(uint128 lhs, expr rhs) noexcept { return lhs.high == 0U && rhs > 0 && lhs.low < static_cast<std::uint64_t>(rhs); } // NOLINT
0204     #define UNSIGNED_INTEGER_OPERATOR_LESS_THAN(expr) constexpr friend bool operator<(uint128 lhs, expr rhs) noexcept { return lhs.high == 0U && lhs.low < static_cast<std::uint64_t>(rhs); } // NOLINT
0205 
0206     INTEGER_OPERATOR_LESS_THAN(char)                            // NOLINT
0207     INTEGER_OPERATOR_LESS_THAN(signed char)                     // NOLINT
0208     INTEGER_OPERATOR_LESS_THAN(short)                           // NOLINT
0209     INTEGER_OPERATOR_LESS_THAN(int)                             // NOLINT
0210     INTEGER_OPERATOR_LESS_THAN(long)                            // NOLINT
0211     INTEGER_OPERATOR_LESS_THAN(long long)                       // NOLINT
0212     UNSIGNED_INTEGER_OPERATOR_LESS_THAN(unsigned char)          // NOLINT
0213     UNSIGNED_INTEGER_OPERATOR_LESS_THAN(unsigned short)         // NOLINT
0214     UNSIGNED_INTEGER_OPERATOR_LESS_THAN(unsigned)               // NOLINT
0215     UNSIGNED_INTEGER_OPERATOR_LESS_THAN(unsigned long)          // NOLINT
0216     UNSIGNED_INTEGER_OPERATOR_LESS_THAN(unsigned long long)     // NOLINT
0217 
0218     #ifdef BOOST_CHARCONV_HAS_INT128
0219     BOOST_CHARCONV_CXX14_CONSTEXPR friend bool operator<(uint128 lhs, boost::int128_type  rhs) noexcept { return lhs < uint128(rhs); }
0220     BOOST_CHARCONV_CXX14_CONSTEXPR friend bool operator<(uint128 lhs, boost::uint128_type rhs) noexcept { return lhs < uint128(rhs); }
0221     #endif
0222 
0223     BOOST_CHARCONV_CXX14_CONSTEXPR friend bool operator<(uint128 lhs, uint128 rhs) noexcept;
0224 
0225     #undef INTEGER_OPERATOR_LESS_THAN
0226     #undef UNSIGNED_INTEGER_OPERATOR_LESS_THAN
0227 
0228     // Less than or equal to
0229     #define INTEGER_OPERATOR_LESS_THAN_OR_EQUAL_TO(expr) constexpr friend bool operator<=(uint128 lhs, expr rhs) noexcept { return lhs.high == 0U && rhs >= 0 && lhs.low <= static_cast<std::uint64_t>(rhs); } // NOLINT
0230     #define UNSIGNED_INTEGER_OPERATOR_LESS_THAN_OR_EQUAL_TO(expr) constexpr friend bool operator<=(uint128 lhs, expr rhs) noexcept { return lhs.high == 0U && lhs.low <= static_cast<std::uint64_t>(rhs); } // NOLINT
0231 
0232     INTEGER_OPERATOR_LESS_THAN_OR_EQUAL_TO(char)                            // NOLINT
0233     INTEGER_OPERATOR_LESS_THAN_OR_EQUAL_TO(signed char)                     // NOLINT
0234     INTEGER_OPERATOR_LESS_THAN_OR_EQUAL_TO(short)                           // NOLINT
0235     INTEGER_OPERATOR_LESS_THAN_OR_EQUAL_TO(int)                             // NOLINT
0236     INTEGER_OPERATOR_LESS_THAN_OR_EQUAL_TO(long)                            // NOLINT
0237     INTEGER_OPERATOR_LESS_THAN_OR_EQUAL_TO(long long)                       // NOLINT
0238     UNSIGNED_INTEGER_OPERATOR_LESS_THAN_OR_EQUAL_TO(unsigned char)          // NOLINT
0239     UNSIGNED_INTEGER_OPERATOR_LESS_THAN_OR_EQUAL_TO(unsigned short)         // NOLINT
0240     UNSIGNED_INTEGER_OPERATOR_LESS_THAN_OR_EQUAL_TO(unsigned)               // NOLINT
0241     UNSIGNED_INTEGER_OPERATOR_LESS_THAN_OR_EQUAL_TO(unsigned long)          // NOLINT
0242     UNSIGNED_INTEGER_OPERATOR_LESS_THAN_OR_EQUAL_TO(unsigned long long)     // NOLINT
0243 
0244     #ifdef BOOST_CHARCONV_HAS_INT128
0245     BOOST_CHARCONV_CXX14_CONSTEXPR friend bool operator<=(uint128 lhs, boost::int128_type  rhs) noexcept { return lhs <= uint128(rhs); }
0246     BOOST_CHARCONV_CXX14_CONSTEXPR friend bool operator<=(uint128 lhs, boost::uint128_type rhs) noexcept { return lhs <= uint128(rhs); }
0247     #endif
0248 
0249     BOOST_CHARCONV_CXX14_CONSTEXPR friend bool operator<=(uint128 lhs, uint128 rhs) noexcept;
0250 
0251     #undef INTEGER_OPERATOR_LESS_THAN_OR_EQUAL_TO
0252     #undef UNSIGNED_INTEGER_OPERATOR_LESS_THAN_OR_EQUAL_TO
0253 
0254     // Greater than
0255     #define INTEGER_OPERATOR_GREATER_THAN(expr) constexpr friend bool operator>(uint128 lhs, expr rhs) noexcept { return lhs.high > 0U || rhs < 0 || lhs.low > static_cast<std::uint64_t>(rhs); } // NOLINT
0256     #define UNSIGNED_INTEGER_OPERATOR_GREATER_THAN(expr) constexpr friend bool operator>(uint128 lhs, expr rhs) noexcept { return lhs.high > 0U || lhs.low > static_cast<std::uint64_t>(rhs); } // NOLINT
0257 
0258     INTEGER_OPERATOR_GREATER_THAN(char)                             // NOLINT
0259     INTEGER_OPERATOR_GREATER_THAN(signed char)                      // NOLINT
0260     INTEGER_OPERATOR_GREATER_THAN(short)                            // NOLINT
0261     INTEGER_OPERATOR_GREATER_THAN(int)                              // NOLINT
0262     INTEGER_OPERATOR_GREATER_THAN(long)                             // NOLINT
0263     INTEGER_OPERATOR_GREATER_THAN(long long)                        // NOLINT
0264     UNSIGNED_INTEGER_OPERATOR_GREATER_THAN(unsigned char)           // NOLINT
0265     UNSIGNED_INTEGER_OPERATOR_GREATER_THAN(unsigned short)          // NOLINT
0266     UNSIGNED_INTEGER_OPERATOR_GREATER_THAN(unsigned)                // NOLINT
0267     UNSIGNED_INTEGER_OPERATOR_GREATER_THAN(unsigned long)           // NOLINT
0268     UNSIGNED_INTEGER_OPERATOR_GREATER_THAN(unsigned long long)      // NOLINT
0269 
0270     #ifdef BOOST_CHARCONV_HAS_INT128
0271     BOOST_CHARCONV_CXX14_CONSTEXPR friend bool operator>(uint128 lhs, boost::int128_type  rhs) noexcept { return lhs > uint128(rhs); }
0272     BOOST_CHARCONV_CXX14_CONSTEXPR friend bool operator>(uint128 lhs, boost::uint128_type rhs) noexcept { return lhs > uint128(rhs); }
0273     #endif
0274 
0275     BOOST_CHARCONV_CXX14_CONSTEXPR friend bool operator>(uint128 lhs, uint128 rhs) noexcept;
0276 
0277     #undef INTEGER_OPERATOR_GREATER_THAN
0278     #undef UNSIGNED_INTEGER_OPERATOR_GREATER_THAN
0279 
0280     // Greater than or equal to
0281     #define INTEGER_OPERATOR_GREATER_THAN_OR_EQUAL_TO(expr) constexpr friend bool operator>=(uint128 lhs, expr rhs) noexcept { return lhs.high > 0U || rhs < 0 || lhs.low >= static_cast<std::uint64_t>(rhs); } // NOLINT
0282     #define UNSIGNED_INTEGER_OPERATOR_GREATER_THAN_OR_EQUAL_TO(expr) constexpr friend bool operator>=(uint128 lhs, expr rhs) noexcept { return lhs.high > 0U || lhs.low >= static_cast<std::uint64_t>(rhs); } // NOLINT
0283 
0284     INTEGER_OPERATOR_GREATER_THAN_OR_EQUAL_TO(char)                             // NOLINT
0285     INTEGER_OPERATOR_GREATER_THAN_OR_EQUAL_TO(signed char)                      // NOLINT
0286     INTEGER_OPERATOR_GREATER_THAN_OR_EQUAL_TO(short)                            // NOLINT
0287     INTEGER_OPERATOR_GREATER_THAN_OR_EQUAL_TO(int)                              // NOLINT
0288     INTEGER_OPERATOR_GREATER_THAN_OR_EQUAL_TO(long)                             // NOLINT
0289     INTEGER_OPERATOR_GREATER_THAN_OR_EQUAL_TO(long long)                        // NOLINT
0290     UNSIGNED_INTEGER_OPERATOR_GREATER_THAN_OR_EQUAL_TO(unsigned char)           // NOLINT
0291     UNSIGNED_INTEGER_OPERATOR_GREATER_THAN_OR_EQUAL_TO(unsigned short)          // NOLINT
0292     UNSIGNED_INTEGER_OPERATOR_GREATER_THAN_OR_EQUAL_TO(unsigned)                // NOLINT
0293     UNSIGNED_INTEGER_OPERATOR_GREATER_THAN_OR_EQUAL_TO(unsigned long)           // NOLINT
0294     UNSIGNED_INTEGER_OPERATOR_GREATER_THAN_OR_EQUAL_TO(unsigned long long)      // NOLINT
0295 
0296     #ifdef BOOST_CHARCONV_HAS_INT128
0297     BOOST_CHARCONV_CXX14_CONSTEXPR friend bool operator>=(uint128 lhs, boost::int128_type  rhs) noexcept { return lhs >= uint128(rhs); }
0298     BOOST_CHARCONV_CXX14_CONSTEXPR friend bool operator>=(uint128 lhs, boost::uint128_type rhs) noexcept { return lhs >= uint128(rhs); }
0299     #endif
0300 
0301     BOOST_CHARCONV_CXX14_CONSTEXPR friend bool operator>=(uint128 lhs, uint128 rhs) noexcept;
0302 
0303     #undef INTEGER_OPERATOR_GREATER_THAN_OR_EQUAL_TO
0304     #undef UNSIGNED_INTEGER_OPERATOR_GREATER_THAN_OR_EQUAL_TO
0305 
0306     // Binary Operators
0307 
0308     // Not
0309     constexpr friend uint128 operator~(uint128 v) noexcept;
0310 
0311     // Or
0312     #define INTEGER_BINARY_OPERATOR_OR(expr) constexpr friend uint128 operator|(uint128 lhs, expr rhs) noexcept { return {lhs.high, lhs.low | static_cast<std::uint64_t>(rhs)}; } // NOLINT
0313 
0314     INTEGER_BINARY_OPERATOR_OR(char)                // NOLINT
0315     INTEGER_BINARY_OPERATOR_OR(signed char)         // NOLINT
0316     INTEGER_BINARY_OPERATOR_OR(short)               // NOLINT
0317     INTEGER_BINARY_OPERATOR_OR(int)                 // NOLINT
0318     INTEGER_BINARY_OPERATOR_OR(long)                // NOLINT
0319     INTEGER_BINARY_OPERATOR_OR(long long)           // NOLINT
0320     INTEGER_BINARY_OPERATOR_OR(unsigned char)       // NOLINT
0321     INTEGER_BINARY_OPERATOR_OR(unsigned short)      // NOLINT
0322     INTEGER_BINARY_OPERATOR_OR(unsigned)            // NOLINT
0323     INTEGER_BINARY_OPERATOR_OR(unsigned long)       // NOLINT
0324     INTEGER_BINARY_OPERATOR_OR(unsigned long long)  // NOLINT
0325 
0326     #ifdef BOOST_CHARCONV_HAS_INT128
0327     constexpr friend uint128 operator|(uint128 lhs, boost::int128_type  rhs) noexcept { return lhs | uint128(rhs); }
0328     constexpr friend uint128 operator|(uint128 lhs, boost::uint128_type rhs) noexcept { return lhs | uint128(rhs); }
0329     #endif
0330 
0331     constexpr friend uint128 operator|(uint128 lhs, uint128 rhs) noexcept;
0332 
0333     BOOST_CHARCONV_CXX14_CONSTEXPR uint128 &operator|=(uint128 v) noexcept;
0334 
0335     #undef INTEGER_BINARY_OPERATOR_OR
0336 
0337     // And
0338     #define INTEGER_BINARY_OPERATOR_AND(expr) constexpr friend uint128 operator&(uint128 lhs, expr rhs) noexcept { return {lhs.high, lhs.low & static_cast<std::uint64_t>(rhs)}; } // NOLINT
0339 
0340     INTEGER_BINARY_OPERATOR_AND(char)                   // NOLINT
0341     INTEGER_BINARY_OPERATOR_AND(signed char)            // NOLINT
0342     INTEGER_BINARY_OPERATOR_AND(short)                  // NOLINT
0343     INTEGER_BINARY_OPERATOR_AND(int)                    // NOLINT
0344     INTEGER_BINARY_OPERATOR_AND(long)                   // NOLINT
0345     INTEGER_BINARY_OPERATOR_AND(long long)              // NOLINT
0346     INTEGER_BINARY_OPERATOR_AND(unsigned char)          // NOLINT
0347     INTEGER_BINARY_OPERATOR_AND(unsigned short)         // NOLINT
0348     INTEGER_BINARY_OPERATOR_AND(unsigned)               // NOLINT
0349     INTEGER_BINARY_OPERATOR_AND(unsigned long)          // NOLINT
0350     INTEGER_BINARY_OPERATOR_AND(unsigned long long)     // NOLINT
0351 
0352     #ifdef BOOST_CHARCONV_HAS_INT128
0353     constexpr friend uint128 operator&(uint128 lhs, boost::int128_type  rhs) noexcept { return lhs & uint128(rhs); }
0354     constexpr friend uint128 operator&(uint128 lhs, boost::uint128_type rhs) noexcept { return lhs & uint128(rhs); }
0355     #endif
0356 
0357     constexpr friend uint128 operator&(uint128 lhs, uint128 rhs) noexcept;
0358 
0359     BOOST_CHARCONV_CXX14_CONSTEXPR uint128 &operator&=(uint128 v) noexcept;
0360 
0361     #undef INTEGER_BINARY_OPERATOR_AND
0362 
0363     // Xor
0364     #define INTEGER_BINARY_OPERATOR_XOR(expr) constexpr friend uint128 operator^(uint128 lhs, expr rhs) noexcept { return {lhs.high, lhs.low ^ static_cast<std::uint64_t>(rhs)}; } // NOLINT
0365 
0366     INTEGER_BINARY_OPERATOR_XOR(char)                   // NOLINT
0367     INTEGER_BINARY_OPERATOR_XOR(signed char)            // NOLINT
0368     INTEGER_BINARY_OPERATOR_XOR(short)                  // NOLINT
0369     INTEGER_BINARY_OPERATOR_XOR(int)                    // NOLINT
0370     INTEGER_BINARY_OPERATOR_XOR(long)                   // NOLINT
0371     INTEGER_BINARY_OPERATOR_XOR(long long)              // NOLINT
0372     INTEGER_BINARY_OPERATOR_XOR(unsigned char)          // NOLINT
0373     INTEGER_BINARY_OPERATOR_XOR(unsigned short)         // NOLINT
0374     INTEGER_BINARY_OPERATOR_XOR(unsigned)               // NOLINT
0375     INTEGER_BINARY_OPERATOR_XOR(unsigned long)          // NOLINT
0376     INTEGER_BINARY_OPERATOR_XOR(unsigned long long)     // NOLINT
0377 
0378     #ifdef BOOST_CHARCONV_HAS_INT128
0379     constexpr friend uint128 operator^(uint128 lhs, boost::int128_type  rhs) noexcept { return lhs ^ uint128(rhs); }
0380     constexpr friend uint128 operator^(uint128 lhs, boost::uint128_type rhs) noexcept { return lhs ^ uint128(rhs); }
0381     #endif
0382 
0383     constexpr friend uint128 operator^(uint128 lhs, uint128 rhs) noexcept;
0384 
0385     BOOST_CHARCONV_CXX14_CONSTEXPR uint128 &operator^=(uint128 v) noexcept;
0386 
0387     #undef INTEGER_BINARY_OPERATOR_XOR
0388 
0389     // Left shift
0390     #define INTEGER_BINARY_OPERATOR_LEFT_SHIFT(expr)                                            \
0391     BOOST_CHARCONV_CXX14_CONSTEXPR friend uint128 operator<<(uint128 lhs, expr rhs) noexcept    \
0392     {                                                                                           \
0393         if (rhs >= 64)                                                                          \
0394         {                                                                                       \
0395             return {lhs.low << (rhs - 64), 0};                                                  \
0396         }                                                                                       \
0397         else if (rhs == 0)                                                                      \
0398         {                                                                                       \
0399             return lhs;                                                                         \
0400         }                                                                                       \
0401                                                                                                 \
0402         return {(lhs.high << rhs) | (lhs.low >> (64 - rhs)), lhs.low << rhs};                   \
0403     } // NOLINT
0404 
0405     INTEGER_BINARY_OPERATOR_LEFT_SHIFT(char)                    // NOLINT
0406     INTEGER_BINARY_OPERATOR_LEFT_SHIFT(signed char)             // NOLINT
0407     INTEGER_BINARY_OPERATOR_LEFT_SHIFT(short)                   // NOLINT
0408     INTEGER_BINARY_OPERATOR_LEFT_SHIFT(int)                     // NOLINT
0409     INTEGER_BINARY_OPERATOR_LEFT_SHIFT(long)                    // NOLINT
0410     INTEGER_BINARY_OPERATOR_LEFT_SHIFT(long long)               // NOLINT
0411     INTEGER_BINARY_OPERATOR_LEFT_SHIFT(unsigned char)           // NOLINT
0412     INTEGER_BINARY_OPERATOR_LEFT_SHIFT(unsigned short)          // NOLINT
0413     INTEGER_BINARY_OPERATOR_LEFT_SHIFT(unsigned)                // NOLINT
0414     INTEGER_BINARY_OPERATOR_LEFT_SHIFT(unsigned long)           // NOLINT
0415     INTEGER_BINARY_OPERATOR_LEFT_SHIFT(unsigned long long)      // NOLINT
0416 
0417     #define INTEGER_BINARY_OPERATOR_EQUALS_LEFT_SHIFT(expr)                     \
0418     BOOST_CHARCONV_CXX14_CONSTEXPR uint128 &operator<<=(expr amount) noexcept   \
0419     {                                                                           \
0420         *this = *this << amount;                                                \
0421         return *this;                                                           \
0422     } // NOLINT
0423 
0424     INTEGER_BINARY_OPERATOR_EQUALS_LEFT_SHIFT(char)                     // NOLINT
0425     INTEGER_BINARY_OPERATOR_EQUALS_LEFT_SHIFT(signed char)              // NOLINT
0426     INTEGER_BINARY_OPERATOR_EQUALS_LEFT_SHIFT(short)                    // NOLINT
0427     INTEGER_BINARY_OPERATOR_EQUALS_LEFT_SHIFT(int)                      // NOLINT
0428     INTEGER_BINARY_OPERATOR_EQUALS_LEFT_SHIFT(long)                     // NOLINT
0429     INTEGER_BINARY_OPERATOR_EQUALS_LEFT_SHIFT(long long)                // NOLINT
0430     INTEGER_BINARY_OPERATOR_EQUALS_LEFT_SHIFT(unsigned char)            // NOLINT
0431     INTEGER_BINARY_OPERATOR_EQUALS_LEFT_SHIFT(unsigned short)           // NOLINT
0432     INTEGER_BINARY_OPERATOR_EQUALS_LEFT_SHIFT(unsigned)                 // NOLINT
0433     INTEGER_BINARY_OPERATOR_EQUALS_LEFT_SHIFT(unsigned long)            // NOLINT
0434     INTEGER_BINARY_OPERATOR_EQUALS_LEFT_SHIFT(unsigned long long)       // NOLINT
0435 
0436     #undef INTEGER_BINARY_OPERATOR_LEFT_SHIFT
0437     #undef INTEGER_BINARY_OPERATOR_EQUALS_LEFT_SHIFT
0438 
0439     // Right Shift
0440     #define INTEGER_BINARY_OPERATOR_RIGHT_SHIFT(expr)                                               \
0441     BOOST_CHARCONV_CXX14_CONSTEXPR friend uint128 operator>>(uint128 lhs, expr amount) noexcept     \
0442     {                                                                                               \
0443         if (amount >= 64)                                                                           \
0444         {                                                                                           \
0445             return {0, lhs.high >> (amount - 64)};                                                  \
0446         }                                                                                           \
0447         else if (amount == 0)                                                                       \
0448         {                                                                                           \
0449             return lhs;                                                                             \
0450         }                                                                                           \
0451                                                                                                     \
0452         return {lhs.high >> amount, (lhs.low >> amount) | (lhs.high << (64 - amount))};             \
0453     } // NOLINT
0454 
0455     INTEGER_BINARY_OPERATOR_RIGHT_SHIFT(char)                   // NOLINT
0456     INTEGER_BINARY_OPERATOR_RIGHT_SHIFT(signed char)            // NOLINT
0457     INTEGER_BINARY_OPERATOR_RIGHT_SHIFT(short)                  // NOLINT
0458     INTEGER_BINARY_OPERATOR_RIGHT_SHIFT(int)                    // NOLINT
0459     INTEGER_BINARY_OPERATOR_RIGHT_SHIFT(long)                   // NOLINT
0460     INTEGER_BINARY_OPERATOR_RIGHT_SHIFT(long long)              // NOLINT
0461     INTEGER_BINARY_OPERATOR_RIGHT_SHIFT(unsigned char)          // NOLINT
0462     INTEGER_BINARY_OPERATOR_RIGHT_SHIFT(unsigned short)         // NOLINT
0463     INTEGER_BINARY_OPERATOR_RIGHT_SHIFT(unsigned)               // NOLINT
0464     INTEGER_BINARY_OPERATOR_RIGHT_SHIFT(unsigned long)          // NOLINT
0465     INTEGER_BINARY_OPERATOR_RIGHT_SHIFT(unsigned long long)     // NOLINT
0466 
0467     #define INTEGER_BINARY_OPERATOR_EQUALS_RIGHT_SHIFT(expr)                        \
0468     BOOST_CHARCONV_CXX14_CONSTEXPR uint128 &operator>>=(expr amount) noexcept       \
0469     {                                                                               \
0470         *this = *this >> amount;                                                    \
0471         return *this;                                                               \
0472     } // NOLINT
0473 
0474     INTEGER_BINARY_OPERATOR_EQUALS_RIGHT_SHIFT(char)                    // NOLINT
0475     INTEGER_BINARY_OPERATOR_EQUALS_RIGHT_SHIFT(signed char)             // NOLINT
0476     INTEGER_BINARY_OPERATOR_EQUALS_RIGHT_SHIFT(short)                   // NOLINT
0477     INTEGER_BINARY_OPERATOR_EQUALS_RIGHT_SHIFT(int)                     // NOLINT
0478     INTEGER_BINARY_OPERATOR_EQUALS_RIGHT_SHIFT(long)                    // NOLINT
0479     INTEGER_BINARY_OPERATOR_EQUALS_RIGHT_SHIFT(long long)               // NOLINT
0480     INTEGER_BINARY_OPERATOR_EQUALS_RIGHT_SHIFT(unsigned char)           // NOLINT
0481     INTEGER_BINARY_OPERATOR_EQUALS_RIGHT_SHIFT(unsigned short)          // NOLINT
0482     INTEGER_BINARY_OPERATOR_EQUALS_RIGHT_SHIFT(unsigned)                // NOLINT
0483     INTEGER_BINARY_OPERATOR_EQUALS_RIGHT_SHIFT(unsigned long)           // NOLINT
0484     INTEGER_BINARY_OPERATOR_EQUALS_RIGHT_SHIFT(unsigned long long)      // NOLINT
0485 
0486     #undef INTEGER_BINARY_OPERATOR_RIGHT_SHIFT
0487     #undef INTEGER_BINARY_OPERATOR_EQUALS_RIGHT_SHIFT
0488 
0489     // Arithmetic operators (Add, sub, mul, div, mod)
0490     inline uint128 &operator+=(std::uint64_t n) noexcept;
0491 
0492     BOOST_CHARCONV_CXX14_CONSTEXPR friend uint128 operator+(uint128 lhs, uint128 rhs) noexcept;
0493 
0494     BOOST_CHARCONV_CXX14_CONSTEXPR uint128 &operator+=(uint128 v) noexcept;
0495 
0496     BOOST_CHARCONV_CXX14_CONSTEXPR uint128 &operator++() noexcept;
0497 
0498     BOOST_CHARCONV_CXX14_CONSTEXPR const uint128 operator++(int) noexcept;
0499 
0500     BOOST_CHARCONV_CXX14_CONSTEXPR friend uint128 operator-(uint128 lhs, uint128 rhs) noexcept;
0501 
0502     BOOST_CHARCONV_CXX14_CONSTEXPR uint128 &operator-=(uint128 v) noexcept;
0503 
0504     BOOST_CHARCONV_CXX14_CONSTEXPR uint128 &operator--() noexcept;
0505 
0506     BOOST_CHARCONV_CXX14_CONSTEXPR const uint128 operator--(int) noexcept;
0507 
0508     BOOST_CHARCONV_CXX14_CONSTEXPR friend uint128 operator*(uint128 lhs, uint128 rhs) noexcept;
0509 
0510     BOOST_CHARCONV_CXX14_CONSTEXPR uint128 &operator*=(uint128 v) noexcept;
0511 
0512     BOOST_CHARCONV_CXX14_CONSTEXPR friend uint128 operator/(uint128 lhs, uint128 rhs) noexcept;
0513 
0514     BOOST_CHARCONV_CXX14_CONSTEXPR uint128 &operator/=(uint128 v) noexcept;
0515 
0516     BOOST_CHARCONV_CXX14_CONSTEXPR friend uint128 operator%(uint128 lhs, uint128 rhs) noexcept;
0517 
0518     BOOST_CHARCONV_CXX14_CONSTEXPR uint128 &operator%=(uint128 v) noexcept;
0519 
0520 private:
0521     BOOST_CHARCONV_CXX14_CONSTEXPR friend int high_bit(uint128 v) noexcept;
0522 
0523     BOOST_CHARCONV_CXX14_CONSTEXPR friend void
0524     div_impl(uint128 lhs, uint128 rhs, uint128 &quotient, uint128 &remainder) noexcept;
0525 };
0526 
0527 constexpr uint128 operator-(uint128 val) noexcept
0528 {
0529     return {~val.high + static_cast<std::uint64_t>(val.low == 0), ~val.low + 1};
0530 }
0531 
0532 constexpr uint128 operator+(uint128 val) noexcept
0533 {
0534     return val;
0535 }
0536 
0537 BOOST_CHARCONV_CXX14_CONSTEXPR uint128 &uint128::operator=(const uint128& v) noexcept // NOLINT : User defined for older compilers
0538 {
0539     low = v.low;
0540     high = v.high;
0541     return *this;
0542 }
0543 
0544 constexpr bool operator==(uint128 lhs, uint128 rhs) noexcept
0545 {
0546     return lhs.high == rhs.high && lhs.low == rhs.low;
0547 }
0548 
0549 constexpr bool operator!=(uint128 lhs, uint128 rhs) noexcept
0550 {
0551     return !(lhs == rhs);
0552 }
0553 
0554 BOOST_CHARCONV_CXX14_CONSTEXPR bool operator<(uint128 lhs, uint128 rhs) noexcept
0555 {
0556     if (lhs.high == rhs.high)
0557     {
0558         return lhs.low < rhs.low;
0559     }
0560 
0561     return lhs.high < rhs.high;
0562 }
0563 
0564 BOOST_CHARCONV_CXX14_CONSTEXPR bool operator<=(uint128 lhs, uint128 rhs) noexcept
0565 {
0566     return !(rhs < lhs);
0567 }
0568 
0569 BOOST_CHARCONV_CXX14_CONSTEXPR bool operator>(uint128 lhs, uint128 rhs) noexcept
0570 {
0571     return rhs < lhs;
0572 }
0573 
0574 BOOST_CHARCONV_CXX14_CONSTEXPR bool operator>=(uint128 lhs, uint128 rhs) noexcept
0575 {
0576     return !(lhs < rhs);
0577 }
0578 
0579 constexpr uint128 operator~(uint128 v) noexcept
0580 {
0581     return {~v.high, ~v.low};
0582 }
0583 
0584 constexpr uint128 operator|(uint128 lhs, uint128 rhs) noexcept
0585 {
0586     return {lhs.high | rhs.high, lhs.low | rhs.low};
0587 }
0588 
0589 BOOST_CHARCONV_CXX14_CONSTEXPR uint128 &uint128::operator|=(uint128 v) noexcept
0590 {
0591     *this = *this | v;
0592     return *this;
0593 }
0594 
0595 constexpr uint128 operator&(uint128 lhs, uint128 rhs) noexcept
0596 {
0597     return {lhs.high & rhs.high, lhs.low & rhs.low};
0598 }
0599 
0600 BOOST_CHARCONV_CXX14_CONSTEXPR uint128 &uint128::operator&=(uint128 v) noexcept
0601 {
0602     *this = *this & v;
0603     return *this;
0604 }
0605 
0606 constexpr uint128 operator^(uint128 lhs, uint128 rhs) noexcept
0607 {
0608     return {lhs.high ^ rhs.high, lhs.low ^ rhs.low};
0609 }
0610 
0611 BOOST_CHARCONV_CXX14_CONSTEXPR uint128 &uint128::operator^=(uint128 v) noexcept
0612 {
0613     *this = *this ^ v;
0614     return *this;
0615 }
0616 
0617 inline uint128 &uint128::operator+=(std::uint64_t n) noexcept
0618 {
0619     #if BOOST_CHARCONV_HAS_BUILTIN(__builtin_addcll)
0620 
0621     unsigned long long carry {};
0622         low = __builtin_addcll(low, n, 0, &carry);
0623         high = __builtin_addcll(high, 0, carry, &carry);
0624 
0625     #elif BOOST_CHARCONV_HAS_BUILTIN(__builtin_ia32_addcarryx_u64)
0626 
0627     unsigned long long result {};
0628         auto carry = __builtin_ia32_addcarryx_u64(0, low, n, &result);
0629         low = result;
0630         __builtin_ia32_addcarryx_u64(carry, high, 0, &result);
0631         high = result;
0632 
0633     #elif defined(BOOST_MSVC) && defined(_M_X64)
0634 
0635     auto carry = _addcarry_u64(0, low, n, &low);
0636         _addcarry_u64(carry, high, 0, &high);
0637 
0638     #else
0639 
0640     auto sum = low + n;
0641     high += (sum < low ? 1 : 0);
0642     low = sum;
0643 
0644     #endif
0645     return *this;
0646 }
0647 
0648 BOOST_CHARCONV_CXX14_CONSTEXPR uint128 operator+(uint128 lhs, uint128 rhs) noexcept
0649 {
0650     const uint128 temp = {lhs.high + rhs.high, lhs.low + rhs.low};
0651 
0652     // Need to carry a bit into rhs
0653     if (temp.low < lhs.low)
0654     {
0655         return {temp.high + 1, temp.low};
0656     }
0657 
0658     return temp;
0659 }
0660 
0661 BOOST_CHARCONV_CXX14_CONSTEXPR uint128 &uint128::operator+=(uint128 v) noexcept
0662 {
0663     *this = *this + v;
0664     return *this;
0665 }
0666 
0667 BOOST_CHARCONV_CXX14_CONSTEXPR uint128 &uint128::operator++() noexcept
0668 {
0669     if (this->low == UINT64_MAX)
0670     {
0671         this->low = 0;
0672         ++this->high;
0673     }
0674     else
0675     {
0676         ++this->low;
0677     }
0678 
0679     return *this;
0680 }
0681 
0682 BOOST_CHARCONV_CXX14_CONSTEXPR const uint128 uint128::operator++(int) noexcept
0683 {
0684     return ++(*this);
0685 }
0686 
0687 BOOST_CHARCONV_CXX14_CONSTEXPR uint128 operator-(uint128 lhs, uint128 rhs) noexcept
0688 {
0689     const uint128 temp {lhs.high - rhs.high, lhs.low - rhs.low};
0690 
0691     // Check for carry
0692     if (lhs.low < rhs.low)
0693     {
0694         return {temp.high - 1, temp.low};
0695     }
0696 
0697     return temp;
0698 }
0699 
0700 BOOST_CHARCONV_CXX14_CONSTEXPR uint128 &uint128::operator-=(uint128 v) noexcept
0701 {
0702     *this = *this - v;
0703     return *this;
0704 }
0705 
0706 BOOST_CHARCONV_CXX14_CONSTEXPR uint128 &uint128::operator--() noexcept
0707 {
0708     if (this->low == 0)
0709     {
0710         this->low = UINT64_MAX;
0711         --this->high;
0712     }
0713     else // NOLINT
0714     {
0715         --this->low;
0716     }
0717 
0718     return *this;
0719 }
0720 
0721 BOOST_CHARCONV_CXX14_CONSTEXPR const uint128 uint128::operator--(int) noexcept
0722 {
0723     return --(*this);
0724 }
0725 BOOST_CHARCONV_CXX14_CONSTEXPR uint128 operator*(uint128 lhs, uint128 rhs) noexcept
0726 {
0727     const auto a = static_cast<std::uint64_t>(lhs.low >> 32);
0728     const auto b = static_cast<std::uint64_t>(lhs.low & UINT32_MAX);
0729     const auto c = static_cast<std::uint64_t>(rhs.low >> 32);
0730     const auto d = static_cast<std::uint64_t>(rhs.low & UINT32_MAX);
0731 
0732     uint128 result { lhs.high * rhs.low + lhs.low * rhs.high + a * c, b * d };
0733     result += uint128(a * d) << 32;
0734     result += uint128(b * c) << 32;
0735     return result;
0736 }
0737 
0738 BOOST_CHARCONV_CXX14_CONSTEXPR uint128 &uint128::operator*=(uint128 v) noexcept
0739 {
0740     *this = *this * v;
0741     return *this;
0742 }
0743 
0744 BOOST_CHARCONV_CXX14_CONSTEXPR int high_bit(uint128 v) noexcept
0745 {
0746     if (v.high != 0)
0747     {
0748         return 127 - boost::core::countl_zero(v.high);
0749     }
0750     else if (v.low != 0)
0751     {
0752         return 63 - boost::core::countl_zero(v.low);
0753     }
0754 
0755     return 0;
0756 }
0757 
0758 // See: https://stackoverflow.com/questions/5386377/division-without-using
0759 BOOST_CHARCONV_CXX14_CONSTEXPR void div_impl(uint128 lhs, uint128 rhs, uint128& quotient, uint128& remainder) noexcept
0760 {
0761     constexpr uint128 one {0, 1};
0762 
0763     if (rhs > lhs)
0764     {
0765         quotient = 0U;
0766         remainder = 0U;
0767     }
0768     else if (lhs == rhs)
0769     {
0770         quotient = 1U;
0771         remainder = 0U;
0772     }
0773 
0774     uint128 denom = rhs;
0775     quotient = 0U;
0776 
0777     std::int32_t shift = high_bit(lhs) - high_bit(rhs);
0778     if (shift < 0)
0779     {
0780         shift = 32 - shift;
0781     }
0782     denom <<= shift;
0783 
0784     for (int i = 0; i <= shift; ++i)
0785     {
0786         quotient <<= 1;
0787         if (lhs >= denom)
0788         {
0789             lhs -= denom;
0790             quotient |= one;
0791         }
0792         denom >>= 1;
0793     }
0794 
0795     remainder = lhs;
0796 }
0797 
0798 BOOST_CHARCONV_CXX14_CONSTEXPR uint128 operator/(uint128 lhs, uint128 rhs) noexcept
0799 {
0800     uint128 quotient {0, 0};
0801     uint128 remainder {0, 0};
0802     div_impl(lhs, rhs, quotient, remainder);
0803 
0804     return quotient;
0805 }
0806 
0807 BOOST_CHARCONV_CXX14_CONSTEXPR uint128 &uint128::operator/=(uint128 v) noexcept
0808 {
0809     *this = *this / v;
0810     return *this;
0811 }
0812 
0813 BOOST_CHARCONV_CXX14_CONSTEXPR uint128 operator%(uint128 lhs, uint128 rhs) noexcept
0814 {
0815     uint128 quotient {0, 0};
0816     uint128 remainder {0, 0};
0817     div_impl(lhs, rhs, quotient, remainder);
0818 
0819     return remainder;
0820 }
0821 
0822 BOOST_CHARCONV_CXX14_CONSTEXPR uint128 &uint128::operator%=(uint128 v) noexcept
0823 {
0824     *this = *this % v;
0825     return *this;
0826 }
0827 
0828 static inline std::uint64_t umul64(std::uint32_t x, std::uint32_t y) noexcept
0829 {
0830     // __emulu is not available on ARM https://learn.microsoft.com/en-us/cpp/intrinsics/emul-emulu?view=msvc-170
0831     #if defined(BOOST_CHARCONV_HAS_MSVC_32BIT_INTRINSICS) && !defined(_M_ARM)
0832 
0833     return __emulu(x, y);
0834 
0835     #else
0836 
0837     return x * static_cast<std::uint64_t>(y);
0838 
0839     #endif
0840 }
0841 
0842 // Get 128-bit result of multiplication of two 64-bit unsigned integers.
0843 BOOST_CHARCONV_SAFEBUFFERS inline uint128 umul128(std::uint64_t x, std::uint64_t y) noexcept 
0844 {
0845     #if defined(BOOST_CHARCONV_HAS_INT128)
0846     
0847     auto result = static_cast<boost::uint128_type>(x) * static_cast<boost::uint128_type>(y);
0848     return {static_cast<std::uint64_t>(result >> 64), static_cast<std::uint64_t>(result)};
0849 
0850     // _umul128 is x64 only https://learn.microsoft.com/en-us/cpp/intrinsics/umul128?view=msvc-170
0851     #elif defined(BOOST_CHARCONV_HAS_MSVC_64BIT_INTRINSICS) && !defined(_M_ARM64)
0852     
0853     unsigned long long high;
0854     std::uint64_t low = _umul128(x, y, &high);
0855     return {static_cast<std::uint64_t>(high), low};
0856     
0857     // https://developer.arm.com/documentation/dui0802/a/A64-General-Instructions/UMULH
0858     #elif defined(_M_ARM64) && !defined(__MINGW32__)
0859 
0860     std::uint64_t high = __umulh(x, y);
0861     std::uint64_t low = x * y;
0862     return {high, low};
0863 
0864     #else
0865     
0866     auto a = static_cast<std::uint32_t>(x >> 32);
0867     auto b = static_cast<std::uint32_t>(x);
0868     auto c = static_cast<std::uint32_t>(y >> 32);
0869     auto d = static_cast<std::uint32_t>(y);
0870 
0871     auto ac = umul64(a, c);
0872     auto bc = umul64(b, c);
0873     auto ad = umul64(a, d);
0874     auto bd = umul64(b, d);
0875 
0876     auto intermediate = (bd >> 32) + static_cast<std::uint32_t>(ad) + static_cast<std::uint32_t>(bc);
0877 
0878     return {ac + (intermediate >> 32) + (ad >> 32) + (bc >> 32),
0879             (intermediate << 32) + static_cast<std::uint32_t>(bd)};
0880     
0881     #endif
0882 }
0883 
0884 BOOST_CHARCONV_SAFEBUFFERS inline std::uint64_t umul128_upper64(std::uint64_t x, std::uint64_t y) noexcept
0885 {
0886     #if defined(BOOST_CHARCONV_HAS_INT128)
0887     
0888     auto result = static_cast<boost::uint128_type>(x) * static_cast<boost::uint128_type>(y);
0889     return static_cast<std::uint64_t>(result >> 64);
0890     
0891     #elif defined(BOOST_CHARCONV_HAS_MSVC_64BIT_INTRINSICS)
0892     
0893     return __umulh(x, y);
0894     
0895     #else
0896     
0897     auto a = static_cast<std::uint32_t>(x >> 32);
0898     auto b = static_cast<std::uint32_t>(x);
0899     auto c = static_cast<std::uint32_t>(y >> 32);
0900     auto d = static_cast<std::uint32_t>(y);
0901 
0902     auto ac = umul64(a, c);
0903     auto bc = umul64(b, c);
0904     auto ad = umul64(a, d);
0905     auto bd = umul64(b, d);
0906 
0907     auto intermediate = (bd >> 32) + static_cast<std::uint32_t>(ad) + static_cast<std::uint32_t>(bc);
0908 
0909     return ac + (intermediate >> 32) + (ad >> 32) + (bc >> 32);
0910     
0911     #endif
0912 }
0913 
0914 // Get upper 128-bits of multiplication of a 64-bit unsigned integer and a 128-bit
0915 // unsigned integer.
0916 BOOST_CHARCONV_SAFEBUFFERS inline uint128 umul192_upper128(std::uint64_t x, uint128 y) noexcept
0917 {
0918     auto r = umul128(x, y.high);
0919     r += umul128_upper64(x, y.low);
0920     return r;
0921 }
0922 
0923 // Get upper 64-bits of multiplication of a 32-bit unsigned integer and a 64-bit
0924 // unsigned integer.
0925 inline std::uint64_t umul96_upper64(std::uint32_t x, std::uint64_t y) noexcept 
0926 {
0927     #if defined(BOOST_CHARCONV_HAS_INT128) || defined(BOOST_CHARCONV_HAS_MSVC_64BIT_INTRINSICS)
0928     
0929     return umul128_upper64(static_cast<std::uint64_t>(x) << 32, y);
0930     
0931     #else
0932     
0933     auto yh = static_cast<std::uint32_t>(y >> 32);
0934     auto yl = static_cast<std::uint32_t>(y);
0935 
0936     auto xyh = umul64(x, yh);
0937     auto xyl = umul64(x, yl);
0938 
0939     return xyh + (xyl >> 32);
0940 
0941     #endif
0942 }
0943 
0944 // Get lower 128-bits of multiplication of a 64-bit unsigned integer and a 128-bit
0945 // unsigned integer.
0946 BOOST_CHARCONV_SAFEBUFFERS inline uint128 umul192_lower128(std::uint64_t x, uint128 y) noexcept
0947 {
0948     auto high = x * y.high;
0949     auto highlow = umul128(x, y.low);
0950     return {high + highlow.high, highlow.low};
0951 }
0952 
0953 // Get lower 64-bits of multiplication of a 32-bit unsigned integer and a 64-bit
0954 // unsigned integer.
0955 inline std::uint64_t umul96_lower64(std::uint32_t x, std::uint64_t y) noexcept 
0956 {
0957     return x * y;
0958 }
0959 
0960 }}} // Namespaces
0961 
0962 // Non-standard libraries may add specializations for library-provided types
0963 namespace std {
0964 
0965 template <>
0966 struct numeric_limits<boost::charconv::detail::uint128>
0967 {
0968     // Member constants
0969     BOOST_ATTRIBUTE_UNUSED static constexpr bool is_specialized = true;
0970     BOOST_ATTRIBUTE_UNUSED static constexpr bool is_signed = false;
0971     BOOST_ATTRIBUTE_UNUSED static constexpr bool is_integer = true;
0972     BOOST_ATTRIBUTE_UNUSED static constexpr bool is_exact = true;
0973     BOOST_ATTRIBUTE_UNUSED static constexpr bool has_infinity = false;
0974     BOOST_ATTRIBUTE_UNUSED static constexpr bool has_quiet_NaN = false;
0975     BOOST_ATTRIBUTE_UNUSED static constexpr bool has_signaling_NaN = false;
0976     BOOST_ATTRIBUTE_UNUSED static constexpr std::float_round_style round_style = std::round_toward_zero;
0977     BOOST_ATTRIBUTE_UNUSED static constexpr bool is_iec559 = false;
0978     BOOST_ATTRIBUTE_UNUSED static constexpr bool is_bounded = true;
0979     BOOST_ATTRIBUTE_UNUSED static constexpr bool is_modulo = true;
0980     BOOST_ATTRIBUTE_UNUSED static constexpr int digits = 128;
0981     BOOST_ATTRIBUTE_UNUSED static constexpr int digits10 = 38;
0982     BOOST_ATTRIBUTE_UNUSED static constexpr int max_digits10 = 0;
0983     BOOST_ATTRIBUTE_UNUSED static constexpr int radix = 2;
0984     BOOST_ATTRIBUTE_UNUSED static constexpr int min_exponent = 0;
0985     BOOST_ATTRIBUTE_UNUSED static constexpr int min_exponent10 = 0;
0986     BOOST_ATTRIBUTE_UNUSED static constexpr int max_exponent = 0;
0987     BOOST_ATTRIBUTE_UNUSED static constexpr int max_exponent10 = 0;
0988     BOOST_ATTRIBUTE_UNUSED static constexpr bool traps = std::numeric_limits<std::uint64_t>::traps;
0989     BOOST_ATTRIBUTE_UNUSED static constexpr bool tinyness_before = false;
0990 
0991     // Member functions
0992     BOOST_ATTRIBUTE_UNUSED static constexpr boost::charconv::detail::uint128 (min)() { return 0; }
0993     BOOST_ATTRIBUTE_UNUSED static constexpr boost::charconv::detail::uint128 lowest() { return 0; }
0994     BOOST_ATTRIBUTE_UNUSED static constexpr boost::charconv::detail::uint128 (max)() { return {UINT64_MAX, UINT64_MAX}; }
0995     BOOST_ATTRIBUTE_UNUSED static constexpr boost::charconv::detail::uint128 epsilon() { return 0; }
0996     BOOST_ATTRIBUTE_UNUSED static constexpr boost::charconv::detail::uint128 round_error() { return 0; }
0997     BOOST_ATTRIBUTE_UNUSED static constexpr boost::charconv::detail::uint128 infinity() { return 0; }
0998     BOOST_ATTRIBUTE_UNUSED static constexpr boost::charconv::detail::uint128 quiet_NaN() { return 0; }
0999     BOOST_ATTRIBUTE_UNUSED static constexpr boost::charconv::detail::uint128 signaling_NaN() { return 0; }
1000     BOOST_ATTRIBUTE_UNUSED static constexpr boost::charconv::detail::uint128 denorm_min() { return 0; }
1001 };
1002 
1003 } // Namespace std
1004 
1005 #endif // BOOST_CHARCONV_DETAIL_EMULATED128_HPP