/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ /* BigInt. */ #ifndef js_BigInt_h #define js_BigInt_h #include "mozilla/Span.h" // mozilla::Span #include // std::numeric_limits #include // int64_t, uint64_t #include // std::enable_if_t, std::{true,false}_type, std::is_{integral,signed,unsigned}_v #include "jstypes.h" // JS_PUBLIC_API #include "js/TypeDecls.h" namespace mozilla { template class Range; } namespace JS { class JS_PUBLIC_API BigInt; namespace detail { using Int64Limits = std::numeric_limits; using Uint64Limits = std::numeric_limits; extern JS_PUBLIC_API BigInt* BigIntFromInt64(JSContext* cx, int64_t num); extern JS_PUBLIC_API BigInt* BigIntFromUint64(JSContext* cx, uint64_t num); extern JS_PUBLIC_API BigInt* BigIntFromBool(JSContext* cx, bool b); template struct NumberToBigIntConverter; template struct NumberToBigIntConverter< SignedIntT, std::enable_if_t< std::is_integral_v && std::is_signed_v && Int64Limits::min() <= std::numeric_limits::min() && std::numeric_limits::max() <= Int64Limits::max()>> { static BigInt* convert(JSContext* cx, SignedIntT num) { return BigIntFromInt64(cx, num); } }; template struct NumberToBigIntConverter< UnsignedIntT, std::enable_if_t< std::is_integral_v && std::is_unsigned_v && std::numeric_limits::max() <= Uint64Limits::max()>> { static BigInt* convert(JSContext* cx, UnsignedIntT num) { return BigIntFromUint64(cx, num); } }; template <> struct NumberToBigIntConverter { static BigInt* convert(JSContext* cx, bool b) { return BigIntFromBool(cx, b); } }; extern JS_PUBLIC_API bool BigIntIsInt64(BigInt* bi, int64_t* result); extern JS_PUBLIC_API bool BigIntIsUint64(BigInt* bi, uint64_t* result); template struct BigIntToNumberChecker; template struct BigIntToNumberChecker< SignedIntT, std::enable_if_t< std::is_integral_v && std::is_signed_v && Int64Limits::min() <= std::numeric_limits::min() && std::numeric_limits::max() <= Int64Limits::max()>> { using TypeLimits = std::numeric_limits; static bool fits(BigInt* bi, SignedIntT* result) { int64_t innerResult; if (!BigIntIsInt64(bi, &innerResult)) { return false; } if (TypeLimits::min() <= innerResult && innerResult <= TypeLimits::max()) { *result = SignedIntT(innerResult); return true; } return false; } }; template struct BigIntToNumberChecker< UnsignedIntT, std::enable_if_t< std::is_integral_v && std::is_unsigned_v && std::numeric_limits::max() <= Uint64Limits::max()>> { static bool fits(BigInt* bi, UnsignedIntT* result) { uint64_t innerResult; if (!BigIntIsUint64(bi, &innerResult)) { return false; } if (innerResult <= std::numeric_limits::max()) { *result = UnsignedIntT(innerResult); return true; } return false; } }; } // namespace detail /** * Create a BigInt from an integer value. All integral types not larger than 64 * bits in size are supported. */ template static inline BigInt* NumberToBigInt(JSContext* cx, NumericT val) { return detail::NumberToBigIntConverter::convert(cx, val); } /** * Create a BigInt from a floating-point value. If the number isn't integral * (that is, if it's NaN, an infinity, or contains a fractional component), * this function returns null and throws an exception. * * Passing -0.0 will produce the bigint 0n. */ extern JS_PUBLIC_API BigInt* NumberToBigInt(JSContext* cx, double num); /** * Create a BigInt by parsing a string using the ECMAScript StringToBigInt * algorithm (https://tc39.es/ecma262/#sec-stringtobigint). Latin1 and two-byte * character ranges are supported. It may be convenient to use * JS::ConstLatin1Chars or JS::ConstTwoByteChars. * * (StringToBigInt performs parsing similar to that performed by the |Number| * global function when passed a string, but it doesn't allow infinities, * decimal points, or exponential notation, and neither algorithm allows numeric * separators or an 'n' suffix character. This fast-and-loose description is * offered purely as a convenience to the reader: see the specification * algorithm for exact behavior.) * * If parsing fails, this function returns null and throws an exception. */ extern JS_PUBLIC_API BigInt* StringToBigInt( JSContext* cx, mozilla::Range chars); extern JS_PUBLIC_API BigInt* StringToBigInt( JSContext* cx, mozilla::Range chars); /** * Create a BigInt by parsing a string consisting of an optional sign character * followed by one or more alphanumeric ASCII digits in the provided radix. * * If the radix is not in the range [2, 36], or the string fails to parse, this * function returns null and throws an exception. */ extern JS_PUBLIC_API BigInt* SimpleStringToBigInt( JSContext* cx, mozilla::Span chars, uint8_t radix); /** * Convert a JS::Value to a BigInt using the ECMAScript ToBigInt algorithm * (https://tc39.es/ecma262/#sec-tobigint). * * (Note in particular that this will throw if passed a value whose type is * 'number'. To convert a number to a BigInt, use one of the overloads of * JS::NumberToBigInt().) */ extern JS_PUBLIC_API BigInt* ToBigInt(JSContext* cx, Handle val); /** * Convert the given BigInt, modulo 2**64, to a signed 64-bit integer. */ extern JS_PUBLIC_API int64_t ToBigInt64(BigInt* bi); /** * Convert the given BigInt, modulo 2**64, to an unsigned 64-bit integer. */ extern JS_PUBLIC_API uint64_t ToBigUint64(BigInt* bi); /** * Convert the given BigInt to a Number value as if calling the Number * constructor on it * (https://tc39.es/ecma262/#sec-number-constructor-number-value). The value * may be rounded if it doesn't fit without loss of precision. */ extern JS_PUBLIC_API double BigIntToNumber(BigInt* bi); /** * Return true if the given BigInt is negative. */ extern JS_PUBLIC_API bool BigIntIsNegative(BigInt* bi); /** * Return true if the given BigInt fits inside the given NumericT type without * loss of precision, and store the value in the out parameter. Otherwise return * false and leave the value of the out parameter unspecified. */ template static inline bool BigIntFits(BigInt* bi, NumericT* out) { return detail::BigIntToNumberChecker::fits(bi, out); } /** * Same as BigIntFits(), but checks if the value fits inside a JS Number value. */ extern JS_PUBLIC_API bool BigIntFitsNumber(BigInt* bi, double* out); /** * Convert the given BigInt to a String value as if toString() were called on * it. * * If the radix is not in the range [2, 36], then this function returns null and * throws an exception. */ extern JS_PUBLIC_API JSString* BigIntToString(JSContext* cx, Handle bi, uint8_t radix); } // namespace JS #endif /* js_BigInt_h */