longfn
Version:
Rewritten variant of long.js that is entirely functional (and faster because of it)
1,261 lines (1,164 loc) • 35.4 kB
JavaScript
export const TWO_PWR_16_DBL = 1 << 16
export const TWO_PWR_32_DBL = TWO_PWR_16_DBL * TWO_PWR_16_DBL
export const TWO_PWR_24_DBL = 1 << 24
export const TWO_PWR_24 = fromInt(TWO_PWR_24_DBL)
export const TWO_PWR_64_DBL = TWO_PWR_32_DBL * TWO_PWR_32_DBL
export const TWO_PWR_63_DBL = TWO_PWR_64_DBL / 2
export const MIN_VALUE = Object.freeze(fromBits(0, 0x80000000))
export const MAX_VALUE = Object.freeze(fromBits(0xFFFFFFFF, 0x7FFFFFFF))
export const MAX_UNSIGNED_VALUE = Object.freeze(fromBits(0xFFFFFFFF, 0xFFFFFFFF, true))
export const ONE = Object.freeze(fromInt(1))
export const UONE = Object.freeze(fromInt(1, true))
export const NEG_ONE = Object.freeze(fromInt(-1))
export const ZERO = Object.freeze(fromInt(0))
export const UZERO = Object.freeze(fromInt(0, true))
export const isLE = new Uint16Array(new Uint8Array([0xAA, 0xBB]).buffer)[0] === 0xBBAA
const powDbl = Math.pow // Used 4 times (4*8 to 15+4)
export function isLong (obj) {
return obj !== null &&
typeof obj === 'object' &&
typeof obj.low === 'number' &&
typeof obj.high === 'number'
}
export function isSLong (obj) {
return isLong(obj) && !obj.unsigned
}
export function isULong (obj) {
return isLong(obj) && !!obj.unsigned
}
export function isLongLike (obj) {
return obj !== null &&
typeof obj === 'object' &&
(obj.low === null || obj.low === undefined || typeof obj.low === 'number') &&
(obj.high === null || obj.high === undefined || typeof obj.high === 'number')
}
export function fromBits (low, high, unsigned, target) {
if (target === undefined || target === null) {
return {
low: low | 0,
high: high | 0,
unsigned: !!unsigned
}
}
target.low = low | 0
target.high = high | 0
target.unsigned = !!unsigned
return target
}
export function fromInt (value, unsigned, target) {
let high
if (unsigned) {
value >>>= 0
high = 0
} else {
value |= 0
high = (value < 0 ? -1 : 0) | 0
}
return fromBits(value, high, unsigned, target)
}
export function noBigInt () {
throw new Error('BigInt is not supported on this platform.')
}
export const fromBigInt = typeof BigInt === 'undefined'
? noBigInt
: (function () {
const N0 = BigInt(0)
const N1 = BigInt(1)
const NN1 = BigInt(-1)
const NTWO_PWR_32_DBL = BigInt(TWO_PWR_32_DBL)
const NTWO_PWR_64_DBL = BigInt(TWO_PWR_64_DBL)
const NTWO_PWR_63_DBL = BigInt(TWO_PWR_63_DBL)
return function fromBigInt (value, unsigned, target) {
if (target === null || target === undefined) {
target = { low: 0 | 0, high: 0 | 0, unsigned: false }
}
if (unsigned) {
if (value < N0) {
return copy(UZERO, target)
}
if (value >= NTWO_PWR_64_DBL) {
return copy(MAX_UNSIGNED_VALUE, target)
}
} else {
if (value <= -NTWO_PWR_63_DBL) {
return copy(MIN_VALUE, target)
}
if (value + N1 >= NTWO_PWR_63_DBL) {
return copy(MAX_VALUE, target)
}
if (value < N0) {
return neg(fromBigInt(value * NN1, unsigned, target), target)
}
}
return fromBits(
Number(value % NTWO_PWR_32_DBL),
Number(value / NTWO_PWR_32_DBL),
unsigned,
target
)
}
})()
// Ported from: https://github.com/dcodeIO/long.js/blob/ce11b4b2bd3ba1240a057d62018563d99db318f9/src/long.js#L161-L178
export function fromNumber (value, unsigned, target) {
if (target === null || target === undefined) {
target = { low: 0 | 0, high: 0 | 0, unsigned: false }
}
if (isNaN(value)) {
return copy(unsigned ? UZERO : ZERO, target)
}
if (unsigned) {
if (value < 0) {
return copy(UZERO, target)
}
if (value >= TWO_PWR_64_DBL) {
return copy(MAX_UNSIGNED_VALUE, target)
}
} else {
if (value <= -TWO_PWR_63_DBL) {
return copy(MIN_VALUE, target)
}
if (value + 1 >= TWO_PWR_63_DBL) {
return copy(MAX_VALUE, target)
}
if (value < 0) {
return neg(fromNumber(-value, unsigned, target), target)
}
}
target.low = (value % TWO_PWR_32_DBL) | 0
target.high = (value / TWO_PWR_32_DBL) | 0
target.unsigned = !!unsigned
return target
}
export function fromValue (value, unsigned, target) {
if (typeof unsigned === 'object' && unsigned !== null) {
return fromValue(value, undefined, unsigned)
}
if (typeof value === 'bigint') {
return fromBigInt(value, unsigned, target)
}
if (typeof value === 'number') {
return fromNumber(value, unsigned, target)
}
if (typeof value === 'string') {
return fromString(value, unsigned, undefined, target)
}
if (value === null || value === undefined || value === false) {
return copy(
unsigned ? UZERO : ZERO,
target || fromInt(0)
)
}
if (value === true) {
return copy(
unsigned ? UONE : ONE,
target || fromInt(0)
)
}
if (value.buffer instanceof ArrayBuffer) {
return fromBytes(value, unsigned, target)
}
if (Array.isArray(value)) {
return fromBits(value[0], value[1], typeof unsigned === 'boolean' ? unsigned : value[2], target)
}
return fromBits(value.low, value.high, typeof unsigned === 'boolean' ? unsigned : value.unsigned, target)
}
export function toNumber (long) {
if (long.unsigned) {
return ((long.high >>> 0) * TWO_PWR_32_DBL) + (long.low >>> 0)
}
return long.high * TWO_PWR_32_DBL + (long.low >>> 0)
}
const toContext = {
out: null,
target: null,
offset: 0
}
function prepareToContext (offset, target) {
if (typeof offset === 'object' && offset !== null) {
const tmp = target
target = offset
offset = tmp || 0
} else {
offset = offset || 0
}
toContext.offset = offset
if (!target) {
target = new Uint8Array(offset + 8)
toContext.out = target
} else if (!(target instanceof Uint8Array) && target.buffer) {
toContext.out = new Uint8Array(target.buffer, target.byteOffset, target.byteLength)
} else {
toContext.out = target
}
toContext.target = target
}
export function toBytesLE (long, offset, target) {
prepareToContext(offset, target)
toBytesLERaw(long, toContext.offset, toContext.out)
return toContext.target
}
export function toBytesLERaw (long, i, out) {
const hi = long.high
const lo = long.low
out[i] = lo & 0xff
out[i + 1] = lo >>> 8 & 0xff
out[i + 2] = lo >>> 16 & 0xff
out[i + 3] = lo >>> 24
out[i + 4] = hi & 0xff
out[i + 5] = hi >>> 8 & 0xff
out[i + 6] = hi >>> 16 & 0xff
out[i + 7] = hi >>> 24
return out
}
const fromContext = {
source: null,
target: null,
offset: 0
}
function prepareFromContext (source, unsigned, offset, target) {
if (typeof unsigned === 'number') {
target = offset
offset = unsigned
unsigned = false
}
if (typeof offset === 'object') {
target = offset
fromContext.offset = 0
} else {
fromContext.offset = offset || 0
}
if ((target === null || target === undefined)) {
fromContext.target = { low: 0 | 0, high: 0 | 0, unsigned: !!unsigned }
} else {
target.unsigned = !!unsigned
fromContext.target = target
}
fromContext.source = !(source instanceof Uint8Array) && source.buffer
? new Uint8Array(source.buffer, source.byteOffset, source.byteLength)
: source
}
export function fromBytesLE (source, unsigned, offset, target) {
prepareFromContext(source, unsigned, offset, target)
return fromBytesLERaw(fromContext.source, fromContext.offset, fromContext.target)
}
export function fromBytesLERaw (source, i, target) {
target.low = source[i] |
source[i + 1] << 8 |
source[i + 2] << 16 |
source[i + 3] << 24
target.high = source[i + 4] |
source[i + 5] << 8 |
source[i + 6] << 16 |
source[i + 7] << 24
return target
}
export function toBytesBE (long, offset, target) {
prepareToContext(offset, target)
toBytesBERaw(long, toContext.offset, toContext.out)
return toContext.target
}
export function toBytesBERaw (long, i, out) {
const hi = long.high
const lo = long.low
out[i] = hi >>> 24
out[i + 1] = hi >>> 16 & 0xff
out[i + 2] = hi >>> 8 & 0xff
out[i + 3] = hi & 0xff
out[i + 4] = lo >>> 24
out[i + 5] = lo >>> 16 & 0xff
out[i + 6] = lo >>> 8 & 0xff
out[i + 7] = lo & 0xff
return out
}
export function fromBytesBE (source, unsigned, offset, target) {
prepareFromContext(source, unsigned, offset, target)
return fromBytesBERaw(fromContext.source, fromContext.offset, fromContext.target)
}
export function fromBytesBERaw (source, i, target) {
target.low = source[i + 4] << 24 |
source[i + 5] << 16 |
source[i + 6] << 8 |
source[i + 7]
target.high = source[i] << 24 |
source[i + 1] << 16 |
source[i + 2] << 8 |
source[i + 3]
return target
}
export const fromBytes = isLE ? fromBytesLE : fromBytesBE
export const fromBytesRaw = isLE ? fromBytesLERaw : fromBytesBERaw
export const toBytes = isLE ? toBytesLE : toBytesBE
export const toBytesRaw = isLE ? toBytesLERaw : toBytesBERaw
const MSB = 0b10000000
const REST = 0b1111111
export function toVarInt (long, offset, target) {
prepareToContext(offset, target)
toVarIntRaw(long, toContext.offset, toContext.out)
toVarInt.bytes = toVarIntRaw.bytes
return toContext.target
}
toVarInt.bytes = 1
const zigZagTmp = fromInt(0)
function tmpToZigZag (long) {
const hi = long.high
const lo = long.low
const hiB = (hi >> 31)
zigZagTmp.low = (lo << 1) ^ hiB
zigZagTmp.high = (lo >>> 31) ^ (hi << 1) ^ hiB
}
export function toZigZag (long, offset, target) {
prepareToContext(offset, target)
toZigZagRaw(long, toContext.offset, toContext.out)
toZigZag.bytes = toZigZagRaw.bytes
return toContext.target
}
export function toZigZagRaw (long, i, out) {
tmpToZigZag(long)
toVarIntRaw(zigZagTmp, i, out)
toZigZagRaw.bytes = toVarIntRaw.bytes
return out
}
export function toVarIntRaw (long, i, out) {
const hi = long.high
const lo = long.low
const b8 = hi >>> 24
const b7 = hi >>> 17 & REST
const b6 = hi >>> 10 & REST
const b5 = hi >>> 3 & REST
const b4 = ((hi & 0b111) << 4) | (lo >>> 28)
const b3 = lo >>> 21 & REST
const b2 = lo >>> 14 & REST
const b1 = lo >>> 7 & REST
const b0 = lo & REST
if (b8 !== 0) {
toVarIntRaw.bytes = 9
out[i + 8] = b8
out[i + 7] = b7 | MSB
out[i + 6] = b6 | MSB
out[i + 5] = b5 | MSB
out[i + 4] = b4 | MSB
out[i + 3] = b3 | MSB
out[i + 2] = b2 | MSB
out[i + 1] = b1 | MSB
out[i] = b0 | MSB
return out
}
if (b7 !== 0) {
toVarIntRaw.bytes = 8
out[i + 7] = b7
out[i + 6] = b6 | MSB
out[i + 5] = b5 | MSB
out[i + 4] = b4 | MSB
out[i + 3] = b3 | MSB
out[i + 2] = b2 | MSB
out[i + 1] = b1 | MSB
out[i] = b0 | MSB
return out
}
if (b6 !== 0) {
toVarIntRaw.bytes = 7
out[i + 6] = b6
out[i + 5] = b5 | MSB
out[i + 4] = b4 | MSB
out[i + 3] = b3 | MSB
out[i + 2] = b2 | MSB
out[i + 1] = b1 | MSB
out[i] = b0 | MSB
return out
}
if (b5 !== 0) {
toVarIntRaw.bytes = 6
out[i + 5] = b5
out[i + 4] = b4 | MSB
out[i + 3] = b3 | MSB
out[i + 2] = b2 | MSB
out[i + 1] = b1 | MSB
out[i] = b0 | MSB
return out
}
if (b4 !== 0) {
toVarIntRaw.bytes = 5
out[i + 4] = b4
out[i + 3] = b3 | MSB
out[i + 2] = b2 | MSB
out[i + 1] = b1 | MSB
out[i] = b0 | MSB
return out
}
if (b3 !== 0) {
toVarIntRaw.bytes = 4
out[i + 3] = b3
out[i + 2] = b2 | MSB
out[i + 1] = b1 | MSB
out[i] = b0 | MSB
return out
}
if (b2 !== 0) {
toVarIntRaw.bytes = 3
out[i + 2] = b2
out[i + 1] = b1 | MSB
out[i] = b0 | MSB
return out
}
if (b1 !== 0) {
toVarIntRaw.bytes = 2
out[i + 1] = b1
out[i] = b0 | MSB
return out
}
toVarIntRaw.bytes = 1
out[i] = b0
return out
}
toVarIntRaw.bytes = 1
export function varIntLength (long) {
const hi = long.high
const lo = long.low
const b8 = hi >>> 24
if (b8 !== 0) return 9
const b7 = hi >>> 17 & REST
if (b7 !== 0) return 8
const b6 = hi >>> 10 & REST
if (b6 !== 0) return 7
const b5 = hi >>> 3 & REST
if (b5 !== 0) return 6
const b4 = ((hi & 0b111) << 4) | (lo >>> 28)
if (b4 !== 0) return 5
const b3 = lo >>> 21 & REST
if (b3 !== 0) return 4
const b2 = lo >>> 14 & REST
if (b2 !== 0) return 3
const b1 = lo >>> 7 & REST
if (b1 !== 0) return 2
return 1
}
export function zigZagLength (long) {
tmpToZigZag(long)
return varIntLength(zigZagTmp)
}
export function fromVarInt (source, unsigned, offset, target) {
prepareFromContext(source, unsigned, offset, target)
fromVarIntRaw(fromContext.source, fromContext.offset, fromContext.target)
fromVarInt.bytes = fromVarIntRaw.bytes
return fromContext.target
}
fromVarInt.bytes = 1
export function fromZigZag (source, unsigned, offset, target) {
prepareFromContext(source, unsigned, offset, target)
fromZigZagRaw(fromContext.source, fromContext.offset, fromContext.target)
fromZigZag.bytes = fromZigZagRaw.bytes
return fromContext.target
}
fromZigZag.bytes = 1
export function fromZigZagRaw (source, i, target) {
fromVarIntRaw(source, i, target)
const hi = target.high
const lo = target.low
const loB = -(lo & 1)
target.low = (hi << 31) ^ (lo >>> 1) ^ loB
target.high = (hi >>> 1) ^ loB
fromZigZagRaw.bytes = fromVarIntRaw.bytes
return target
}
fromZigZagRaw.bytes = 1
export function fromVarIntRaw (source, i, target) {
let b = source[i]
if ((b & MSB) === 0) {
target.low = b
target.high = 0
fromVarIntRaw.bytes = 1
return target
}
let lo = b & REST
b = source[i + 1]
if ((b & MSB) === 0) {
target.low = lo | b << 7
target.high = 0
fromVarIntRaw.bytes = 2
return target
}
lo |= (b & REST) << 7
b = source[i + 2]
if ((b & MSB) === 0) {
target.low = lo | b << 14
target.high = 0
fromVarIntRaw.bytes = 3
return target
}
lo |= (b & REST) << 14
b = source[i + 3]
if ((b & MSB) === 0) {
target.low = lo | b << 21
target.high = 0
fromVarIntRaw.bytes = 4
return target
}
lo |= (b & REST) << 21
b = source[i + 4]
target.low = lo | (b & 0b1111) << 28
let hi = (b & 0b1110000) >> 4
if ((b & MSB) === 0) {
target.high = hi
fromVarIntRaw.bytes = 5
return target
}
b = source[i + 5]
if ((b & MSB) === 0) {
target.high = hi | b << 3
fromVarIntRaw.bytes = 6
return target
}
hi |= (b & REST) << 3
b = source[i + 6]
if ((b & MSB) === 0) {
target.high = hi | b << 10
fromVarIntRaw.bytes = 7
return target
}
hi |= (b & REST) << 10
b = source[i + 7]
if ((b & MSB) === 0) {
target.high = hi | b << 17
fromVarIntRaw.bytes = 8
return target
}
hi |= (b & REST) << 17
b = source[i + 8]
target.high = hi | (source[i + 8] << 24)
fromVarIntRaw.bytes = 9
return target
}
fromVarIntRaw.bytes = 1
export const toString = (function () {
const TMP_NEG = fromInt(0)
const radixLong = fromInt(0)
const tmpDiv = fromInt(0)
const rem1 = fromInt(0)
const TMP_REM2 = fromInt(0)
const TMP_RADIX_POW = fromInt(0)
const TMP_REMDIV = fromInt(0)
const TMP_INTVAL = fromInt(0)
// Ported from https://github.com/dcodeIO/long.js/blob/ce11b4b2bd3ba1240a057d62018563d99db318f9/src/long.js#L480-L516
return function toString (long, radix) {
if (radix === undefined || radix === null || radix === 0 || radix === false) {
radix = 10
} else if (typeof radix === 'string') {
radix = parseInt(radix, 10)
}
if (radix < 2 || radix > 36) {
throw new RangeError(`Radix between 2 and 36 expected, got: ${radix}`)
}
if (isZero(long)) {
return '0'
}
if (isNegative(long)) { // Unsigned Longs are never negative
if (eq(long, MIN_VALUE)) {
// 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.
fromNumber(radix, false, radixLong)
div(long, radixLong, tmpDiv)
mul(tmpDiv, radixLong, rem1)
sub(rem1, long, rem1)
return toString(tmpDiv, radix) + toInt(rem1).toString(radix)
} else {
return '-' + toString(neg(long, TMP_NEG), radix)
}
}
// Do several (6) digits each time through the loop, so as to
// minimize the calls to the very expensive emulated div.
fromNumber(powDbl(radix, 6), long.unsigned, TMP_RADIX_POW)
copy(long, TMP_REM2)
let result = ''
while (true) {
div(TMP_REM2, TMP_RADIX_POW, TMP_REMDIV)
mul(TMP_REMDIV, TMP_RADIX_POW, TMP_INTVAL)
const intval = toInt(sub(TMP_REM2, TMP_INTVAL, TMP_INTVAL)) >>> 0
let digits = intval.toString(radix)
copy(TMP_REMDIV, TMP_REM2)
if (isZero(TMP_REM2)) {
return digits + result
} else {
while (digits.length < 6) {
digits = '0' + digits
}
result = '' + digits + result
}
}
}
})()
export function toInt (long) {
return long.unsigned ? long.low >>> 0 : long.low
}
export const toBigInt = typeof BigInt === 'undefined'
? noBigInt
: (function () {
const NTWO_PWR_32_DBL = BigInt(TWO_PWR_32_DBL)
const NBASE = BigInt(0x80000000) * 2n
const NN1 = BigInt(-1)
const tmp = fromInt(0)
return function toBigInt (long) {
if (isNegative(long)) {
return toBigInt(neg(long, tmp)) * NN1
}
const low = long.low < 0 ? NBASE + BigInt(long.low) : BigInt(long.low)
const value = BigInt(long.high) * NTWO_PWR_32_DBL + low
if (long.unsigned) {
return BigInt.asUintN(64, value)
}
return BigInt.asIntN(64, value)
}
})()
export function isZero (long) {
return long.low === 0 && long.high === 0
}
export function isOdd (long) {
return (long.low & 1) === 1
}
export function isEven (long) {
return (long.low & 1) === 0
}
export function eq (a, b) {
if (!a.unsigned !== !b.unsigned && (a.high >>> 31) === 1 && (b.high >>> 31) === 1) {
return false
}
return a.high === b.high && a.low === b.low
}
export function ne (a, b) {
return !eq(a, b)
}
export function lt (long, greater) {
return compare(long, greater) < 0
}
export function le (long, sameOrGreater) {
return compare(long, sameOrGreater) <= 0
}
export function ge (long, sameOrLesser) {
return compare(long, sameOrLesser) >= 0
}
export function gt (long, lesser) {
return compare(long, lesser) > 0
}
export function isNegative (long) {
return !long.unsigned && long.high < 0
}
export function isPositive (long) {
return long.unsigned || long.high >= 0
}
export const fromFloat = (function () {
const buffer = new ArrayBuffer(8)
const floatIn = new Float64Array(buffer)
const intOut = new Uint32Array(buffer)
if (isLE) {
return function fromFloatLE (float, target, unsigned) {
if (target === null || target === undefined) {
target = { low: 0 | 0, high: 0 | 0, unsigned: unsigned }
}
floatIn[0] = float
target.low = intOut[0]
target.high = intOut[1]
target.unsigned = !!unsigned
return target
}
}
return function fromFloatBE (float, target, unsigned) {
if (target === null || target === undefined) {
target = { low: 0 | 0, high: 0 | 0, unsigned: unsigned }
}
floatIn[0] = float
target.low = intOut[1]
target.high = intOut[0]
target.unsigned = !!unsigned
return target
}
})()
// Ported from https://github.com/dcodeIO/long.js/blob/ce11b4b2bd3ba1240a057d62018563d99db318f9/src/long.js#L808-L843
export function add (long, addend, target) {
// Divide each number into 4 chunks of 16 bits, and then sum the chunks.
const a48 = long.high >>> 16
const a32 = long.high & 0xFFFF
const a16 = long.low >>> 16
const a00 = long.low & 0xFFFF
const b48 = addend.high >>> 16
const b32 = addend.high & 0xFFFF
const b16 = addend.low >>> 16
const b00 = addend.low & 0xFFFF
let c00 = a00 + b00
let c16 = c00 >>> 16
c00 &= 0xFFFF
c16 += a16 + b16
let c32 = c16 >>> 16
c16 &= 0xFFFF
c32 += a32 + b32
let c48 = c32 >>> 16
c32 &= 0xFFFF
c48 += a48 + b48
c48 &= 0xFFFF
target.low = (c16 << 16) | c00
target.high = (c48 << 16) | c32
target.unsigned = !!long.unsigned
return target
}
export function toUnsigned (long, target) {
target.low = long.low
target.high = long.high
target.unsigned = true
return target
}
export function toSigned (long, target) {
target.low = long.low
target.high = long.high
target.unsigned = false
return target
}
export function not (long, target) {
target.low = ~long.low
target.high = ~long.high
target.unsigned = !!long.unsigned
return target
}
export function or (long, other, target) {
target.low = long.low | other.low
target.high = long.high | other.high
target.unsigned = !!long.unsigned
return target
}
export function xor (long, other, target) {
target.low = long.low ^ other.low
target.high = long.high ^ other.high
target.unsigned = !!long.unsigned
return target
}
export function and (long, other, target) {
target.low = long.low & other.low
target.high = long.high & other.high
target.unsigned = !!long.unsigned
return target
}
export const neg = (function () {
const tmp = fromInt(0)
return function neg (long, target) {
if (!long.unsigned && eq(long, MIN_VALUE)) {
return copy(MIN_VALUE, target, false)
}
return add(not(long, tmp), ONE, target)
}
})()
export const sub = (function () {
const tmp = fromInt(0)
return function sub (long, subtrahend, target) {
return add(long, neg(subtrahend, tmp), target)
}
})()
export const compare = (function () {
const tmp = fromInt(0)
return function compare (a, b) {
if (eq(a, b)) {
return 0
}
const aNeg = isNegative(a)
const bNeg = isNegative(b)
if (aNeg && !bNeg) {
return -1
}
if (!aNeg && bNeg) {
return 1
}
// At this point the sign bits are the same
if (!a.unsigned) {
return isNegative(sub(a, b, tmp)) ? -1 : 1
}
// Both are positive if at least one is unsigned
return (b.high >>> 0) > (a.high >>> 0) || (b.high === a.high && (b.low >>> 0) > (a.low >>> 0)) ? -1 : 1
}
})()
// Ported from https://github.com/dcodeIO/long.js/blob/ce11b4b2bd3ba1240a057d62018563d99db318f9/src/long.js#L1157-L1172
export function shr (long, numBits, target) {
if ((numBits &= 63) === 0) {
target.low = long.low
target.high = long.high
} else if (numBits < 32) {
target.low = (long.low >>> numBits) | (long.high << (32 - numBits))
target.high = long.high >> numBits
} else {
target.low = long.high >> (numBits - 32)
target.high = long.high >= 0 ? 0 : -1
}
target.unsigned = !!long.unsigned
return target
}
// Ported from https://github.com/dcodeIO/long.js/blob/ce11b4b2bd3ba1240a057d62018563d99db318f9/src/long.js#L1207-L1219
export function shru (long, numBits, target) {
if ((numBits &= 63) === 0) {
target.low = long.low
target.high = long.high
} else if (numBits < 32) {
target.low = (long.low >>> numBits) | (long.high << (32 - numBits))
target.high = long.high >>> numBits
} else if (numBits === 32) {
target.low = long.high
target.high = 0
} else {
target.low = long.high >>> (numBits - 32)
target.high = 0
}
target.unsigned = !!long.unsigned
return target
}
// Ported from https://github.com/dcodeIO/long.js/blob/ce11b4b2bd3ba1240a057d62018563d99db318f9/src/long.js#L1213-L1219
export function shl (long, numBits, target) {
if ((numBits &= 63) === 0) {
target.low = long.low
target.high = long.high
} else if (numBits < 32) {
target.low = long.low << numBits
target.high = (long.high << numBits) | (long.low >>> (32 - numBits))
} else {
target.low = 0
target.high = long.low << (numBits - 32)
}
target.unsigned = !!long.unsigned
return target
}
export function mulRaw (long, multiplier, target) {
// If both longs are small, use float multiplication
if (lt(long, TWO_PWR_24) && lt(multiplier, TWO_PWR_24)) {
const numa = toNumber(long)
const numb = toNumber(multiplier)
const multiplied = numa * numb
fromNumber(multiplied, long.unsigned, target)
return target
}
// Divide each long into 4 chunks of 16 bits, and then add up 4x4 products.
// We can skip products that would overflow.
const a48 = long.high >>> 16
const a32 = long.high & 0xFFFF
const a16 = long.low >>> 16
const a00 = long.low & 0xFFFF
const b48 = multiplier.high >>> 16
const b32 = multiplier.high & 0xFFFF
const b16 = multiplier.low >>> 16
const b00 = multiplier.low & 0xFFFF
let c00 = a00 * b00
let c16 = c00 >>> 16
c00 &= 0xFFFF
c16 += a16 * b00
let c32 = c16 >>> 16
c16 &= 0xFFFF
c16 += a00 * b16
c32 += c16 >>> 16
c16 &= 0xFFFF
c32 += a32 * b00
let 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
target.low = (c16 << 16) | c00
target.high = (c48 << 16) | c32
target.unsigned = !!long.unsigned
return target
}
// Ported from https://github.com/dcodeIO/long.js/blob/ce11b4b2bd3ba1240a057d62018563d99db318f9/src/long.js#L865-L940
export const mul = (function () {
const TMP_MULTI1 = fromInt(0)
const TMP_MULTI2 = fromInt(0)
return function mul (long, multiplier, target) {
if (isZero(long) || isZero(multiplier)) {
return copy(long.unsigned ? UZERO : ZERO, target)
}
if (eq(long, MIN_VALUE)) {
copy(isOdd(multiplier) ? MIN_VALUE : ZERO, target)
target.unsigned = !!long.unsigned
return target
}
if (eq(multiplier, MIN_VALUE)) {
copy(isOdd(long) ? MIN_VALUE : ZERO, target)
target.unsigned = !!long.unsigned
return target
}
if (isNegative(long)) {
neg(long, TMP_MULTI1)
if (isNegative(multiplier)) {
neg(multiplier, TMP_MULTI2)
mulRaw(TMP_MULTI1, TMP_MULTI2, target)
} else {
mulRaw(TMP_MULTI1, multiplier, TMP_MULTI2)
neg(TMP_MULTI2, target)
}
return target
}
if (isNegative(multiplier)) {
neg(multiplier, TMP_MULTI1)
mulRaw(long, TMP_MULTI1, TMP_MULTI2)
neg(TMP_MULTI2, target)
return target
}
return mulRaw(long, multiplier, target)
}
})()
// Ported from https://github.com/dcodeIO/long.js/blob/ce11b4b2bd3ba1240a057d62018563d99db318f9/src/long.js#L957-L1062
export const div = (function () {
const rem = fromInt(0)
const approxRes = fromInt(0)
const approxRem = fromInt(0)
const negLong = fromInt(0)
const negDivisor = fromInt(0)
const unsignedDivisor = fromInt(0)
const halfUnsigned = fromInt(0)
return function div (long, divisor, target) {
if (isZero(divisor)) {
throw Error('division by zero')
}
if (isZero(long)) {
return copy(long, target)
}
if (!long.unsigned) {
// This section is only relevant for signed longs and is derived from the
// closure library as a whole.
if (eq(long, MIN_VALUE)) {
if (eq(divisor, ONE) || eq(divisor, NEG_ONE)) {
return copy(MIN_VALUE, target, false) // recall that -MIN_VALUE == MIN_VALUE
}
if (eq(divisor, MIN_VALUE)) {
return copy(ONE, target, false)
}
// At this point, we have |other| >= 2, so |this/other| < |MIN_VALUE|.
const halfThis = shr(long, 1, {})
const approx = {}
shl(div(halfThis, divisor, {}), 1, approx)
if (eq(approx, ZERO)) {
return copy(isNegative(divisor) ? ONE : NEG_ONE, target, false)
}
sub(long, mul(divisor, approx, target), target)
return add(approx, div(target, divisor, target), target)
}
if (eq(divisor, MIN_VALUE)) {
return copy(ZERO, target)
}
if (isNegative(long)) {
long = neg(long, negLong)
if (isNegative(divisor)) {
return div(long, neg(divisor, negDivisor), target)
}
return neg(div(long, divisor, target), target)
}
if (isNegative(divisor)) {
return neg(div(long, neg(divisor, negDivisor), target), target)
}
copy(ZERO, target)
} else {
// 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 (!divisor.unsigned) {
divisor = copy(divisor, unsignedDivisor, true)
}
if (gt(divisor, long)) {
return copy(UZERO, target)
}
if (gt(divisor, shru(long, 1, halfUnsigned))) { // 15 >>> 1 = 7 ; with divisor = 8 ; true
return copy(UONE, target)
}
copy(UZERO, target)
}
// 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.
copy(long, rem)
while (ge(rem, divisor)) {
// Approximate the result of division. This may be a little greater or
// smaller than the actual value.
let approx = Math.max(1, Math.floor(toNumber(rem) / toNumber(divisor)))
// We will tweak the approximate result by changing it in the 48-th digit or
// the smallest non-fractional digit, whichever is larger.
const log2 = Math.ceil(Math.log(approx) / Math.LN2)
const delta = (log2 <= 48) ? 1 : powDbl(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.
fromNumber(approx, false, approxRes)
mul(approxRes, divisor, approxRem)
while (isNegative(approxRem) || gt(approxRem, rem)) {
approx -= delta
fromNumber(approx, long.unsigned, approxRes)
mul(approxRes, divisor, approxRem)
}
// We know the answer can't be zero... and actually, zero would cause
// infinite recursion since we would make no progress.
add(target, isZero(approxRes) ? ONE : approxRes, target)
sub(rem, approxRem, rem)
}
return target
}
})()
export const mod = (function () {
const tmp = fromInt(0)
return function modjs (long, divisor, target) {
div(long, divisor, tmp)
mul(tmp, divisor, tmp)
return sub(long, tmp, target)
}
})()
export function rotl (long, numBits, target) {
if ((numBits &= 63) === 0) {
return copy(long, target)
}
if (numBits === 32) {
target.low = long.high
target.high = long.low
} else if (numBits < 32) {
const b = 32 - numBits
target.low = (long.low << numBits) | (long.high >>> b)
target.high = (long.high << numBits) | (long.low >>> b)
} else {
numBits -= 32
const b = 32 - numBits
target.low = (long.high << numBits) | (long.low >>> b)
target.high = (long.low << numBits) | (long.high >>> b)
}
target.unsigned = !!long.unsigned
return target
}
export function rotr (long, numBits, target) {
if ((numBits &= 63) === 0) {
return copy(long, target)
}
if (numBits === 32) {
target.low = long.high
target.high = long.low
} else if (numBits < 32) {
const b = 32 - numBits
target.low = (long.high << b) | (long.low >>> numBits)
target.high = (long.low << b) | (long.high >>> numBits)
} else {
numBits -= 32
const b = 32 - numBits
target.low = (long.low << b) | (long.high >>> numBits)
target.high = (long.high << b) | (long.low >>> numBits)
}
target.unsigned = !!long.unsigned
return target
}
export function copy (source, target, forceUnsigned) {
target.low = source.low | 0
target.high = source.high | 0
target.unsigned = forceUnsigned !== undefined ? forceUnsigned : !!source.unsigned
return target
}
let RADIX_DIGITS
function getDigitsByRadix (radix) {
if (RADIX_DIGITS === undefined) {
RADIX_DIGITS = {}
for (let radix = 2; radix <= 36; radix++) {
const radixLng = fromInt(radix, true)
const digitsByPos = []
let multi = fromInt(1, true)
let prev = fromInt(0, true)
for (let pos = 0; gt(multi, prev); pos++) {
const lookup = {}
digitsByPos.push(lookup)
for (let digit = 1; digit < radix; digit++) {
const num = fromInt(digit, true)
lookup[digit.toString(radix)] = mul(num, multi, num)
}
const tmp = prev
prev = multi
multi = mul(multi, radixLng, tmp)
}
RADIX_DIGITS[radix] = digitsByPos
}
}
return RADIX_DIGITS[radix]
}
// Ported from https://github.com/dcodeIO/long.js/blob/ce11b4b2bd3ba1240a057d62018563d99db318f9/src/long.js#L227-L268
export function fromString (str, unsigned, radix, target) {
if (str.length === 0) {
return copy(ZERO, target)
}
if (typeof unsigned === 'object') {
target = unsigned
unsigned = false
radix = undefined
} else if (typeof unsigned === 'number' || typeof radix === 'boolean') {
return fromString(str, radix, unsigned, target)
}
if (target === null || target === undefined) {
target = { low: 0 | 0, high: 0 | 0, unsigned: unsigned }
}
if (str === 'NaN' || str === 'Infinity' || str === '+Infinity' || str === '-Infinity') {
throw new Error(`Input "${str}" is not supported by longfn.`)
}
str = str.trim()
const p = str.indexOf('-')
if (p > 0) {
throw new Error(`Input "${str}" contains hyphen at unexpected position ${p}`)
}
const negate = p === 0
if (negate) {
if (unsigned) {
throw new Error(`Input "${str}" is marked as negative though it is supposed to be unsigned.`)
}
str = str.substr(1)
}
if (radix === undefined || radix === 0 || radix === false) {
if (/^0x/i.test(str)) {
str = str.substr(2)
radix = 16
} else if (/^0/.test(str)) {
throw new Error(`If no radix is specified, input "${str}" should not start with a 0 as a it is an unclear state in JavaScript`)
} else {
radix = 10
}
} else {
if (typeof radix === 'string') {
radix = parseInt(radix, 10)
}
if (radix < 2 || radix > 36) {
throw new RangeError(`Radix between 2 and 36 expected, got: ${radix}`)
}
}
const digits = getDigitsByRadix(radix)
copy(ZERO, target, true)
let numDigits = 0
for (; numDigits < str.length; numDigits++) {
const byPos = digits[numDigits % digits.length]
const char = str[numDigits]
if (char === '0') {
// zero does nothing
continue
}
const value = byPos[char]
if (value === undefined) {
break
}
}
for (let digit = 0, pos = numDigits - 1; digit < numDigits; digit++, pos--) {
const byPos = digits[digit % digits.length]
const char = str[pos]
if (char === '0') {
// zero does nothing
continue
}
add(target, byPos[char], target)
}
target.unsigned = !!unsigned
if (negate) {
neg(target, target)
}
return target
}
function ctz32 (value) {
const c = Math.clz32(value & -value)
return value ? 31 - c : c
}
export function clz (long) {
return long.high ? Math.clz32(long.high) : Math.clz32(long.low) + 32
}
export function ctz (long) {
return long.low ? ctz32(long.low) : ctz32(long.high) + 32
}