201 lines
5.3 KiB
JavaScript
201 lines
5.3 KiB
JavaScript
"use strict";
|
|
module.exports = LongBits;
|
|
|
|
var util = require("../util/minimal");
|
|
|
|
/**
|
|
* Constructs new long bits.
|
|
* @classdesc Helper class for working with the low and high bits of a 64 bit value.
|
|
* @memberof util
|
|
* @constructor
|
|
* @param {number} lo Low 32 bits, unsigned
|
|
* @param {number} hi High 32 bits, unsigned
|
|
*/
|
|
function LongBits(lo, hi) {
|
|
|
|
// note that the casts below are theoretically unnecessary as of today, but older statically
|
|
// generated converter code might still call the ctor with signed 32bits. kept for compat.
|
|
|
|
/**
|
|
* Low bits.
|
|
* @type {number}
|
|
*/
|
|
this.lo = lo >>> 0;
|
|
|
|
/**
|
|
* High bits.
|
|
* @type {number}
|
|
*/
|
|
this.hi = hi >>> 0;
|
|
}
|
|
|
|
/**
|
|
* Zero bits.
|
|
* @memberof util.LongBits
|
|
* @type {util.LongBits}
|
|
*/
|
|
var zero = LongBits.zero = new LongBits(0, 0);
|
|
|
|
zero.toNumber = function() { return 0; };
|
|
zero.zzEncode = zero.zzDecode = function() { return this; };
|
|
zero.length = function() { return 1; };
|
|
|
|
/**
|
|
* Zero hash.
|
|
* @memberof util.LongBits
|
|
* @type {string}
|
|
*/
|
|
var zeroHash = LongBits.zeroHash = "\0\0\0\0\0\0\0\0";
|
|
|
|
/**
|
|
* Constructs new long bits from the specified number.
|
|
* @param {number} value Value
|
|
* @returns {util.LongBits} Instance
|
|
*/
|
|
LongBits.fromNumber = function fromNumber(value) {
|
|
if (value === 0)
|
|
return zero;
|
|
var sign = value < 0;
|
|
if (sign)
|
|
value = -value;
|
|
var lo = value >>> 0,
|
|
hi = (value - lo) / 4294967296 >>> 0;
|
|
if (sign) {
|
|
hi = ~hi >>> 0;
|
|
lo = ~lo >>> 0;
|
|
if (++lo > 4294967295) {
|
|
lo = 0;
|
|
if (++hi > 4294967295)
|
|
hi = 0;
|
|
}
|
|
}
|
|
return new LongBits(lo, hi);
|
|
};
|
|
|
|
/**
|
|
* Constructs new long bits from a number, long or string.
|
|
* @param {Long|number|string} value Value
|
|
* @returns {util.LongBits} Instance
|
|
*/
|
|
LongBits.from = function from(value) {
|
|
if (typeof value === "number")
|
|
return LongBits.fromNumber(value);
|
|
if (util.isString(value)) {
|
|
/* istanbul ignore else */
|
|
if (util.Long)
|
|
value = util.Long.fromString(value);
|
|
else
|
|
return LongBits.fromNumber(parseInt(value, 10));
|
|
}
|
|
return value.low || value.high ? new LongBits(value.low >>> 0, value.high >>> 0) : zero;
|
|
};
|
|
|
|
/**
|
|
* Converts this long bits to a possibly unsafe JavaScript number.
|
|
* @param {boolean} [unsigned=false] Whether unsigned or not
|
|
* @returns {number} Possibly unsafe number
|
|
*/
|
|
LongBits.prototype.toNumber = function toNumber(unsigned) {
|
|
if (!unsigned && this.hi >>> 31) {
|
|
var lo = ~this.lo + 1 >>> 0,
|
|
hi = ~this.hi >>> 0;
|
|
if (!lo)
|
|
hi = hi + 1 >>> 0;
|
|
return -(lo + hi * 4294967296);
|
|
}
|
|
return this.lo + this.hi * 4294967296;
|
|
};
|
|
|
|
/**
|
|
* Converts this long bits to a long.
|
|
* @param {boolean} [unsigned=false] Whether unsigned or not
|
|
* @returns {Long} Long
|
|
*/
|
|
LongBits.prototype.toLong = function toLong(unsigned) {
|
|
return util.Long
|
|
? new util.Long(this.lo | 0, this.hi | 0, Boolean(unsigned))
|
|
/* istanbul ignore next */
|
|
: { low: this.lo | 0, high: this.hi | 0, unsigned: Boolean(unsigned) };
|
|
};
|
|
|
|
var charCodeAt = String.prototype.charCodeAt;
|
|
|
|
/**
|
|
* Constructs new long bits from the specified 8 characters long hash.
|
|
* @param {string} hash Hash
|
|
* @returns {util.LongBits} Bits
|
|
*/
|
|
LongBits.fromHash = function fromHash(hash) {
|
|
if (hash === zeroHash)
|
|
return zero;
|
|
return new LongBits(
|
|
( charCodeAt.call(hash, 0)
|
|
| charCodeAt.call(hash, 1) << 8
|
|
| charCodeAt.call(hash, 2) << 16
|
|
| charCodeAt.call(hash, 3) << 24) >>> 0
|
|
,
|
|
( charCodeAt.call(hash, 4)
|
|
| charCodeAt.call(hash, 5) << 8
|
|
| charCodeAt.call(hash, 6) << 16
|
|
| charCodeAt.call(hash, 7) << 24) >>> 0
|
|
);
|
|
};
|
|
|
|
/**
|
|
* Converts this long bits to a 8 characters long hash.
|
|
* @returns {string} Hash
|
|
*/
|
|
LongBits.prototype.toHash = function toHash() {
|
|
return String.fromCharCode(
|
|
this.lo & 255,
|
|
this.lo >>> 8 & 255,
|
|
this.lo >>> 16 & 255,
|
|
this.lo >>> 24 ,
|
|
this.hi & 255,
|
|
this.hi >>> 8 & 255,
|
|
this.hi >>> 16 & 255,
|
|
this.hi >>> 24
|
|
);
|
|
};
|
|
|
|
/**
|
|
* Zig-zag encodes this long bits.
|
|
* @returns {util.LongBits} `this`
|
|
*/
|
|
LongBits.prototype.zzEncode = function zzEncode() {
|
|
var mask = this.hi >> 31;
|
|
this.hi = ((this.hi << 1 | this.lo >>> 31) ^ mask) >>> 0;
|
|
this.lo = ( this.lo << 1 ^ mask) >>> 0;
|
|
return this;
|
|
};
|
|
|
|
/**
|
|
* Zig-zag decodes this long bits.
|
|
* @returns {util.LongBits} `this`
|
|
*/
|
|
LongBits.prototype.zzDecode = function zzDecode() {
|
|
var mask = -(this.lo & 1);
|
|
this.lo = ((this.lo >>> 1 | this.hi << 31) ^ mask) >>> 0;
|
|
this.hi = ( this.hi >>> 1 ^ mask) >>> 0;
|
|
return this;
|
|
};
|
|
|
|
/**
|
|
* Calculates the length of this longbits when encoded as a varint.
|
|
* @returns {number} Length
|
|
*/
|
|
LongBits.prototype.length = function length() {
|
|
var part0 = this.lo,
|
|
part1 = (this.lo >>> 28 | this.hi << 4) >>> 0,
|
|
part2 = this.hi >>> 24;
|
|
return part2 === 0
|
|
? part1 === 0
|
|
? part0 < 16384
|
|
? part0 < 128 ? 1 : 2
|
|
: part0 < 2097152 ? 3 : 4
|
|
: part1 < 16384
|
|
? part1 < 128 ? 5 : 6
|
|
: part1 < 2097152 ? 7 : 8
|
|
: part2 < 128 ? 9 : 10;
|
|
};
|