tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

Int128.h (22517B)


      1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
      2 * vim: set ts=8 sts=2 et sw=2 tw=80:
      3 * This Source Code Form is subject to the terms of the Mozilla Public
      4 * License, v. 2.0. If a copy of the MPL was not distributed with this
      5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      6 
      7 #ifndef vm_Int128_h
      8 #define vm_Int128_h
      9 
     10 #include "mozilla/Assertions.h"
     11 #include "mozilla/EndianUtils.h"
     12 #include "mozilla/MathAlgorithms.h"
     13 
     14 #include <climits>
     15 #include <limits>
     16 #include <stdint.h>
     17 #include <utility>
     18 
     19 namespace js {
     20 
     21 class Int128;
     22 class Uint128;
     23 
     24 /**
     25 * Unsigned 128-bit integer, implemented as a pair of unsigned 64-bit integers.
     26 *
     27 * Supports all basic arithmetic operators.
     28 */
     29 class alignas(16) Uint128 final {
     30 #if MOZ_LITTLE_ENDIAN()
     31  uint64_t low = 0;
     32  uint64_t high = 0;
     33 #else
     34  uint64_t high = 0;
     35  uint64_t low = 0;
     36 #endif
     37 
     38  friend class Int128;
     39 
     40  constexpr Uint128(uint64_t low, uint64_t high) : low(low), high(high) {}
     41 
     42  /**
     43   * Return the high double-word of the multiplication of `u * v`.
     44   *
     45   * Based on "Multiply high unsigned" from Hacker's Delight, 2nd edition,
     46   * figure 8-2.
     47   */
     48  static constexpr uint64_t mulhu(uint64_t u, uint64_t v) {
     49    uint64_t u0 = u & 0xffff'ffff;
     50    uint64_t u1 = u >> 32;
     51 
     52    uint64_t v0 = v & 0xffff'ffff;
     53    uint64_t v1 = v >> 32;
     54 
     55    uint64_t w0 = u0 * v0;
     56    uint64_t t = u1 * v0 + (w0 >> 32);
     57    uint64_t w1 = t & 0xffff'ffff;
     58    uint64_t w2 = t >> 32;
     59    w1 = u0 * v1 + w1;
     60    return u1 * v1 + w2 + (w1 >> 32);
     61  }
     62 
     63  /**
     64   * Based on "Unsigned doubleword division from long division" from
     65   * Hacker's Delight, 2nd edition, figure 9-5.
     66   */
     67  static constexpr std::pair<Uint128, Uint128> udivdi(const Uint128& u,
     68                                                      const Uint128& v) {
     69    MOZ_ASSERT(v != Uint128{});
     70 
     71    // If v < 2**64
     72    if (v.high == 0) {
     73      // If u < 2**64
     74      if (u.high == 0) {
     75        // Prefer built-in division if possible.
     76        return {Uint128{u.low / v.low, 0}, Uint128{u.low % v.low, 0}};
     77      }
     78 
     79      // If u/v cannot overflow, just do one division.
     80      if (Uint128{u.high, 0} < v) {
     81        auto [q, r] = divlu(u.high, u.low, v.low);
     82        return {Uint128{q, 0}, Uint128{r, 0}};
     83      }
     84 
     85      // If u/v would overflow: Break u up into two halves.
     86 
     87      // First quotient digit and first remainder, < v.
     88      auto [q1, r1] = divlu(0, u.high, v.low);
     89 
     90      // Second quotient digit.
     91      auto [q0, r0] = divlu(r1, u.low, v.low);
     92 
     93      // Return quotient and remainder.
     94      return {Uint128{q0, q1}, Uint128{r0, 0}};
     95    }
     96 
     97    // Here v >= 2**64.
     98 
     99    // 0 <= n <= 63
    100    auto n = mozilla::CountLeadingZeroes64(v.high);
    101 
    102    // Normalize the divisor so its MSB is 1.
    103    auto v1 = (v << n).high;
    104 
    105    // To ensure no overflow.
    106    auto u1 = u >> 1;
    107 
    108    // Get quotient from divide unsigned instruction.
    109    auto [q1, r1] = divlu(u1.high, u1.low, v1);
    110 
    111    // Undo normalization and division of u by 2.
    112    auto q0 = (Uint128{q1, 0} << n) >> 63;
    113 
    114    // Make q0 correct or too small by 1.
    115    if (q0 != Uint128{0}) {
    116      q0 -= Uint128{1};
    117    }
    118 
    119    // Now q0 is correct.
    120    auto r0 = u - q0 * v;
    121    if (r0 >= v) {
    122      q0 += Uint128{1};
    123      r0 -= v;
    124    }
    125 
    126    // Return quotient and remainder.
    127    return {q0, r0};
    128  }
    129 
    130  /**
    131   * Based on "Divide long unsigned, using fullword division instructions" from
    132   * Hacker's Delight, 2nd edition, figure 9-3.
    133   */
    134  static constexpr std::pair<uint64_t, uint64_t> divlu(uint64_t u1, uint64_t u0,
    135                                                       uint64_t v) {
    136    // Number base (32 bits).
    137    constexpr uint64_t base = 4294967296;
    138 
    139    // If overflow, set the remainder to an impossible value and return the
    140    // largest possible quotient.
    141    if (u1 >= v) {
    142      return {UINT64_MAX, UINT64_MAX};
    143    }
    144 
    145    // Shift amount for normalization. (0 <= s <= 63)
    146    int64_t s = mozilla::CountLeadingZeroes64(v);
    147 
    148    // Normalize the divisor.
    149    v = v << s;
    150 
    151    // Normalized divisor digits.
    152    //
    153    // Break divisor up into two 32-bit digits.
    154    uint64_t vn1 = v >> 32;
    155    uint64_t vn0 = uint32_t(v);
    156 
    157    // Dividend digit pairs.
    158    //
    159    // Shift dividend left.
    160    uint64_t un32 = (u1 << s) | ((u0 >> ((64 - s) & 63)) & (-s >> 63));
    161    uint64_t un10 = u0 << s;
    162 
    163    // Normalized dividend least significant digits.
    164    //
    165    // Break right half of dividend into two digits.
    166    uint64_t un1 = un10 >> 32;
    167    uint64_t un0 = uint32_t(un10);
    168 
    169    // Compute the first quotient digit and its remainder.
    170    uint64_t q1 = un32 / vn1;
    171    uint64_t rhat = un32 - q1 * vn1;
    172    while (q1 >= base || q1 * vn0 > base * rhat + un1) {
    173      q1 -= 1;
    174      rhat += vn1;
    175      if (rhat >= base) {
    176        break;
    177      }
    178    }
    179 
    180    // Multiply and subtract.
    181    uint64_t un21 = un32 * base + un1 - q1 * v;
    182 
    183    // Compute the second quotient digit and its remainder.
    184    uint64_t q0 = un21 / vn1;
    185    rhat = un21 - q0 * vn1;
    186    while (q0 >= base || q0 * vn0 > base * rhat + un0) {
    187      q0 -= 1;
    188      rhat += vn1;
    189      if (rhat >= base) {
    190        break;
    191      }
    192    }
    193 
    194    // Return the quotient and remainder.
    195    uint64_t q = q1 * base + q0;
    196    uint64_t r = (un21 * base + un0 - q0 * v) >> s;
    197    return {q, r};
    198  }
    199 
    200  static double toDouble(const Uint128& x, bool negative);
    201 
    202 public:
    203  constexpr Uint128() = default;
    204  constexpr Uint128(const Uint128&) = default;
    205 
    206  explicit constexpr Uint128(int value)
    207      : Uint128(uint64_t(value), uint64_t(value < 0 ? -1 : 0)) {}
    208  explicit constexpr Uint128(long value)
    209      : Uint128(uint64_t(value), uint64_t(value < 0 ? -1 : 0)) {}
    210  explicit constexpr Uint128(long long value)
    211      : Uint128(uint64_t(value), uint64_t(value < 0 ? -1 : 0)) {}
    212 
    213  explicit constexpr Uint128(unsigned int value)
    214      : Uint128(uint64_t(value), uint64_t(0)) {}
    215  explicit constexpr Uint128(unsigned long value)
    216      : Uint128(uint64_t(value), uint64_t(0)) {}
    217  explicit constexpr Uint128(unsigned long long value)
    218      : Uint128(uint64_t(value), uint64_t(0)) {}
    219 
    220  constexpr bool operator==(const Uint128& other) const {
    221    return low == other.low && high == other.high;
    222  }
    223 
    224  constexpr bool operator<(const Uint128& other) const {
    225    if (high == other.high) {
    226      return low < other.low;
    227    }
    228    return high < other.high;
    229  }
    230 
    231  // Other operators are implemented in terms of operator== and operator<.
    232  constexpr bool operator!=(const Uint128& other) const {
    233    return !(*this == other);
    234  }
    235  constexpr bool operator>(const Uint128& other) const { return other < *this; }
    236  constexpr bool operator<=(const Uint128& other) const {
    237    return !(other < *this);
    238  }
    239  constexpr bool operator>=(const Uint128& other) const {
    240    return !(*this < other);
    241  }
    242 
    243  explicit constexpr operator bool() const { return !(*this == Uint128{}); }
    244 
    245  explicit constexpr operator int8_t() const { return int8_t(low); }
    246  explicit constexpr operator int16_t() const { return int16_t(low); }
    247  explicit constexpr operator int32_t() const { return int32_t(low); }
    248  explicit constexpr operator int64_t() const { return int64_t(low); }
    249 
    250  explicit constexpr operator uint8_t() const { return uint8_t(low); }
    251  explicit constexpr operator uint16_t() const { return uint16_t(low); }
    252  explicit constexpr operator uint32_t() const { return uint32_t(low); }
    253  explicit constexpr operator uint64_t() const { return uint64_t(low); }
    254 
    255  explicit constexpr operator Int128() const;
    256 
    257  explicit operator double() const { return toDouble(*this, false); }
    258 
    259  constexpr Uint128 operator+(const Uint128& other) const {
    260    // "ยง2-16 Double-Length Add/Subtract" from Hacker's Delight, 2nd edition.
    261    Uint128 result;
    262    result.low = low + other.low;
    263    result.high = high + other.high + static_cast<uint64_t>(result.low < low);
    264    return result;
    265  }
    266 
    267  constexpr Uint128 operator-(const Uint128& other) const {
    268    // "ยง2-16 Double-Length Add/Subtract" from Hacker's Delight, 2nd edition.
    269    Uint128 result;
    270    result.low = low - other.low;
    271    result.high = high - other.high - static_cast<uint64_t>(low < other.low);
    272    return result;
    273  }
    274 
    275  constexpr Uint128 operator*(const Uint128& other) const {
    276    uint64_t w01 = low * other.high;
    277    uint64_t w10 = high * other.low;
    278    uint64_t w00 = mulhu(low, other.low);
    279 
    280    uint64_t w1 = w00 + w10 + w01;
    281    uint64_t w0 = low * other.low;
    282 
    283    return Uint128{w0, w1};
    284  }
    285 
    286  /**
    287   * Return the quotient and remainder of the division.
    288   */
    289  constexpr std::pair<Uint128, Uint128> divrem(const Uint128& divisor) const {
    290    return udivdi(*this, divisor);
    291  }
    292 
    293  constexpr Uint128 operator/(const Uint128& other) const {
    294    auto [quot, rem] = divrem(other);
    295    return quot;
    296  }
    297 
    298  constexpr Uint128 operator%(const Uint128& other) const {
    299    auto [quot, rem] = divrem(other);
    300    return rem;
    301  }
    302 
    303  constexpr Uint128 operator<<(int shift) const {
    304    MOZ_ASSERT(0 <= shift && shift <= 127, "undefined shift amount");
    305 
    306    // Ensure the shift amount is in range.
    307    shift &= 127;
    308 
    309    // "ยง2-17 Double-Length Shifts" from Hacker's Delight, 2nd edition.
    310    if (shift >= 64) {
    311      uint64_t y0 = 0;
    312      uint64_t y1 = low << (shift - 64);
    313      return Uint128{y0, y1};
    314    }
    315    if (shift > 0) {
    316      uint64_t y0 = low << shift;
    317      uint64_t y1 = high << shift | low >> (64 - shift);
    318      return Uint128{y0, y1};
    319    }
    320    return *this;
    321  }
    322 
    323  constexpr Uint128 operator>>(int shift) const {
    324    MOZ_ASSERT(0 <= shift && shift <= 127, "undefined shift amount");
    325 
    326    // Ensure the shift amount is in range.
    327    shift &= 127;
    328 
    329    // "ยง2-17 Double-Length Shifts" from Hacker's Delight, 2nd edition.
    330    if (shift >= 64) {
    331      uint64_t y0 = high >> (shift - 64);
    332      uint64_t y1 = 0;
    333      return Uint128{y0, y1};
    334    }
    335    if (shift > 0) {
    336      uint64_t y0 = low >> shift | high << (64 - shift);
    337      uint64_t y1 = high >> shift;
    338      return Uint128{y0, y1};
    339    }
    340    return *this;
    341  }
    342 
    343  constexpr Uint128 operator&(const Uint128& other) const {
    344    return Uint128{low & other.low, high & other.high};
    345  }
    346 
    347  constexpr Uint128 operator|(const Uint128& other) const {
    348    return Uint128{low | other.low, high | other.high};
    349  }
    350 
    351  constexpr Uint128 operator^(const Uint128& other) const {
    352    return Uint128{low ^ other.low, high ^ other.high};
    353  }
    354 
    355  constexpr Uint128 operator~() const { return Uint128{~low, ~high}; }
    356 
    357  constexpr Uint128 operator-() const { return Uint128{} - *this; }
    358 
    359  constexpr Uint128 operator+() const { return *this; }
    360 
    361  constexpr Uint128& operator++() {
    362    *this = *this + Uint128{1, 0};
    363    return *this;
    364  }
    365 
    366  constexpr Uint128 operator++(int) {
    367    auto result = *this;
    368    ++*this;
    369    return result;
    370  }
    371 
    372  constexpr Uint128& operator--() {
    373    *this = *this - Uint128{1, 0};
    374    return *this;
    375  }
    376 
    377  constexpr Uint128 operator--(int) {
    378    auto result = *this;
    379    --*this;
    380    return result;
    381  }
    382 
    383  constexpr Uint128 operator+=(const Uint128& other) {
    384    *this = *this + other;
    385    return *this;
    386  }
    387 
    388  constexpr Uint128 operator-=(const Uint128& other) {
    389    *this = *this - other;
    390    return *this;
    391  }
    392 
    393  constexpr Uint128 operator*=(const Uint128& other) {
    394    *this = *this * other;
    395    return *this;
    396  }
    397 
    398  constexpr Uint128 operator/=(const Uint128& other) {
    399    *this = *this / other;
    400    return *this;
    401  }
    402 
    403  constexpr Uint128 operator%=(const Uint128& other) {
    404    *this = *this % other;
    405    return *this;
    406  }
    407 
    408  constexpr Uint128 operator&=(const Uint128& other) {
    409    *this = *this & other;
    410    return *this;
    411  }
    412 
    413  constexpr Uint128 operator|=(const Uint128& other) {
    414    *this = *this | other;
    415    return *this;
    416  }
    417 
    418  constexpr Uint128 operator^=(const Uint128& other) {
    419    *this = *this ^ other;
    420    return *this;
    421  }
    422 
    423  constexpr Uint128 operator<<=(int shift) {
    424    *this = *this << shift;
    425    return *this;
    426  }
    427 
    428  constexpr Uint128 operator>>=(int shift) {
    429    *this = *this >> shift;
    430    return *this;
    431  }
    432 };
    433 
    434 /**
    435 * Signed 128-bit integer, implemented as a pair of unsigned 64-bit integers.
    436 *
    437 * Supports all basic arithmetic operators.
    438 */
    439 class alignas(16) Int128 final {
    440 #if MOZ_LITTLE_ENDIAN()
    441  uint64_t low = 0;
    442  uint64_t high = 0;
    443 #else
    444  uint64_t high = 0;
    445  uint64_t low = 0;
    446 #endif
    447 
    448  friend class Uint128;
    449 
    450  constexpr Int128(uint64_t low, uint64_t high) : low(low), high(high) {}
    451 
    452  /**
    453   * Based on "Signed doubleword division from unsigned doubleword division"
    454   * from Hacker's Delight, 2nd edition, figure 9-6.
    455   */
    456  static constexpr std::pair<Int128, Int128> divdi(const Int128& u,
    457                                                   const Int128& v) {
    458    auto [q, r] = Uint128::udivdi(u.abs(), v.abs());
    459 
    460    // If u and v have different signs, negate q.
    461    // If is negative, negate r.
    462    auto t = static_cast<Uint128>((u ^ v) >> 127);
    463    auto s = static_cast<Uint128>(u >> 127);
    464    return {static_cast<Int128>((q ^ t) - t), static_cast<Int128>((r ^ s) - s)};
    465  }
    466 
    467 public:
    468  constexpr Int128() = default;
    469  constexpr Int128(const Int128&) = default;
    470 
    471  explicit constexpr Int128(int value)
    472      : Int128(uint64_t(value), uint64_t(value < 0 ? -1 : 0)) {}
    473  explicit constexpr Int128(long value)
    474      : Int128(uint64_t(value), uint64_t(value < 0 ? -1 : 0)) {}
    475  explicit constexpr Int128(long long value)
    476      : Int128(uint64_t(value), uint64_t(value < 0 ? -1 : 0)) {}
    477 
    478  explicit constexpr Int128(unsigned int value)
    479      : Int128(uint64_t(value), uint64_t(0)) {}
    480  explicit constexpr Int128(unsigned long value)
    481      : Int128(uint64_t(value), uint64_t(0)) {}
    482  explicit constexpr Int128(unsigned long long value)
    483      : Int128(uint64_t(value), uint64_t(0)) {}
    484 
    485  /**
    486   * Return the quotient and remainder of the division.
    487   */
    488  constexpr std::pair<Int128, Int128> divrem(const Int128& divisor) const {
    489    return divdi(*this, divisor);
    490  }
    491 
    492  /**
    493   * Return the absolute value of this integer.
    494   */
    495  constexpr Uint128 abs() const {
    496    if (*this >= Int128{}) {
    497      return Uint128{low, high};
    498    }
    499    auto neg = -*this;
    500    return Uint128{neg.low, neg.high};
    501  }
    502 
    503  constexpr bool operator==(const Int128& other) const {
    504    return low == other.low && high == other.high;
    505  }
    506 
    507  constexpr bool operator<(const Int128& other) const {
    508    if (high == other.high) {
    509      return low < other.low;
    510    }
    511    return int64_t(high) < int64_t(other.high);
    512  }
    513 
    514  // Other operators are implemented in terms of operator== and operator<.
    515  constexpr bool operator!=(const Int128& other) const {
    516    return !(*this == other);
    517  }
    518  constexpr bool operator>(const Int128& other) const { return other < *this; }
    519  constexpr bool operator<=(const Int128& other) const {
    520    return !(other < *this);
    521  }
    522  constexpr bool operator>=(const Int128& other) const {
    523    return !(*this < other);
    524  }
    525 
    526  explicit constexpr operator bool() const { return !(*this == Int128{}); }
    527 
    528  explicit constexpr operator int8_t() const { return int8_t(low); }
    529  explicit constexpr operator int16_t() const { return int16_t(low); }
    530  explicit constexpr operator int32_t() const { return int32_t(low); }
    531  explicit constexpr operator int64_t() const { return int64_t(low); }
    532 
    533  explicit constexpr operator uint8_t() const { return uint8_t(low); }
    534  explicit constexpr operator uint16_t() const { return uint16_t(low); }
    535  explicit constexpr operator uint32_t() const { return uint32_t(low); }
    536  explicit constexpr operator uint64_t() const { return uint64_t(low); }
    537 
    538  explicit constexpr operator Uint128() const { return Uint128{low, high}; }
    539 
    540  explicit operator double() const {
    541    return Uint128::toDouble(abs(), *this < Int128{0});
    542  }
    543 
    544  constexpr Int128 operator+(const Int128& other) const {
    545    return Int128{Uint128{*this} + Uint128{other}};
    546  }
    547 
    548  constexpr Int128 operator-(const Int128& other) const {
    549    return Int128{Uint128{*this} - Uint128{other}};
    550  }
    551 
    552  constexpr Int128 operator*(const Int128& other) const {
    553    return Int128{Uint128{*this} * Uint128{other}};
    554  }
    555 
    556  constexpr Int128 operator/(const Int128& other) const {
    557    auto [quot, rem] = divrem(other);
    558    return quot;
    559  }
    560 
    561  constexpr Int128 operator%(const Int128& other) const {
    562    auto [quot, rem] = divrem(other);
    563    return rem;
    564  }
    565 
    566  constexpr Int128 operator<<(int shift) const {
    567    return Int128{Uint128{*this} << shift};
    568  }
    569 
    570  constexpr Int128 operator>>(int shift) const {
    571    MOZ_ASSERT(0 <= shift && shift <= 127, "undefined shift amount");
    572 
    573    // Ensure the shift amount is in range.
    574    shift &= 127;
    575 
    576    // "ยง2-17 Double-Length Shifts" from Hacker's Delight, 2nd edition.
    577    if (shift >= 64) {
    578      uint64_t y0 = uint64_t(int64_t(high) >> (shift - 64));
    579      uint64_t y1 = uint64_t(int64_t(high) >> 63);
    580      return Int128{y0, y1};
    581    }
    582    if (shift > 0) {
    583      uint64_t y0 = low >> shift | high << (64 - shift);
    584      uint64_t y1 = uint64_t(int64_t(high) >> shift);
    585      return Int128{y0, y1};
    586    }
    587    return *this;
    588  }
    589 
    590  constexpr Int128 operator&(const Int128& other) const {
    591    return Int128{low & other.low, high & other.high};
    592  }
    593 
    594  constexpr Int128 operator|(const Int128& other) const {
    595    return Int128{low | other.low, high | other.high};
    596  }
    597 
    598  constexpr Int128 operator^(const Int128& other) const {
    599    return Int128{low ^ other.low, high ^ other.high};
    600  }
    601 
    602  constexpr Int128 operator~() const { return Int128{~low, ~high}; }
    603 
    604  constexpr Int128 operator-() const { return Int128{} - *this; }
    605 
    606  constexpr Int128 operator+() const { return *this; }
    607 
    608  constexpr Int128& operator++() {
    609    *this = *this + Int128{1, 0};
    610    return *this;
    611  }
    612 
    613  constexpr Int128 operator++(int) {
    614    auto result = *this;
    615    ++*this;
    616    return result;
    617  }
    618 
    619  constexpr Int128& operator--() {
    620    *this = *this - Int128{1, 0};
    621    return *this;
    622  }
    623 
    624  constexpr Int128 operator--(int) {
    625    auto result = *this;
    626    --*this;
    627    return result;
    628  }
    629 
    630  constexpr Int128 operator+=(const Int128& other) {
    631    *this = *this + other;
    632    return *this;
    633  }
    634 
    635  constexpr Int128 operator-=(const Int128& other) {
    636    *this = *this - other;
    637    return *this;
    638  }
    639 
    640  constexpr Int128 operator*=(const Int128& other) {
    641    *this = *this * other;
    642    return *this;
    643  }
    644 
    645  constexpr Int128 operator/=(const Int128& other) {
    646    *this = *this / other;
    647    return *this;
    648  }
    649 
    650  constexpr Int128 operator%=(const Int128& other) {
    651    *this = *this % other;
    652    return *this;
    653  }
    654 
    655  constexpr Int128 operator&=(const Int128& other) {
    656    *this = *this & other;
    657    return *this;
    658  }
    659 
    660  constexpr Int128 operator|=(const Int128& other) {
    661    *this = *this | other;
    662    return *this;
    663  }
    664 
    665  constexpr Int128 operator^=(const Int128& other) {
    666    *this = *this ^ other;
    667    return *this;
    668  }
    669 
    670  constexpr Int128 operator<<=(int shift) {
    671    *this = *this << shift;
    672    return *this;
    673  }
    674 
    675  constexpr Int128 operator>>=(int shift) {
    676    *this = *this >> shift;
    677    return *this;
    678  }
    679 };
    680 
    681 constexpr Uint128::operator Int128() const { return Int128{low, high}; }
    682 
    683 } /* namespace js */
    684 
    685 template <>
    686 class std::numeric_limits<js::Int128> {
    687 public:
    688  static constexpr bool is_specialized = true;
    689  static constexpr bool is_signed = true;
    690  static constexpr bool is_integer = true;
    691  static constexpr bool is_exact = true;
    692  static constexpr bool has_infinity = false;
    693  static constexpr bool has_quiet_NaN = false;
    694  static constexpr bool has_signaling_NaN = false;
    695  static constexpr std::float_denorm_style has_denorm = std::denorm_absent;
    696  static constexpr bool has_denorm_loss = false;
    697  static constexpr std::float_round_style round_style = std::round_toward_zero;
    698  static constexpr bool is_iec559 = false;
    699  static constexpr bool is_bounded = true;
    700  static constexpr bool is_modulo = true;
    701  static constexpr int digits = CHAR_BIT * sizeof(js::Int128) - 1;
    702  static constexpr int digits10 = int(digits * /* std::log10(2) */ 0.30102999);
    703  static constexpr int max_digits10 = 0;
    704  static constexpr int radix = 2;
    705  static constexpr int min_exponent = 0;
    706  static constexpr int min_exponent10 = 0;
    707  static constexpr int max_exponent = 0;
    708  static constexpr int max_exponent10 = 0;
    709  static constexpr bool traps = true;
    710  static constexpr bool tinyness_before = false;
    711 
    712  static constexpr auto min() noexcept { return js::Int128{1} << 127; }
    713  static constexpr auto lowest() noexcept { return min(); }
    714  static constexpr auto max() noexcept { return ~min(); }
    715  static constexpr auto epsilon() noexcept { return js::Int128{}; }
    716  static constexpr auto round_error() noexcept { return js::Int128{}; }
    717  static constexpr auto infinity() noexcept { return js::Int128{}; }
    718  static constexpr auto quiet_NaN() noexcept { return js::Int128{}; }
    719  static constexpr auto signaling_NaN() noexcept { return js::Int128{}; }
    720  static constexpr auto denorm_min() noexcept { return js::Int128{}; }
    721 };
    722 
    723 template <>
    724 class std::numeric_limits<js::Uint128> {
    725 public:
    726  static constexpr bool is_specialized = true;
    727  static constexpr bool is_signed = false;
    728  static constexpr bool is_integer = true;
    729  static constexpr bool is_exact = true;
    730  static constexpr bool has_infinity = false;
    731  static constexpr bool has_quiet_NaN = false;
    732  static constexpr bool has_signaling_NaN = false;
    733  static constexpr std::float_denorm_style has_denorm = std::denorm_absent;
    734  static constexpr bool has_denorm_loss = false;
    735  static constexpr std::float_round_style round_style = std::round_toward_zero;
    736  static constexpr bool is_iec559 = false;
    737  static constexpr bool is_bounded = true;
    738  static constexpr bool is_modulo = true;
    739  static constexpr int digits = CHAR_BIT * sizeof(js::Uint128);
    740  static constexpr int digits10 = int(digits * /* std::log10(2) */ 0.30102999);
    741  static constexpr int max_digits10 = 0;
    742  static constexpr int radix = 2;
    743  static constexpr int min_exponent = 0;
    744  static constexpr int min_exponent10 = 0;
    745  static constexpr int max_exponent = 0;
    746  static constexpr int max_exponent10 = 0;
    747  static constexpr bool traps = true;
    748  static constexpr bool tinyness_before = false;
    749 
    750  static constexpr auto min() noexcept { return js::Uint128{}; }
    751  static constexpr auto lowest() noexcept { return min(); }
    752  static constexpr auto max() noexcept { return ~js::Uint128{}; }
    753  static constexpr auto epsilon() noexcept { return js::Uint128{}; }
    754  static constexpr auto round_error() noexcept { return js::Uint128{}; }
    755  static constexpr auto infinity() noexcept { return js::Uint128{}; }
    756  static constexpr auto quiet_NaN() noexcept { return js::Uint128{}; }
    757  static constexpr auto signaling_NaN() noexcept { return js::Uint128{}; }
    758  static constexpr auto denorm_min() noexcept { return js::Uint128{}; }
    759 };
    760 
    761 #endif /* vm_Int128_h */