Created
December 17, 2018 10:50
-
-
Save ChiChou/71d2f6a8cf11dc72200088e1ef9450a8 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { Struct } from "./utils"; | |
function operator(target, name, descriptor) { | |
const oldValue = descriptor.value; | |
descriptor.value = function() { | |
if (arguments.length != oldValue.length) | |
throw Error("Not enough arguments for function " + name); | |
for (let arg of arguments) | |
if (!(arg instanceof Int64)) | |
arguments[i] = new Int64(arg); | |
return oldValue.apply(this, arguments); | |
}; | |
return descriptor; | |
} | |
export default class Int64 { | |
constructor() { | |
this.bytes = new Uint8Array(8); | |
switch (typeof v) { | |
case 'number': | |
v = '0x' + Math.floor(v).toString(16); | |
case 'string': | |
if (v.startsWith('0x')) | |
v = v.substr(2); | |
if (v.length % 2 == 1) | |
v = '0' + v; | |
var bigEndian = unhexlify(v, 8); | |
bytes.set(Array.from(bigEndian).reverse()); | |
break; | |
case 'object': | |
if (v instanceof Int64) { | |
bytes.set(v.bytes()); | |
} else { | |
if (v.length != 8) | |
throw TypeError('Array must have excactly 8 elements.'); | |
bytes.set(v); | |
} | |
break; | |
case 'undefined': | |
break; | |
default: | |
throw TypeError('Int64 constructor requires an argument.'); | |
} | |
} | |
asDouble() { | |
// Check for NaN | |
if (bytes[7] == 0xff && (bytes[6] == 0xff || bytes[6] == 0xfe)) | |
throw new RangeError("Integer can not be represented by a double"); | |
return Struct.unpack(Struct.float64, bytes); | |
} | |
asJSValue() { | |
if ((bytes[7] == 0 && bytes[6] == 0) || (bytes[7] == 0xff && bytes[6] == 0xff)) | |
throw new RangeError("Integer can not be represented by a JSValue"); | |
// For NaN-boxing, JSC adds 2^48 to a double value's bit pattern. | |
this.assignSub(this, 0x1000000000000); | |
const res = Struct.unpack(Struct.float64, bytes); | |
this.assignAdd(this, 0x1000000000000); | |
return res; | |
} | |
bytes() { | |
return Array.from(bytes); | |
} | |
byteAt(i) { | |
return bytes[i]; | |
} | |
toString() { | |
return '0x' + hexlify(Array.from(bytes).reverse()); | |
} | |
@operator | |
assignNeg() { | |
for (let i = 0; i < 8; i++) | |
bytes[i] = ~this.byteAt(i); | |
return this.assignAdd(this, Int64.One); | |
} | |
neg() { | |
return new Int64(this).assignNeg(); | |
} | |
@operator | |
assignAdd(b) { | |
let carry = 0; | |
for (let i = 0; i < 8; i++) { | |
const cur = this.byteAt(i) + b.byteAt(i) + carry; | |
carry = cur > 0xff | 0; | |
bytes[i] = cur; | |
} | |
return this; | |
} | |
add(op) { | |
return new Int64(this).assignAdd(op); | |
} | |
@operator | |
assignSub(b) { | |
let carry = 0; | |
for (let i = 0; i < 8; i++) { | |
const cur = this.byteAt(i) - b.byteAt(i) - carry; | |
carry = cur < 0 | 0; | |
bytes[i] = cur; | |
} | |
return this; | |
} | |
sub(op) { | |
return new Int64(this).assignSub(op); | |
} | |
static fromDouble(d) { | |
const bytes = Struct.pack(Struct.float64, d); | |
return new Int64(bytes); | |
} | |
} | |
Int64.Zero = new Int64(0); | |
Int64.One = new Int64(1); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment