/
number.ts
81 lines (70 loc) · 2.85 KB
/
number.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
import JSBI from "jsbi";
import { BytePrefix } from "./prefix";
export function writeNumberForBinaryEncodingJSBI(hash: number) {
let payload = encodeNumberAsUInt64JSBI(hash);
let outputStream = Buffer.from(BytePrefix.Number, "hex");
const firstChunk = JSBI.asUintN(64, JSBI.signedRightShift(payload, JSBI.BigInt(56)));
outputStream = Buffer.concat([outputStream, Buffer.from(firstChunk.toString(16), "hex")]);
payload = JSBI.asUintN(64, JSBI.leftShift(JSBI.BigInt(payload), JSBI.BigInt(0x8)));
let byteToWrite = JSBI.BigInt(0);
let firstIteration = false;
let shifted: JSBI;
let padded: string;
do {
if (!firstIteration) {
// we pad because after shifting because we will produce characters like "f" or similar,
// which cannot be encoded as hex in a buffer because they are invalid hex
// https://github.com/nodejs/node/issues/24491
padded = byteToWrite.toString(16).padStart(2, "0");
if (padded !== "00") {
outputStream = Buffer.concat([outputStream, Buffer.from(padded, "hex")]);
}
} else {
firstIteration = false;
}
shifted = JSBI.asUintN(64, JSBI.signedRightShift(payload, JSBI.BigInt(56)));
byteToWrite = JSBI.asUintN(64, JSBI.bitwiseOr(shifted, JSBI.BigInt(0x01)));
payload = JSBI.asUintN(64, JSBI.leftShift(payload, JSBI.BigInt(7)));
} while (JSBI.notEqual(payload, JSBI.BigInt(0)));
const lastChunk = JSBI.asUintN(64, JSBI.bitwiseAnd(byteToWrite, JSBI.BigInt(0xfe)));
// we pad because after shifting because we will produce characters like "f" or similar,
// which cannot be encoded as hex in a buffer because they are invalid hex
// https://github.com/nodejs/node/issues/24491
padded = lastChunk.toString(16).padStart(2, "0");
if (padded !== "00") {
outputStream = Buffer.concat([outputStream, Buffer.from(padded, "hex")]);
}
return outputStream;
}
function encodeNumberAsUInt64JSBI(value: number) {
const rawValueBits = getRawBitsJSBI(value);
const mask = JSBI.BigInt(0x8000000000000000);
const returned =
rawValueBits < mask
? JSBI.bitwiseXor(rawValueBits, mask)
: JSBI.add(JSBI.bitwiseNot(rawValueBits), JSBI.BigInt(1));
return returned;
}
export function doubleToByteArrayJSBI(double: number) {
const output: Buffer = Buffer.alloc(8);
const lng = getRawBitsJSBI(double);
for (let i = 0; i < 8; i++) {
output[i] = JSBI.toNumber(
JSBI.bitwiseAnd(
JSBI.signedRightShift(lng, JSBI.multiply(JSBI.BigInt(i), JSBI.BigInt(8))),
JSBI.BigInt(0xff)
)
);
}
return output;
}
function getRawBitsJSBI(value: number) {
const view = new DataView(new ArrayBuffer(8));
view.setFloat64(0, value);
return JSBI.BigInt(`0x${buf2hex(view.buffer)}`);
}
function buf2hex(buffer: ArrayBuffer) {
return Array.prototype.map
.call(new Uint8Array(buffer), (x: number) => ("00" + x.toString(16)).slice(-2))
.join("");
}