diffusion
Version:
Diffusion JavaScript client
182 lines (140 loc) • 4.42 kB
JavaScript
var _implements = require('util/interface')._implements;
var Int64 = require('../../../data/primitive/int64');
var P16 = 1 << 16;
var P24 = 1 << 24;
var P32 = P16 * P16;
function putInt32(value, buffer, high) {
var offset = high ? 0 : 4;
for (var i = 3; i >= 0; --i) {
buffer[offset + i] = value & 255;
value = value >> 8;
}
}
function getInt32(buffer, high) {
var offset = high ? 0 : 4;
return (buffer[offset] * P24) +
(buffer[offset + 1] << 16) +
(buffer[offset + 2] << 8) +
buffer[offset + 3];
}
function putPositiveNumber(value, buffer) {
for (var i = 7; i >= 0; --i) {
buffer[i] = value & 255;
value /= 256;
}
}
function putNegativeNumber(value, buffer) {
value++;
for (var i = 7; i >= 0; --i) {
buffer[i] = ((-value) & 255) ^ 255;
value /= 256;
}
}
function putString(value, radix, buffer) {
radix = radix || 10;
var negative = value[0] === "-";
if (negative) {
value = value.substring(1);
} else if (value.substring(0, 2) === "0x") {
value = value.substring(2);
radix = 16;
}
var high = 0;
var low = 0;
for (var i = 0; i < value.length; ++i) {
low = low * radix + parseInt(value[i], radix);
high = high * radix + Math.floor(low / P32);
low %= P32;
}
if (negative) {
high = ~high;
if (low) {
low = P32 - low;
} else {
high++;
}
}
putInt32(high, buffer, true);
putInt32(low, buffer, false);
}
/**
* Implementation of signed 64-bit integer. May be constructed from a buffer, string or number.
*/
module.exports = _implements(Int64, function Int64Impl(value, radix) {
var buffer = new Buffer([0, 0, 0, 0, 0, 0, 0, 0]);
if (Buffer.isBuffer(value)) {
buffer = value;
}
if (typeof value === 'string') {
putString(value, radix, buffer);
}
if (typeof value === 'number') {
// Explicit high/low bits
if (typeof radix === 'number') {
putInt32(value, buffer, true);
putInt32(radix, buffer, false);
} else if (value >= 0) {
putPositiveNumber(value, buffer);
} else {
putNegativeNumber(value, buffer);
}
}
if (value instanceof Int64Impl) {
putInt32(value.getHighBits(), buffer, true);
putInt32(value.getLowBits(), buffer, false);
}
this.getHighBits = function() {
return getInt32(buffer, true);
};
this.getLowBits = function() {
return getInt32(buffer, false);
};
this.toBuffer = function() {
return buffer;
};
this.toNumber = function() {
var high = this.getHighBits() | 0;
var low = this.getLowBits();
// This is a lossy operation - see docs. Will be accurate for numbers up to 2 ^ 53
return high ? high * P32 + low : low;
};
this.isNegative = function() {
return this.getHighBits() & 0x80000000;
};
this.toString = function(radix) {
radix = radix || 10;
var high = this.getHighBits();
var low = this.getLowBits();
var sign = this.isNegative();
if (sign) {
high = ~high;
low = P32 - low;
}
if (high === 0 && low === 0) {
return "0";
}
var result = "";
while (high || low) {
// Multiply modulo remainder up to its "real" value (since it represents the top 32 bits of a single value)
var rem = (high % radix) * P32 + low;
// Divide by radix, essentially reducing the high/low values by the digits we've taken from the modulo
// remainder. We can't use bitwise operations to coerce to integer, as that would truncate to 32 bits
high = Math.floor(high / radix);
low = Math.floor(rem / radix);
result = (rem % radix).toString(radix) + result;
}
if (sign) {
result = "-" + result;
}
return result;
};
this.equals = function(other) {
if (other && other instanceof Int64Impl) {
return this.getHighBits() === other.getHighBits() && this.getLowBits() === other.getLowBits();
}
return false;
};
});
module.exports.toString = function() {
return "Int64Impl";
};