tor-browser

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

BigInt.h (7697B)


      1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* This Source Code Form is subject to the terms of the Mozilla Public
      3 * License, v. 2.0. If a copy of the MPL was not distributed with this
      4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      5 
      6 /* BigInt. */
      7 
      8 #ifndef js_BigInt_h
      9 #define js_BigInt_h
     10 
     11 #include "mozilla/Span.h"  // mozilla::Span
     12 
     13 #include <limits>       // std::numeric_limits
     14 #include <stdint.h>     // int64_t, uint64_t
     15 #include <type_traits>  // std::enable_if_t, std::{true,false}_type, std::is_{integral,signed,unsigned}_v
     16 
     17 #include "jstypes.h"  // JS_PUBLIC_API
     18 #include "js/TypeDecls.h"
     19 
     20 namespace mozilla {
     21 template <typename T>
     22 class Range;
     23 }
     24 
     25 namespace JS {
     26 
     27 class JS_PUBLIC_API BigInt;
     28 
     29 namespace detail {
     30 
     31 using Int64Limits = std::numeric_limits<int64_t>;
     32 using Uint64Limits = std::numeric_limits<uint64_t>;
     33 
     34 extern JS_PUBLIC_API BigInt* BigIntFromInt64(JSContext* cx, int64_t num);
     35 extern JS_PUBLIC_API BigInt* BigIntFromUint64(JSContext* cx, uint64_t num);
     36 extern JS_PUBLIC_API BigInt* BigIntFromBool(JSContext* cx, bool b);
     37 
     38 template <typename T, typename = void>
     39 struct NumberToBigIntConverter;
     40 
     41 template <typename SignedIntT>
     42 struct NumberToBigIntConverter<
     43    SignedIntT,
     44    std::enable_if_t<
     45        std::is_integral_v<SignedIntT> && std::is_signed_v<SignedIntT> &&
     46        Int64Limits::min() <= std::numeric_limits<SignedIntT>::min() &&
     47        std::numeric_limits<SignedIntT>::max() <= Int64Limits::max()>> {
     48  static BigInt* convert(JSContext* cx, SignedIntT num) {
     49    return BigIntFromInt64(cx, num);
     50  }
     51 };
     52 
     53 template <typename UnsignedIntT>
     54 struct NumberToBigIntConverter<
     55    UnsignedIntT,
     56    std::enable_if_t<
     57        std::is_integral_v<UnsignedIntT> && std::is_unsigned_v<UnsignedIntT> &&
     58        std::numeric_limits<UnsignedIntT>::max() <= Uint64Limits::max()>> {
     59  static BigInt* convert(JSContext* cx, UnsignedIntT num) {
     60    return BigIntFromUint64(cx, num);
     61  }
     62 };
     63 
     64 template <>
     65 struct NumberToBigIntConverter<bool> {
     66  static BigInt* convert(JSContext* cx, bool b) {
     67    return BigIntFromBool(cx, b);
     68  }
     69 };
     70 
     71 extern JS_PUBLIC_API bool BigIntIsInt64(const BigInt* bi, int64_t* result);
     72 extern JS_PUBLIC_API bool BigIntIsUint64(const BigInt* bi, uint64_t* result);
     73 
     74 template <typename T, typename = void>
     75 struct BigIntToNumberChecker;
     76 
     77 template <typename SignedIntT>
     78 struct BigIntToNumberChecker<
     79    SignedIntT,
     80    std::enable_if_t<
     81        std::is_integral_v<SignedIntT> && std::is_signed_v<SignedIntT> &&
     82        Int64Limits::min() <= std::numeric_limits<SignedIntT>::min() &&
     83        std::numeric_limits<SignedIntT>::max() <= Int64Limits::max()>> {
     84  using TypeLimits = std::numeric_limits<SignedIntT>;
     85 
     86  static bool fits(const BigInt* bi, SignedIntT* result) {
     87    int64_t innerResult;
     88    if (!BigIntIsInt64(bi, &innerResult)) {
     89      return false;
     90    }
     91    if (TypeLimits::min() <= innerResult && innerResult <= TypeLimits::max()) {
     92      *result = SignedIntT(innerResult);
     93      return true;
     94    }
     95    return false;
     96  }
     97 };
     98 
     99 template <typename UnsignedIntT>
    100 struct BigIntToNumberChecker<
    101    UnsignedIntT,
    102    std::enable_if_t<
    103        std::is_integral_v<UnsignedIntT> && std::is_unsigned_v<UnsignedIntT> &&
    104        std::numeric_limits<UnsignedIntT>::max() <= Uint64Limits::max()>> {
    105  static bool fits(const BigInt* bi, UnsignedIntT* result) {
    106    uint64_t innerResult;
    107    if (!BigIntIsUint64(bi, &innerResult)) {
    108      return false;
    109    }
    110    if (innerResult <= std::numeric_limits<UnsignedIntT>::max()) {
    111      *result = UnsignedIntT(innerResult);
    112      return true;
    113    }
    114    return false;
    115  }
    116 };
    117 
    118 }  // namespace detail
    119 
    120 /**
    121 * Create a BigInt from an integer value. All integral types not larger than 64
    122 * bits in size are supported.
    123 */
    124 template <typename NumericT>
    125 static inline BigInt* NumberToBigInt(JSContext* cx, NumericT val) {
    126  return detail::NumberToBigIntConverter<NumericT>::convert(cx, val);
    127 }
    128 
    129 /**
    130 * Create a BigInt from a floating-point value. If the number isn't integral
    131 * (that is, if it's NaN, an infinity, or contains a fractional component),
    132 * this function returns null and throws an exception.
    133 *
    134 * Passing -0.0 will produce the bigint 0n.
    135 */
    136 extern JS_PUBLIC_API BigInt* NumberToBigInt(JSContext* cx, double num);
    137 
    138 /**
    139 * Create a BigInt by parsing a string using the ECMAScript StringToBigInt
    140 * algorithm (https://tc39.es/ecma262/#sec-stringtobigint). Latin1 and two-byte
    141 * character ranges are supported. It may be convenient to use
    142 * JS::ConstLatin1Chars or JS::ConstTwoByteChars.
    143 *
    144 * (StringToBigInt performs parsing similar to that performed by the |Number|
    145 * global function when passed a string, but it doesn't allow infinities,
    146 * decimal points, or exponential notation, and neither algorithm allows numeric
    147 * separators or an 'n' suffix character. This fast-and-loose description is
    148 * offered purely as a convenience to the reader: see the specification
    149 * algorithm for exact behavior.)
    150 *
    151 * If parsing fails, this function returns null and throws an exception.
    152 */
    153 extern JS_PUBLIC_API BigInt* StringToBigInt(
    154    JSContext* cx, const mozilla::Range<const Latin1Char>& chars);
    155 
    156 extern JS_PUBLIC_API BigInt* StringToBigInt(
    157    JSContext* cx, const mozilla::Range<const char16_t>& chars);
    158 
    159 /**
    160 * Create a BigInt by parsing a string consisting of an optional sign character
    161 * followed by one or more alphanumeric ASCII digits in the provided radix.
    162 *
    163 * If the radix is not in the range [2, 36], or the string fails to parse, this
    164 * function returns null and throws an exception.
    165 */
    166 extern JS_PUBLIC_API BigInt* SimpleStringToBigInt(
    167    JSContext* cx, mozilla::Span<const char> chars, uint8_t radix);
    168 
    169 /**
    170 * Convert a JS::Value to a BigInt using the ECMAScript ToBigInt algorithm
    171 * (https://tc39.es/ecma262/#sec-tobigint).
    172 *
    173 * (Note in particular that this will throw if passed a value whose type is
    174 * 'number'. To convert a number to a BigInt, use one of the overloads of
    175 * JS::NumberToBigInt().)
    176 */
    177 extern JS_PUBLIC_API BigInt* ToBigInt(JSContext* cx, Handle<Value> val);
    178 
    179 /**
    180 * Convert the given BigInt, modulo 2**64, to a signed 64-bit integer.
    181 */
    182 extern JS_PUBLIC_API int64_t ToBigInt64(const BigInt* bi);
    183 
    184 /**
    185 * Convert the given BigInt, modulo 2**64, to an unsigned 64-bit integer.
    186 */
    187 extern JS_PUBLIC_API uint64_t ToBigUint64(const BigInt* bi);
    188 
    189 /**
    190 * Convert the given BigInt to a Number value as if calling the Number
    191 * constructor on it
    192 * (https://tc39.es/ecma262/#sec-number-constructor-number-value). The value
    193 * may be rounded if it doesn't fit without loss of precision.
    194 */
    195 extern JS_PUBLIC_API double BigIntToNumber(const BigInt* bi);
    196 
    197 /**
    198 * Return true if the given BigInt is negative.
    199 */
    200 extern JS_PUBLIC_API bool BigIntIsNegative(const BigInt* bi);
    201 
    202 /**
    203 * Return true if the given BigInt fits inside the given NumericT type without
    204 * loss of precision, and store the value in the out parameter. Otherwise return
    205 * false and leave the value of the out parameter unspecified.
    206 */
    207 template <typename NumericT>
    208 static inline bool BigIntFits(const BigInt* bi, NumericT* out) {
    209  return detail::BigIntToNumberChecker<NumericT>::fits(bi, out);
    210 }
    211 
    212 /**
    213 * Same as BigIntFits(), but checks if the value fits inside a JS Number value.
    214 */
    215 extern JS_PUBLIC_API bool BigIntFitsNumber(const BigInt* bi, double* out);
    216 
    217 /**
    218 * Convert the given BigInt to a String value as if toString() were called on
    219 * it.
    220 *
    221 * If the radix is not in the range [2, 36], then this function returns null and
    222 * throws an exception.
    223 */
    224 extern JS_PUBLIC_API JSString* BigIntToString(JSContext* cx, Handle<BigInt*> bi,
    225                                              uint8_t radix);
    226 
    227 }  // namespace JS
    228 
    229 #endif /* js_BigInt_h */