UNPKG

@creditkarma/thrift-server-core

Version:
258 lines 8.16 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.isInt64 = exports.Int64 = void 0; const POW2_31 = Math.pow(2, 31); const POW2_32 = Math.pow(2, 32); const POW10_11 = Math.pow(10, 11); const _HEX = []; for (let i = 0; i < 256; i++) { _HEX[i] = (i > 0xf ? '' : '0') + i.toString(16); } const HEX_REGEX = /^(?:0x)?([0-9a-fA-F]+)/; const BYTE_COUNT = 8; function hiLoNeg({ hi, lo }) { const nlo = ~lo + 1; const carry = nlo === 0 ? 1 : 0; const nhi = ~hi + carry; return { hi: nhi, lo: nlo, }; } function hiLoSignedToUnsigned(i64) { const negative = i64.hi < 0; const { hi, lo } = negative ? hiLoNeg(i64) : i64; return { negative, hi: hi >>> 0, lo: lo >>> 0, }; } function hiLoSignedToNumber({ hi, lo }) { const carry = lo < 0 ? 1 : 0; return (hi + carry) * POW2_32 + lo; } function hiLoSignedFromNumber(i64) { i64 = Math.trunc(i64); const lo = i64 >> 0; const carry = lo < 0 ? 1 : 0; const hi = (i64 - lo) / POW2_32 - carry; return { signed: true, hi, lo }; } function prepBuffer(source, offset) { if (offset === 0 && source.length === BYTE_COUNT) { return source; } const end = offset >= 0 ? offset + BYTE_COUNT : Math.max(source.length + offset + BYTE_COUNT, 0); const slice = source.slice(offset, end); if (slice.length > BYTE_COUNT) { return slice.slice(0, BYTE_COUNT); } if (slice.length === BYTE_COUNT) { return slice; } const out = Buffer.alloc(BYTE_COUNT); slice.copy(out, BYTE_COUNT - slice.length); return out; } class Int64 { constructor(...args) { if (args[0] instanceof Buffer) { const source = args[0]; const offset = args[1] || 0; this.buffer = prepBuffer(source, offset); } else if (Object.prototype.toString.call(args[0]) === '[object Uint8Array]') { const source = Buffer.from(args[0]); const offset = args[1] || 0; this.buffer = prepBuffer(source, offset); } else { this.buffer = Buffer.alloc(BYTE_COUNT); this.setValue(args[0], args[1]); } } static toDecimalString(i64) { if (typeof i64 === 'number') { return `${i64}`; } else { return i64.toDecimalString(); } } static fromDecimalString(text) { const negative = text.charAt(0) === '-'; if (text.length < (negative ? 17 : 16)) { return new Int64(+text); } else if (text.length > (negative ? 20 : 19)) { throw new RangeError(`Too many digits for Int64: ${text}`); } else { const high5 = +text.slice(negative ? 1 : 0, -15); const remainder = +text.slice(-15) + high5 * 2764472320; const hi = Math.floor(remainder / POW2_32) + high5 * 232830; const lo = remainder % POW2_32; if (hi >= POW2_31 && !(negative && hi === POW2_31 && lo === 0)) { throw new RangeError('The magnitude is too large for Int64.'); } if (negative) { const neg = hiLoNeg({ hi, lo }); return new Int64(neg.hi, neg.lo); } return new Int64(hi, lo); } } setValue(hi, lo) { if (lo === undefined) { if (typeof hi === 'number') { this.setNumber(hi); return; } if (typeof hi === 'string') { this.setHexString(hi); return; } throw new Error(hi + ' must be a Number or String'); } if (typeof hi !== 'number' || typeof lo !== 'number') { throw new Error(`${hi} and ${lo} must be Numbers`); } this.setHiLo({ hi, lo }); } toDecimalString() { const i64 = this.read(); const value = hiLoSignedToNumber(i64); if (Number.isSafeInteger(value)) { return value.toString(); } const { negative, hi, lo } = hiLoSignedToUnsigned(i64); const high2 = hi >>> 16; const low = lo + (hi & 0x0000ffff) * POW2_32 + high2 * 74976710656; const high = Math.floor(low / POW10_11) + high2 * 2814; const lowStr = ('00000000000' + String(low % POW10_11)).slice(-11); return (negative ? '-' : '') + String(high) + lowStr; } toNumber(allowImprecise = true) { const x = hiLoSignedToNumber(this.read()); if (!allowImprecise && !Number.isSafeInteger(x)) { return x < 0 ? Number.NEGATIVE_INFINITY : Number.POSITIVE_INFINITY; } return x; } valueOf() { return this.toNumber(false); } toString(radix = 10) { return this.valueOf().toString(radix); } toOctetString(sep = '') { if (!sep) { return this.buffer.toString('hex'); } return Array.from(this.buffer, (num) => _HEX[num]).join(sep); } toBuffer(rawBuffer = false) { if (rawBuffer) { return this.buffer; } const out = Buffer.alloc(BYTE_COUNT); this.buffer.copy(out); return out; } copy(targetBuffer, targetOffset = 0) { this.buffer.copy(targetBuffer, targetOffset); } compare(other) { if ((this.buffer[0] & 0x80) !== (other.buffer[0] & 0x80)) { return other.buffer[0] - this.buffer[0]; } return this.buffer.compare(other.buffer); } equals(other) { return this.compare(other) === 0; } inspect() { return ('[Int64 value:' + this + ' octets:' + this.toOctetString(' ') + ']'); } setNumber(i64) { if (!Number.isFinite(i64)) { throw new RangeError(`Value is not finite: ${i64}`); } const { hi, lo } = hiLoSignedFromNumber(i64); try { this.buffer.writeInt32BE(hi, 0); this.buffer.writeInt32BE(lo, 4); } catch { throw new RangeError(`Value is outside the Int64 range: ${i64}`); } } setHiLo(i64) { const { hi, lo } = i64; if (!Number.isInteger(hi)) { throw new TypeError(`Hi is not an integer: ${hi}`); } if (!Number.isInteger(lo)) { throw new TypeError(`Lo is not an integer: ${lo}`); } try { if (hi < 0) { this.buffer.writeInt32BE(hi, 0); } else { this.buffer.writeUInt32BE(hi, 0); } } catch { throw new RangeError(`Hi is outside the Int64 range: ${hi}`); } try { if (lo < 0) { this.buffer.writeInt32BE(lo, 4); } else { this.buffer.writeUInt32BE(lo, 4); } } catch { throw new RangeError(`Lo is outside the Int64 range: ${lo}`); } } setHexString(source) { const matches = source.match(HEX_REGEX); const match = (matches && matches[1]) || ''; const hex = (match.length % 2 === 0 ? '' : '0') + match; const length = Buffer.byteLength(hex, 'hex'); if (length > BYTE_COUNT) { throw new RangeError(source + ' is outside Int64 range'); } const offset = BYTE_COUNT - length; this.buffer.fill(0, 0, offset); this.buffer.write(hex, offset, length, 'hex'); } read() { return { signed: true, hi: this.buffer.readInt32BE(0), lo: this.buffer.readInt32BE(4), }; } } exports.Int64 = Int64; Int64.MAX_INT = Math.pow(2, 53); Int64.MIN_INT = -Math.pow(2, 53); function isInt64(i64) { return (i64 instanceof Int64 || (typeof i64 === 'object' && i64.buffer instanceof Buffer && i64.buffer.length === BYTE_COUNT && typeof i64.toDecimalString === 'function')); } exports.isInt64 = isInt64; //# sourceMappingURL=Int64.js.map