// ------------------------------------------------------------------------------ // Code generated by the Fast Binary Encoding compiler. DO NOT EDIT. // https://github.com/chronoxor/FastBinaryEncoding // Source: FBE // FBE version: 1.15.0.0 // ------------------------------------------------------------------------------ /* eslint-disable prefer-const,no-loss-of-precision */ 'use strict' /** * Signed 64-bit integer value */ class Int64 { /** * Initialize signed 64-bit integer value with high & low parts * @param {number} low The low 32-bit part * @param {number} high The high 32-bit part * @constructor */ constructor (low, high) { this.low = low | 0 this.high = high | 0 } /** * Zero value constant * @returns {!Int64} */ static get ZERO () { return INT64_ZERO } /** * Minimal value constant * @returns {!Int64} */ static get MIN () { return INT64_MIN } /** * Maximal value constant * @returns {!Int64} */ static get MAX () { return INT64_MAX } /** * Is the specified object Int64? * @param obj Object to check * @returns {!boolean} */ static isInt64 (obj) { return (obj && obj.__isInt64__) === true } /** * Returns Int64 representing the 64 bit integer that comes by concatenating the given low and high 32 bits parts * @param {number} lowBits The low 32-bit part * @param {number} highBits The high 32-bit part * @returns {!Int64} The corresponding Int64 value */ static fromBits (lowBits, highBits) { return new Int64(lowBits, highBits) } /** * Returns Int64 from its bytes representation * @param {!Array.} bytes Bytes representation * @param {boolean=} le Whether little or big endian, defaults to little endian * @returns {!Int64} The corresponding Int64 value */ static fromBytes (bytes, le = true) { return le ? Int64.fromBytesLE(bytes) : Int64.fromBytesBE(bytes) } /** * Returns Int64 from its bytes representation (bid endian) * @param {!Array.} bytes Bytes representation * @returns {!Int64} The corresponding Int64 value */ static fromBytesBE (bytes) { return new Int64( bytes[4] << 24 | bytes[5] << 16 | bytes[6] << 8 | bytes[7] << 0, bytes[0] << 24 | bytes[1] << 16 | bytes[2] << 8 | bytes[3] << 0 ) } /** * Returns Int64 from its bytes representation (little endian) * @param {!Array.} bytes Bytes representation * @returns {!Int64} The corresponding Int64 value */ static fromBytesLE (bytes) { return new Int64( bytes[0] << 0 | bytes[1] << 8 | bytes[2] << 16 | bytes[3] << 24, bytes[4] << 0 | bytes[5] << 8 | bytes[6] << 16 | bytes[7] << 24 ) } /** * Returns Int64 representing the given 32-bit integer value * @param {number} value 32-bit integer value * @returns {!Int64} The corresponding Int64 value */ static fromInt32 (value) { value |= 0 let cache = ((value >= -128) && (value < 128)) if (cache) { let cached = Int64Cache[value] if (cached) { return cached } } let result = Int64.fromBits(value, (value < 0) ? -1 : 0) if (cache) { Int64Cache[value] = result } return result } /** * Returns Int64 representing the given value, provided that it is a finite number. Otherwise, zero is returned. * @param {number} value 32-bit integer value * @returns {!Int64} The corresponding Int64 value */ static fromNumber (value) { if (isNaN(value)) { return INT64_ZERO } if (value <= -INT64_TWO_PWR_63_DBL) { return INT64_MIN } if (value + 1 >= INT64_TWO_PWR_63_DBL) { return INT64_MAX } if (value < 0) { return Int64.fromNumber(-value).neg() } return Int64.fromBits((value % INT64_TWO_PWR_32_DBL) | 0, (value / INT64_TWO_PWR_32_DBL) | 0) } /** * Returns Int64 representation of the given string, written using the specified radix. * @param {string} str The textual representation of the Int64 * @param {number=} radix The radix in which the text is written (2-36), defaults to 10 * @returns {!Int64} The corresponding Int64 value */ static fromString (str, radix = 10) { if (str.length === 0) { throw new Error('Empty string!') } if ((str === 'NaN') || (str === 'Infinity') || (str === '+Infinity') || (str === '-Infinity')) { return INT64_ZERO } radix = radix || 10 if ((radix < 2) || (radix > 36)) { throw new RangeError('radix') } let p = str.indexOf('-') if (p > 0) { throw new Error('Interior hyphen!') } else if (p === 0) { return Int64.fromString(str.substring(1), radix).neg() } // Do several (8) digits each time through the loop, so as to // minimize the calls to the very expensive emulated div. let radixToPower = Int64.fromNumber(Math.pow(radix, 8)) let result = INT64_ZERO for (let i = 0; i < str.length; i += 8) { let size = Math.min(8, str.length - i) let value = parseInt(str.substring(i, i + size), radix) if (size < 8) { let power = Int64.fromNumber(Math.pow(radix, size)) result = result.mul(power).add(Int64.fromNumber(value)) } else { result = result.mul(radixToPower) result = result.add(Int64.fromNumber(value)) } } return result } /** * Converts the specified value to a Int64 using the appropriate from* function for its type. * @param {!Int64|!UInt64|number|string} value Value * @returns {!Int64} The corresponding Int64 value */ static fromValue (value) { if (typeof value === 'number') { return Int64.fromNumber(value) } if (typeof value === 'string') { return Int64.fromString(value, 10) } return Int64.fromBits(value.low, value.high) } /** * Converts the Int64 to its bytes representation * @this {!Int64} * @param {boolean=} le Whether little or big endian, defaults to little endian * @returns {!Array.} Bytes representation */ toBytes (le = true) { return le ? this.toBytesLE() : this.toBytesBE() } /** * Converts the Int64 to its bytes representation (big endian) * @this {!Int64} * @returns {!Array.} Bytes representation */ toBytesBE () { let hi = this.high let lo = this.low return [ hi >>> 24 & 0xFF, hi >>> 16 & 0xFF, hi >>> 8 & 0xFF, hi >>> 0 & 0xFF, lo >>> 24 & 0xFF, lo >>> 16 & 0xFF, lo >>> 8 & 0xFF, lo >>> 0 & 0xFF ] } /** * Converts the Int64 to its bytes representation (little endian) * @this {!Int64} * @returns {!Array.} Bytes representation */ toBytesLE () { let hi = this.high let lo = this.low return [ lo >>> 0 & 0xFF, lo >>> 8 & 0xFF, lo >>> 16 & 0xFF, lo >>> 24 & 0xFF, hi >>> 0 & 0xFF, hi >>> 8 & 0xFF, hi >>> 16 & 0xFF, hi >>> 24 & 0xFF ] } /** * Converts the Int64 to a 32-bit integer, assuming it is a 32-bit integer * @this {!Int64} * @returns {number} Result 32-bit integer */ toInt32 () { return this.low } /** * Converts the Int64 to a the nearest floating-point representation of this value (double, 53 bit mantissa) * @this {!Int64} * @returns {number} Result number */ toNumber () { return this.high * INT64_TWO_PWR_32_DBL + (this.low >>> 0) } /** * Converts the Int64 to a string written in the specified radix * @this {!Int64} * @param {number=} radix Radix (2-36), defaults to 10 * @returns {string} Result string */ toString (radix = 10) { radix = radix || 10 if ((radix < 2) || (radix > 36)) { throw new RangeError('Radix must be in range [2, 36]') } if (this.isZero) { return '0' } if (this.isNegative) { if (this.eq(INT64_MIN)) { // We need to change the Long value before it can be negated, so we remove // the bottom-most digit in this base and then recurse to do the rest. let radixLong = Int64.fromNumber(radix) let div = this.div(radixLong) let rem1 = div.mul(radixLong).sub(this) return div.toString(radix) + rem1.toInt32().toString(radix) } else { return '-' + this.neg().toString(radix) } } // Do several (6) digits each time through the loop, so as to // minimize the calls to the very expensive emulated div. let radixToPower = Int64.fromNumber(Math.pow(radix, 6)) let rem = this let result = '' while (true) { let remDiv = rem.div(radixToPower) let intval = rem.sub(remDiv.mul(radixToPower)).toInt32() >>> 0 let digits = intval.toString(radix) rem = remDiv if (rem.isZero) { return digits + result } else { while (digits.length < 6) { digits = '0' + digits } result = '' + digits + result } } } /** * Converts the Int64 to Int64 * @this {!Int64} * @returns {!Int64} Result Int64 number */ toSigned () { return this } /** * Converts the Int64 to UInt64 * @this {!Int64} * @returns {!UInt64} Result UInt64 number */ toUnsigned () { return UInt64.fromBits(this.low, this.high) } /** * Get the high 32 bits as a signed integer * @this {!Int64} * @returns {number} Signed high bits */ get HighBits () { return this.high } /** * Get the high 32 bits as an unsigned integer * @this {!Int64} * @returns {number} Unsigned high bits */ get HighBitsUnsigned () { return this.high >>> 0 } /** * Get the low 32 bits as a signed integer * @this {!Int64} * @returns {number} Signed low bits */ get LowBits () { return this.low } /** * Get the low 32 bits as an unsigned integer * @this {!Int64} * @returns {number} Unsigned low bits */ get LowBitsUnsigned () { return this.low >>> 0 } /** * Get the number of bits needed to represent the absolute value of this Int64 * @this {!Int64} * @returns {number} Number of represented bits */ get NumBits () { if (this.isNegative) { return this.eq(INT64_MIN) ? 64 : this.neg().NumBits } let val = (this.high !== 0) ? this.high : this.low let bit for (bit = 31; bit > 0; bit--) { if ((val & (1 << bit)) !== 0) { break } } return (this.high !== 0) ? (bit + 33) : (bit + 1) } /** * Is this value zero? * @this {!Int64} * @returns {boolean} Zero test result */ get isZero () { return (this.high === 0) && (this.low === 0) } /** * Is this value positive? * @this {!Int64} * @returns {boolean} Positive test result */ get isPositive () { return this.high >= 0 } /** * Is this value negative? * @this {!Int64} * @returns {boolean} Negative test result */ get isNegative () { return this.high < 0 } /** * Is this value odd? * @this {!Int64} * @returns {boolean} Odd test result */ get isOdd () { return (this.low & 1) === 1 } /** * Is this value even? * @this {!Int64} * @returns {boolean} Even test result */ get isEven () { return (this.low & 1) === 0 } /** * Is this value equal to other one? * @this {!Int64} * @param {!Int64|!UInt64|number|string} other Other value * @returns {boolean} Equal result */ eq (other) { if (UInt64.isUInt64(other)) { if (((this.high >>> 31) === 1) && ((other.high >>> 31) === 1)) { return false } } else if (!Int64.isInt64(other)) { other = Int64.fromValue(other) } return (this.high === other.high) && (this.low === other.low) } /** * Is this value not equal to other one? * @this {!Int64} * @param {!Int64|!UInt64|number|string} other Other value * @returns {boolean} Not equal result */ ne (other) { return !this.eq(other) } /** * Is this value less than other one? * @this {!Int64} * @param {!Int64|!UInt64|number|string} other Other value * @returns {boolean} Less than result */ lt (other) { return this.cmp(other) < 0 } /** * Is this value less than or equal other one? * @this {!Int64} * @param {!Int64|!UInt64|number|string} other Other value * @returns {boolean} Less than or equal result */ lte (other) { return this.cmp(other) <= 0 } /** * Is this value greater than other one? * @this {!Int64} * @param {!Int64|!UInt64|number|string} other Other value * @returns {boolean} Greater than result */ gt (other) { return this.cmp(other) > 0 } /** * Is this value greater than or equal other one? * @this {!Int64} * @param {!Int64|!UInt64|number|string} other Other value * @returns {boolean} Greater than or equal result */ gte (other) { return this.cmp(other) >= 0 } /** * Compare this value to other one * @this {!Int64} * @param {!Int64|!UInt64|number|string} other Other value * @returns {number} 0 if they are the same, 1 if the this is greater and -1 if the given one is greater */ cmp (other) { if (!Int64.isInt64(other) && !UInt64.isUInt64(other)) { other = Int64.fromValue(other) } if (this.eq(other)) { return 0 } let thisNeg = this.isNegative let otherNeg = other.isNegative if (thisNeg && !otherNeg) { return -1 } if (!thisNeg && otherNeg) { return 1 } // At this point the sign bits are the same return this.sub(other).isNegative ? -1 : 1 } /** * Negates this value * @this {!Int64} * @returns {!Int64} Negated value */ neg () { if (this.eq(INT64_MIN)) { return INT64_MIN } return this.not().add(INT64_ONE) } /** * Add this value to other one * @this {!Int64} * @param {!Int64|!UInt64|number|string} other Other value * @returns {!Int64} Sum of the values */ add (other) { if (!Int64.isInt64(other) && !UInt64.isUInt64(other)) { other = Int64.fromValue(other) } // Divide each number into 4 chunks of 16 bits, and then sum the chunks let a48 = this.high >>> 16 let a32 = this.high & 0xFFFF let a16 = this.low >>> 16 let a00 = this.low & 0xFFFF let b48 = other.high >>> 16 let b32 = other.high & 0xFFFF let b16 = other.low >>> 16 let b00 = other.low & 0xFFFF let c48 = 0 let c32 = 0 let c16 = 0 let c00 = 0 c00 += a00 + b00 c16 += c00 >>> 16 c00 &= 0xFFFF c16 += a16 + b16 c32 += c16 >>> 16 c16 &= 0xFFFF c32 += a32 + b32 c48 += c32 >>> 16 c32 &= 0xFFFF c48 += a48 + b48 c48 &= 0xFFFF return Int64.fromBits((c16 << 16) | c00, (c48 << 16) | c32) } /** * Subtract other value from this value * @this {!Int64} * @param {!Int64|!UInt64|number|string} other Other value * @returns {!Int64} Difference of two values */ sub (other) { if (!Int64.isInt64(other) && !UInt64.isUInt64(other)) { other = Int64.fromValue(other) } return this.add(other.neg()) } /** * Multiply this value with other one * @this {!Int64} * @param {!Int64|!UInt64|number|string} other Other value * @returns {!Int64} Multiplication of two values */ mul (other) { if (this.isZero) { return INT64_ZERO } if (!Int64.isInt64(other) && !UInt64.isUInt64(other)) { other = Int64.fromValue(other) } if (other.isZero) { return INT64_ZERO } if (this.eq(INT64_MIN)) { return other.isOdd ? INT64_MIN : INT64_ZERO } if (other.eq(INT64_MIN)) { return this.isOdd ? INT64_MIN : INT64_ZERO } if (this.isNegative) { if (other.isNegative) { return this.neg().mul(other.neg()) } else { return this.neg().mul(other).neg() } } else if (other.isNegative) { return this.mul(other.neg()).neg() } // If both longs are small, use float multiplication if (this.lt(INT64_TWO_PWR_24) && other.lt(INT64_TWO_PWR_24)) { return Int64.fromNumber(this.toNumber() * other.toNumber()) } // Divide each long into 4 chunks of 16 bits, and then add up 4x4 products. // We can skip products that would overflow. let a48 = this.high >>> 16 let a32 = this.high & 0xFFFF let a16 = this.low >>> 16 let a00 = this.low & 0xFFFF let b48 = other.high >>> 16 let b32 = other.high & 0xFFFF let b16 = other.low >>> 16 let b00 = other.low & 0xFFFF let c48 = 0 let c32 = 0 let c16 = 0 let c00 = 0 c00 += a00 * b00 c16 += c00 >>> 16 c00 &= 0xFFFF c16 += a16 * b00 c32 += c16 >>> 16 c16 &= 0xFFFF c16 += a00 * b16 c32 += c16 >>> 16 c16 &= 0xFFFF c32 += a32 * b00 c48 += c32 >>> 16 c32 &= 0xFFFF c32 += a16 * b16 c48 += c32 >>> 16 c32 &= 0xFFFF c32 += a00 * b32 c48 += c32 >>> 16 c32 &= 0xFFFF c48 += a48 * b00 + a32 * b16 + a16 * b32 + a00 * b48 c48 &= 0xFFFF return Int64.fromBits((c16 << 16) | c00, (c48 << 16) | c32) } /** * Divide this value by other one * @this {!Int64} * @param {!Int64|!UInt64|number|string} other Other value * @returns {!Int64} Division of two values */ div (other) { if (!Int64.isInt64(other) && !UInt64.isUInt64(other)) { other = Int64.fromValue(other) } if (other.isZero) { throw new Error('Division by zero!') } if (this.isZero) { return INT64_ZERO } let approx, rem, res // This section is only relevant for signed longs and is derived from the closure library as a whole if (this.eq(INT64_MIN)) { // Recall that -MIN_VALUE == MIN_VALUE if (other.eq(INT64_ONE) || other.eq(INT64_NEG_ONE)) { return INT64_MIN } else if (other.eq(INT64_MIN)) { return INT64_ONE } else { // At this point, we have |other| >= 2, so |this/other| < |MIN_VALUE| let halfThis = this.shr(1) approx = halfThis.div(other).shl(1) if (approx.eq(INT64_ZERO)) { return other.isNegative ? INT64_ONE : INT64_NEG_ONE } else { rem = this.sub(other.mul(approx)) res = approx.add(rem.div(other)) return res } } } else if (other.eq(INT64_MIN)) { return INT64_ZERO } if (this.isNegative) { if (other.isNegative) { return this.neg().div(other.neg()) } return this.neg().div(other).neg() } else if (other.isNegative) { return this.div(other.neg()).neg() } res = INT64_ZERO // Repeat the following until the remainder is less than other: find a floating-point that approximates // remainder / other *from below*, add this into the result, and subtract it from the remainder. // It is critical that the approximate value is less than or equal to the real value so that the // remainder never becomes negative. rem = this while (rem.gte(other)) { // Approximate the result of division. This may be a little greater or smaller than the actual value approx = Math.max(1, Math.floor(rem.toNumber() / other.toNumber())) // We will tweak the approximate result by changing it in the 48-th digit or the smallest non-fractional // digit, whichever is larger. let log2 = Math.ceil(Math.log(approx) / Math.LN2) let delta = (log2 <= 48) ? 1 : Math.pow(2, log2 - 48) // Decrease the approximation until it is smaller than the remainder. // Note that if it is too large, the product overflows and is negative. let approxRes = Int64.fromNumber(approx) let approxRem = approxRes.mul(other) while (approxRem.isNegative || approxRem.gt(rem)) { approx -= delta approxRes = Int64.fromNumber(approx) approxRem = approxRes.mul(other) } // We know the answer can't be zero... and actually, zero would cause infinite recursion since // we would make no progress. if (approxRes.isZero) { approxRes = INT64_ONE } res = res.add(approxRes) rem = rem.sub(approxRem) } return res } /** * Modulo this value by other one * @this {!Int64} * @param {!Int64|!UInt64|number|string} other Other value * @returns {!Int64} Module of two values */ mod (other) { if (!Int64.isInt64(other) && !UInt64.isUInt64(other)) { other = Int64.fromValue(other) } return this.sub(this.div(other).mul(other)) } /** * Bitwise NOT this value * @this {!Int64} * @returns {!Int64} Bitwise NOT result value */ not () { return Int64.fromBits(~this.low, ~this.high) } /** * Bitwise AND this value and other one * @this {!Int64} * @param {!Int64|!UInt64|number|string} other Other value * @returns {!Int64} Bitwise AND result value */ and (other) { if (!Int64.isInt64(other) && !UInt64.isUInt64(other)) { other = Int64.fromValue(other) } return Int64.fromBits(this.low & other.low, this.high & other.high) } /** * Bitwise OR this value and other one * @this {!Int64} * @param {!Int64|!UInt64|number|string} other Other value * @returns {!Int64} Bitwise OR result value */ or (other) { if (!Int64.isInt64(other) && !UInt64.isUInt64(other)) { other = Int64.fromValue(other) } return Int64.fromBits(this.low | other.low, this.high | other.high) } /** * Bitwise XOR this value and other one * @this {!Int64} * @param {!Int64|!UInt64|number|string} other Other value * @returns {!Int64} Bitwise XOR result value */ xor (other) { if (!Int64.isInt64(other) && !UInt64.isUInt64(other)) { other = Int64.fromValue(other) } return Int64.fromBits(this.low ^ other.low, this.high ^ other.high) } /** * This Int64 with bits shifted to the left by the given amount * @this {!Int64} * @param {Int64|UInt64|number} numBits Number of bits * @returns {!Int64} Shifted result value */ shl (numBits) { if (Int64.isInt64(numBits) || UInt64.isUInt64(numBits)) { numBits = numBits.toInt32() } if ((numBits &= 63) === 0) { return this } else if (numBits < 32) { return Int64.fromBits(this.low << numBits, (this.high << numBits) | (this.low >>> (32 - numBits))) } else { return Int64.fromBits(0, this.low << (numBits - 32)) } } /** * This Int64 with bits shifted to the right by the given amount * @this {!Int64} * @param {Int64|UInt64|number} numBits Number of bits * @returns {!Int64} Shifted result value */ shr (numBits) { if (Int64.isInt64(numBits) || UInt64.isUInt64(numBits)) { numBits = numBits.toInt32() } if ((numBits &= 63) === 0) { return this } else if (numBits < 32) { return Int64.fromBits((this.low >>> numBits) | (this.high << (32 - numBits)), this.high >> numBits) } else { return Int64.fromBits(this.high >> (numBits - 32), (this.high >= 0) ? 0 : -1) } } /** * This Int64 with bits shifted to the right by the given amount with filling zeros to the left * @this {!Int64} * @param {Int64|UInt64|number} numBits Number of bits * @returns {!Int64} Shifted result value */ shru (numBits) { if (Int64.isInt64(numBits) || UInt64.isUInt64(numBits)) { numBits = numBits.toInt32() } numBits &= 63 if (numBits === 0) { return this } else { let high = this.high if (numBits < 32) { let low = this.low return Int64.fromBits((low >>> numBits) | (high << (32 - numBits)), high >>> numBits) } else if (numBits === 32) { return Int64.fromBits(high, 0) } else { return Int64.fromBits(high >>> (numBits - 32), 0) } } } } Object.defineProperty(Int64.prototype, '__isInt64__', { value: true }) // Useful constants const INT64_TWO_PWR_16_DBL = 1 << 16 const INT64_TWO_PWR_24_DBL = 1 << 24 const INT64_TWO_PWR_32_DBL = INT64_TWO_PWR_16_DBL * INT64_TWO_PWR_16_DBL const INT64_TWO_PWR_64_DBL = INT64_TWO_PWR_32_DBL * INT64_TWO_PWR_32_DBL const INT64_TWO_PWR_63_DBL = INT64_TWO_PWR_64_DBL / 2 // Int64 values cache const Int64Cache = {} // Int64 values constants const INT64_ZERO = Int64.fromInt32(0) const INT64_ONE = Int64.fromInt32(1) const INT64_NEG_ONE = Int64.fromInt32(-1) const INT64_MIN = Int64.fromBits(0, 0x80000000 | 0) const INT64_MAX = Int64.fromBits(0xFFFFFFFF | 0, 0x7FFFFFFF | 0) const INT64_TWO_PWR_24 = Int64.fromInt32(INT64_TWO_PWR_24_DBL) exports.Int64 = Int64 /** * Unsigned 64-bit integer value */ class UInt64 { /** * Initialize unsigned 64-bit integer value with high & low parts * @param {number} low The low 32-bit part * @param {number} high The high 32-bit part * @constructor */ constructor (low, high) { this.low = low | 0 this.high = high | 0 } /** * Zero value constant * @returns {!UInt64} */ static get ZERO () { return UINT64_ZERO } /** * Minimal value constant * @returns {!UInt64} */ static get MIN () { return UINT64_MIN } /** * Maximal value constant * @returns {!UInt64} */ static get MAX () { return UINT64_MAX } /** * Is the specified object UInt64? * @param obj Object to check * @returns {boolean} */ static isUInt64 (obj) { return (obj && obj.__isUInt64__) === true } /** * Returns UInt64 representing the 64 bit integer that comes by concatenating the given low and high 32 bits parts * @param {number} lowBits The low 32-bit part * @param {number} highBits The high 32-bit part * @returns {!UInt64} The corresponding UInt64 value */ static fromBits (lowBits, highBits) { return new UInt64(lowBits, highBits) } /** * Returns UInt64 from its bytes representation * @param {!Array.} bytes Bytes representation * @param {boolean=} le Whether little or big endian, defaults to little endian * @returns {!UInt64} The corresponding Int64 value */ static fromBytes (bytes, le = true) { return le ? UInt64.fromBytesLE(bytes) : UInt64.fromBytesBE(bytes) } /** * Returns UInt64 from its bytes representation (bid endian) * @param {!Array.} bytes Bytes representation * @returns {!UInt64} The corresponding Int64 value */ static fromBytesBE (bytes) { return new UInt64( bytes[4] << 24 | bytes[5] << 16 | bytes[6] << 8 | bytes[7] << 0, bytes[0] << 24 | bytes[1] << 16 | bytes[2] << 8 | bytes[3] << 0 ) } /** * Returns UInt64 from its bytes representation (little endian) * @param {!Array.} bytes Bytes representation * @returns {!UInt64} The corresponding Int64 value */ static fromBytesLE (bytes) { return new UInt64( bytes[0] << 0 | bytes[1] << 8 | bytes[2] << 16 | bytes[3] << 24, bytes[4] << 0 | bytes[5] << 8 | bytes[6] << 16 | bytes[7] << 24 ) } /** * Returns UInt64 representing the given 32-bit integer value * @param {number} value 32-bit integer value * @returns {!UInt64} The corresponding UInt64 value */ static fromInt32 (value) { value >>>= 0 let cache = ((value >= 0) && (value < 256)) if (cache) { let cached = UInt64Cache[value] if (cached) { return cached } } let result = UInt64.fromBits(value, ((value | 0) < 0) ? -1 : 0) if (cache) { UInt64Cache[value] = result } return result } /** * Returns UInt64 representing the given value, provided that it is a finite number. Otherwise, zero is returned. * @param {number} value 32-bit integer value * @returns {!UInt64} The corresponding UInt64 value */ static fromNumber (value) { if (isNaN(value)) { return UINT64_ZERO } if (value < 0) { return UINT64_ZERO } if (value >= UINT64_TWO_PWR_64_DBL) { return UINT64_MAX } if (value < 0) { return UInt64.fromNumber(-value).neg() } return UInt64.fromBits((value % UINT64_TWO_PWR_32_DBL) | 0, (value / UINT64_TWO_PWR_32_DBL) | 0) } /** * Returns UInt64 representation of the given string, written using the specified radix. * @param {string} str The textual representation of the UInt64 * @param {number=} radix The radix in which the text is written (2-36), defaults to 10 * @returns {!UInt64} The corresponding UInt64 value */ static fromString (str, radix = 10) { if (str.length === 0) { throw new Error('Empty string!') } if ((str === 'NaN') || (str === 'Infinity') || (str === '+Infinity') || (str === '-Infinity')) { return UINT64_ZERO } radix = radix || 10 if ((radix < 2) || (radix > 36)) { throw new RangeError('radix') } let p = str.indexOf('-') if (p > 0) { throw new Error('Interior hyphen!') } else if (p === 0) { return UInt64.fromString(str.substring(1), radix).neg() } // Do several (8) digits each time through the loop, so as to // minimize the calls to the very expensive emulated div. let radixToPower = UInt64.fromNumber(Math.pow(radix, 8)) let result = UINT64_ZERO for (let i = 0; i < str.length; i += 8) { let size = Math.min(8, str.length - i) let value = parseInt(str.substring(i, i + size), radix) if (size < 8) { let power = UInt64.fromNumber(Math.pow(radix, size)) result = result.mul(power).add(UInt64.fromNumber(value)) } else { result = result.mul(radixToPower) result = result.add(UInt64.fromNumber(value)) } } return result } /** * Converts the specified value to a UInt64 using the appropriate from* function for its type. * @param {!Int64|!UInt64|number|string} value Value * @returns {!UInt64} The corresponding UInt64 value */ static fromValue (value) { if (typeof value === 'number') { return UInt64.fromNumber(value) } if (typeof value === 'string') { return UInt64.fromString(value, 10) } return UInt64.fromBits(value.low, value.high) } /** * Converts the UInt64 to its bytes representation * @this {!UInt64} * @param {boolean=} le Whether little or big endian, defaults to little endian * @returns {!Array.} Bytes representation */ toBytes (le = true) { return le ? this.toBytesLE() : this.toBytesBE() } /** * Converts the UInt64 to its bytes representation (big endian) * @this {!UInt64} * @returns {!Array.} Bytes representation */ toBytesBE () { let hi = this.high let lo = this.low return [ hi >>> 24 & 0xff, hi >>> 16 & 0xff, hi >>> 8 & 0xff, hi >>> 0 & 0xff, lo >>> 24 & 0xff, lo >>> 16 & 0xff, lo >>> 8 & 0xff, lo >>> 0 & 0xff ] } /** * Converts the UInt64 to its bytes representation (little endian) * @this {!UInt64} * @returns {!Array.} Bytes representation */ toBytesLE () { let hi = this.high let lo = this.low return [ lo >>> 0 & 0xff, lo >>> 8 & 0xff, lo >>> 16 & 0xff, lo >>> 24 & 0xff, hi >>> 0 & 0xff, hi >>> 8 & 0xff, hi >>> 16 & 0xff, hi >>> 24 & 0xff ] } /** * Converts the UInt32 to a 32-bit integer, assuming it is a 32-bit integer * @this {!UInt64} * @returns {number} Result 32-bit integer */ toInt32 () { return this.low >>> 0 } /** * Converts the UInt64 to a the nearest floating-point representation of this value (double, 53 bit mantissa) * @this {!UInt64} * @returns {number} Result number */ toNumber () { return ((this.high >>> 0) * UINT64_TWO_PWR_32_DBL) + (this.low >>> 0) } /** * Converts the UInt64 to a string written in the specified radix * @this {!UInt64} * @param {number=} radix Radix (2-36), defaults to 10 * @returns {string} Result string */ toString (radix = 10) { radix = radix || 10 if ((radix < 2) || (radix > 36)) { throw new RangeError('Radix must be in range [2, 36]') } if (this.isZero) { return '0' } if (this.isNegative) { if (this.eq(UINT64_MIN)) { // We need to change the Long value before it can be negated, so we remove // the bottom-most digit in this base and then recurse to do the rest. let radixLong = UInt64.fromNumber(radix) let div = this.div(radixLong) let rem1 = div.mul(radixLong).sub(this) return div.toString(radix) + rem1.toInt32().toString(radix) } else { return '-' + this.neg().toString(radix) } } // Do several (6) digits each time through the loop, so as to // minimize the calls to the very expensive emulated div. let radixToPower = UInt64.fromNumber(Math.pow(radix, 6)) let rem = this let result = '' while (true) { let remDiv = rem.div(radixToPower) let intval = rem.sub(remDiv.mul(radixToPower)).toInt32() >>> 0 let digits = intval.toString(radix) rem = remDiv if (rem.isZero) { return digits + result } else { while (digits.length < 6) { digits = '0' + digits } result = '' + digits + result } } } /** * Converts the UInt64 to Int64 * @this {!UInt64} * @returns {!Int64} Result Int64 number */ toSigned () { return Int64.fromBits(this.low, this.high) } /** * Converts the UInt64 to UInt64 * @this {!UInt64} * @returns {!UInt64} Result UInt64 number */ toUnsigned () { return this } /** * Gets the high 32 bits as a signed integer * @this {!UInt64} * @returns {number} Signed high bits */ get HighBits () { return this.high } /** * Gets the high 32 bits as an unsigned integer * @this {!UInt64} * @returns {number} Unsigned high bits */ get HighBitsUnsigned () { return this.high >>> 0 } /** * Gets the low 32 bits as a signed integer * @this {!UInt64} * @returns {number} Signed low bits */ get LowBits () { return this.low } /** * Gets the low 32 bits as an unsigned integer * @this {!UInt64} * @returns {number} Unsigned low bits */ get LowBitsUnsigned () { return this.low >>> 0 } /** * Gets the number of bits needed to represent the absolute value of this UInt64 * @this {!UInt64} * @returns {number} Number of represented bits */ get NumBits () { if (this.isNegative) { return this.eq(UINT64_MIN) ? 64 : this.neg().NumBits } let val = (this.high !== 0) ? this.high : this.low let bit for (bit = 31; bit > 0; bit--) { if ((val & (1 << bit)) !== 0) { break } } return (this.high !== 0) ? (bit + 33) : (bit + 1) } /** * Is this value zero? * @this {!UInt64} * @returns {boolean} Zero test result */ get isZero () { return (this.high === 0) && (this.low === 0) } /** * Is this value positive? * @this {!UInt64} * @returns {boolean} Positive test result */ get isPositive () { return true } /** * Is this value negative? * @this {!UInt64} * @returns {boolean} Negative test result */ get isNegative () { return false } /** * Is this value odd? * @this {!UInt64} * @returns {boolean} Odd test result */ get isOdd () { return (this.low & 1) === 1 } /** * Is this value even? * @this {!UInt64} * @returns {boolean} Even test result */ get isEven () { return (this.low & 1) === 0 } /** * Is this value equal to other one? * @this {!UInt64} * @param {!Int64|!UInt64|number|string} other Other value * @returns {boolean} Equal result */ eq (other) { if (Int64.isInt64(other)) { if (((this.high >>> 31) === 1) && ((other.high >>> 31) === 1)) { return false } } else if (!UInt64.isUInt64(other)) { other = UInt64.fromValue(other) } return (this.high === other.high) && (this.low === other.low) } /** * Is this value not equal to other one? * @this {!UInt64} * @param {!Int64|!UInt64|number|string} other Other value * @returns {boolean} Not equal result */ ne (other) { return !this.eq(other) } /** * Is this value less than other one? * @this {!UInt64} * @param {!Int64|!UInt64|number|string} other Other value * @returns {boolean} Less than result */ lt (other) { return this.cmp(other) < 0 } /** * Is this value less than or equal other one? * @this {!UInt64} * @param {!Int64|!UInt64|number|string} other Other value * @returns {boolean} Less than or equal result */ lte (other) { return this.cmp(other) <= 0 } /** * Is this value greater than other one? * @this {!UInt64} * @param {!Int64|!UInt64|number|string} other Other value * @returns {boolean} Greater than result */ gt (other) { return this.cmp(other) > 0 } /** * Is this value greater than or equal other one? * @this {!UInt64} * @param {!Int64|!UInt64|number|string} other Other value * @returns {boolean} Greater than or equal result */ gte (other) { return this.cmp(other) >= 0 } /** * Compare this value to other one * @this {!UInt64} * @param {!Int64|!UInt64|number|string} other Other value * @returns {number} 0 if they are the same, 1 if the this is greater and -1 if the given one is greater */ cmp (other) { if (!Int64.isInt64(other) && !UInt64.isUInt64(other)) { other = UInt64.fromValue(other) } if (this.eq(other)) { return 0 } let thisNeg = this.isNegative let otherNeg = other.isNegative if (thisNeg && !otherNeg) { return -1 } if (!thisNeg && otherNeg) { return 1 } // Both are positive if at least one is unsigned return (((other.high >>> 0) > (this.high >>> 0)) || ((other.high === this.high) && (other.low >>> 0) > (this.low >>> 0))) ? -1 : 1 } /** * Negates this value * @this {!UInt64} * @returns {!UInt64} Negated value */ neg () { return this.not().add(UINT64_ONE) } /** * Add this value to other one * @this {!UInt64} * @param {!Int64|!UInt64|number|string} other Other value * @returns {!UInt64} Sum of two values */ add (other) { if (!Int64.isInt64(other) && !UInt64.isUInt64(other)) { other = UInt64.fromValue(other) } // Divide each number into 4 chunks of 16 bits, and then sum the chunks let a48 = this.high >>> 16 let a32 = this.high & 0xFFFF let a16 = this.low >>> 16 let a00 = this.low & 0xFFFF let b48 = other.high >>> 16 let b32 = other.high & 0xFFFF let b16 = other.low >>> 16 let b00 = other.low & 0xFFFF let c48 = 0 let c32 = 0 let c16 = 0 let c00 = 0 c00 += a00 + b00 c16 += c00 >>> 16 c00 &= 0xFFFF c16 += a16 + b16 c32 += c16 >>> 16 c16 &= 0xFFFF c32 += a32 + b32 c48 += c32 >>> 16 c32 &= 0xFFFF c48 += a48 + b48 c48 &= 0xFFFF return UInt64.fromBits((c16 << 16) | c00, (c48 << 16) | c32) } /** * Subtract other value from this value * @this {!UInt64} * @param {!Int64|!UInt64|number|string} other Other value * @returns {!UInt64} Difference of two values */ sub (other) { if (!Int64.isInt64(other) && !UInt64.isUInt64(other)) { other = UInt64.fromValue(other) } return this.add(other.neg()) } /** * Multiply this value with other one * @this {!UInt64} * @param {!Int64|!UInt64|number|string} other Other value * @returns {!UInt64} Multiplication of two values */ mul (other) { if (this.isZero) { return UINT64_ZERO } if (!Int64.isInt64(other) && !UInt64.isUInt64(other)) { other = UInt64.fromValue(other) } if (other.isZero) { return UINT64_ZERO } if (this.eq(UINT64_MIN)) { return other.isOdd ? UINT64_MIN : UINT64_ZERO } if (other.eq(UINT64_MIN)) { return this.isOdd ? UINT64_MIN : UINT64_ZERO } if (this.isNegative) { if (other.isNegative) { return this.neg().mul(other.neg()) } else { return this.neg().mul(other).neg() } } else if (other.isNegative) { return this.mul(other.neg()).neg() } // If both longs are small, use float multiplication if (this.lt(UINT64_TWO_PWR_24) && other.lt(UINT64_TWO_PWR_24)) { return UInt64.fromNumber(this.toNumber() * other.toNumber()) } // Divide each long into 4 chunks of 16 bits, and then add up 4x4 products. // We can skip products that would overflow. let a48 = this.high >>> 16 let a32 = this.high & 0xFFFF let a16 = this.low >>> 16 let a00 = this.low & 0xFFFF let b48 = other.high >>> 16 let b32 = other.high & 0xFFFF let b16 = other.low >>> 16 let b00 = other.low & 0xFFFF let c48 = 0 let c32 = 0 let c16 = 0 let c00 = 0 c00 += a00 * b00 c16 += c00 >>> 16 c00 &= 0xFFFF c16 += a16 * b00 c32 += c16 >>> 16 c16 &= 0xFFFF c16 += a00 * b16 c32 += c16 >>> 16 c16 &= 0xFFFF c32 += a32 * b00 c48 += c32 >>> 16 c32 &= 0xFFFF c32 += a16 * b16 c48 += c32 >>> 16 c32 &= 0xFFFF c32 += a00 * b32 c48 += c32 >>> 16 c32 &= 0xFFFF c48 += a48 * b00 + a32 * b16 + a16 * b32 + a00 * b48 c48 &= 0xFFFF return UInt64.fromBits((c16 << 16) | c00, (c48 << 16) | c32) } /** * Divide this value by other one * @this {!UInt64} * @param {!Int64|!UInt64|number|string} other Other value * @returns {!UInt64} Division of two values */ div (other) { if (!Int64.isInt64(other) && !UInt64.isUInt64(other)) { other = UInt64.fromValue(other) } if (other.isZero) { throw new Error('Division by zero!') } if (this.isZero) { return UINT64_ZERO } let approx, rem, res // The algorithm below has not been made for unsigned longs. It's therefore required to take special care of // the MSB prior to running it. if (Int64.isInt64(other)) { other = other.toUnsigned() } if (other.gt(this)) { return UINT64_ZERO } // 15 >>> 1 = 7 ; with divisor = 8 ; true if (other.gt(this.shru(1))) { return UINT64_ONE } res = UINT64_ZERO // Repeat the following until the remainder is less than other: find a floating-point that approximates // remainder / other *from below*, add this into the result, and subtract it from the remainder. // It is critical that the approximate value is less than or equal to the real value so that the // remainder never becomes negative. rem = this while (rem.gte(other)) { // Approximate the result of division. This may be a little greater or smaller than the actual value approx = Math.max(1, Math.floor(rem.toNumber() / other.toNumber())) // We will tweak the approximate result by changing it in the 48-th digit or the smallest non-fractional // digit, whichever is larger. let log2 = Math.ceil(Math.log(approx) / Math.LN2) let delta = (log2 <= 48) ? 1 : Math.pow(2, log2 - 48) // Decrease the approximation until it is smaller than the remainder. // Note that if it is too large, the product overflows and is negative. let approxRes = Int64.fromNumber(approx) let approxRem = approxRes.mul(other) while (approxRem.isNegative || approxRem.gt(rem)) { approx -= delta approxRes = UInt64.fromNumber(approx) approxRem = approxRes.mul(other) } // We know the answer can't be zero... and actually, zero would cause infinite recursion since // we would make no progress. if (approxRes.isZero) { approxRes = UINT64_ONE } res = res.add(approxRes) rem = rem.sub(approxRem) } return res } /** * Modulo this value by other one * @this {!UInt64} * @param {!Int64|!UInt64|number|string} other Other value * @returns {!UInt64} Module of two values */ mod (other) { if (!Int64.isInt64(other) && !UInt64.isUInt64(other)) { other = UInt64.fromValue(other) } return this.sub(this.div(other).mul(other)) } /** * Bitwise NOT this value * @this {!UInt64} * @returns {!UInt64} Bitwise NOT result value */ not () { return UInt64.fromBits(~this.low, ~this.high) } /** * Bitwise AND this value and other one * @this {!UInt64} * @param {!Int64|!UInt64|number|string} other Other value * @returns {!UInt64} Bitwise AND result value */ and (other) { if (!Int64.isInt64(other) && !UInt64.isUInt64(other)) { other = UInt64.fromValue(other) } return UInt64.fromBits(this.low & other.low, this.high & other.high) } /** * Bitwise OR this value and other one * @this {!UInt64} * @param {!Int64|!UInt64|number|string} other Other value * @returns {!UInt64} Bitwise OR result value */ or (other) { if (!Int64.isInt64(other) && !UInt64.isUInt64(other)) { other = UInt64.fromValue(other) } return UInt64.fromBits(this.low | other.low, this.high | other.high) } /** * Bitwise XOR this value and other one * @this {!UInt64} * @param {!Int64|!UInt64|number|string} other Other value * @returns {!UInt64} Bitwise XOR result value */ xor (other) { if (!Int64.isInt64(other) && !UInt64.isUInt64(other)) { other = UInt64.fromValue(other) } return UInt64.fromBits(this.low ^ other.low, this.high ^ other.high) } /** * This UInt64 with bits shifted to the left by the given amount * @this {!UInt64} * @param {Int64|UInt64|number} numBits Number of bits * @returns {!UInt64} Shifted result value */ shl (numBits) { if (Int64.isInt64(numBits) || UInt64.isUInt64(numBits)) { numBits = numBits.toInt32() } if ((numBits &= 63) === 0) { return this } else if (numBits < 32) { return UInt64.fromBits(this.low << numBits, (this.high << numBits) | (this.low >>> (32 - numBits))) } else { return UInt64.fromBits(0, this.low << (numBits - 32)) } } /** * This UInt64 with bits shifted to the right by the given amount * @this {!UInt64} * @param {Int64|UInt64|number} numBits Number of bits * @returns {!UInt64} Shifted result value */ shr (numBits) { if (Int64.isInt64(numBits) || UInt64.isUInt64(numBits)) { numBits = numBits.toInt32() } if ((numBits &= 63) === 0) { return this } else if (numBits < 32) { return UInt64.fromBits((this.low >>> numBits) | (this.high << (32 - numBits)), this.high >> numBits) } else { return UInt64.fromBits(this.high >> (numBits - 32), (this.high >= 0) ? 0 : -1) } } /** * This UInt64 with bits shifted to the right by the given amount with filling zeros to the left * @this {!UInt64} * @param {Int64|UInt64|number} numBits Number of bits * @returns {!UInt64} Shifted result value */ shru (numBits) { if (Int64.isInt64(numBits) || UInt64.isUInt64(numBits)) { numBits = numBits.toInt32() } numBits &= 63 if (numBits === 0) { return this } else { let high = this.high if (numBits < 32) { let low = this.low return UInt64.fromBits((low >>> numBits) | (high << (32 - numBits)), high >>> numBits) } else if (numBits === 32) { return UInt64.fromBits(high, 0) } else { return UInt64.fromBits(high >>> (numBits - 32), 0) } } } } Object.defineProperty(UInt64.prototype, '__isUInt64__', { value: true }) // Useful constants const UINT64_TWO_PWR_16_DBL = 1 << 16 const UINT64_TWO_PWR_24_DBL = 1 << 24 const UINT64_TWO_PWR_32_DBL = UINT64_TWO_PWR_16_DBL * UINT64_TWO_PWR_16_DBL const UINT64_TWO_PWR_64_DBL = UINT64_TWO_PWR_32_DBL * UINT64_TWO_PWR_32_DBL // UInt64 values cache const UInt64Cache = {} // Int64 values constants const UINT64_ZERO = UInt64.fromInt32(0) const UINT64_ONE = UInt64.fromInt32(1) const UINT64_MIN = UInt64.fromInt32(0) const UINT64_MAX = UInt64.fromBits(0xFFFFFFFF | 0, 0xFFFFFFFF | 0) const UINT64_TWO_PWR_24 = UInt64.fromInt32(UINT64_TWO_PWR_24_DBL) exports.UInt64 = UInt64