LCOV - code coverage report
Current view: top level - json/detail/dragonbox - emulated128.hpp (source / functions) Coverage Total Hit
Test: coverage_filtered.info Lines: 81.8 % 22 18
Test Date: 2025-12-23 16:57:37 Functions: 83.3 % 6 5

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

Generated by: LCOV version 2.1