Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(JavaScript): enhance performance 64bits number #1320

Merged
merged 5 commits into from
Jan 9, 2024
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,10 @@
* under the License.
*/

import { Config, LATIN1 } from "./type";
import { isNodeEnv } from "./util";
import { PlatformBuffer, alloc, fromUint8Array } from "./platformBuffer";
import { read1, read10, read11, read12, read13, read14, read15, read2, read3, read4, read5, read6, read7, read8, read9 } from "./string";
import { Config, LATIN1 } from "../type";
import { isNodeEnv } from "../util";
import { PlatformBuffer, alloc, fromUint8Array } from "../platformBuffer";
import { readLatin1String } from "./string";

export const BinaryReader = (config: Config) => {
const sliceStringEnable = isNodeEnv && config.useSliceString;
Expand Down Expand Up @@ -135,42 +135,7 @@ export const BinaryReader = (config: Config) => {
function stringLatin1Slow(len: number) {
const rawCursor = cursor;
cursor += len;
switch (len) {
case 0:
return "";
case 1:
return read1(buffer, rawCursor);
case 2:
return read2(buffer, rawCursor);
case 3:
return read3(buffer, rawCursor);
case 4:
return read4(buffer, rawCursor);
case 5:
return read5(buffer, rawCursor);
case 6:
return read6(buffer, rawCursor);
case 7:
return read7(buffer, rawCursor);
case 8:
return read8(buffer, rawCursor);
case 9:
return read9(buffer, rawCursor);
case 10:
return read10(buffer, rawCursor);
case 11:
return read11(buffer, rawCursor);
case 12:
return read12(buffer, rawCursor);
case 13:
return read13(buffer, rawCursor);
case 14:
return read14(buffer, rawCursor);
case 15:
return read15(buffer, rawCursor);
default:
return buffer.latin1Slice(rawCursor, cursor);
}
return readLatin1String(buffer, len, rawCursor);
}

function binary(len: number) {
Expand All @@ -186,67 +151,137 @@ export const BinaryReader = (config: Config) => {
return result;
}

function zigZag(v: number) {
return (v >> 1) ^ -(v & 1);
}

function zigZagBigInt(v: bigint) {
return (v >> 1n) ^ -(v & 1n);
}

function varUInt32() {
let byte_ = uint8();
let result = byte_ & 0x7f;
if ((byte_ & 0x80) != 0) {
byte_ = uint8();
result |= (byte_ & 0x7f) << 7;
if ((byte_ & 0x80) != 0) {
byte_ = uint8();
result |= (byte_ & 0x7f) << 14;
if ((byte_ & 0x80) != 0) {
byte_ = uint8();
result |= (byte_ & 0x7f) << 21;
if ((byte_ & 0x80) != 0) {
byte_ = uint8();
result |= (byte_) << 28;
// Reduce memory reads as much as possible. Reading a uint32 at once is far faster than reading four uint8s separately.
if (buffer.byteLength - cursor >= 5) {
const b1 = uint8();
const u32 = dataView.getUint32(cursor, true);
theweipeng marked this conversation as resolved.
Show resolved Hide resolved
let result = b1 & 0x7f;
if ((b1 & 0x80) != 0) {
cursor++;
const b2 = u32;
result |= (b2 & 0x7f) << 7;
if ((b2 & 0x80) != 0) {
cursor++;
const b3 = u32 >> 8;
result |= (b3 & 0x7f) << 14;
if ((b3 & 0x80) != 0) {
cursor++;
const b4 = u32 >> 16;
result |= (b4 & 0x7f) << 21;
if ((b4 & 0x80) != 0) {
cursor++;
const b5 = u32 >> 24;
result |= (b5) << 28;
}
}
}
}
return result;
}
let byte = uint8();
let result = byte & 0x7f;
if ((byte & 0x80) != 0) {
byte = uint8();
result |= (byte & 0x7f) << 7;
if ((byte & 0x80) != 0) {
byte = uint8();
result |= (byte & 0x7f) << 14;
if ((byte & 0x80) != 0) {
byte = uint8();
result |= (byte & 0x7f) << 21;
if ((byte & 0x80) != 0) {
byte = uint8();
result |= (byte) << 28;
}
}
}
}
return result;
}

function varInt32() {
const v = varUInt32();
return (v >> 1) ^ -(v & 1); // zigZag decode
}

function bigUInt8() {
return BigInt(uint8() >>> 0);
}

function varUInt64() {
let byte_ = bigUInt8();
let result = byte_ & 0x7fn;
if ((byte_ & 0x80n) != 0n) {
byte_ = bigUInt8();
result |= (byte_ & 0x7fn) << 7n;
if ((byte_ & 0x80n) != 0n) {
byte_ = bigUInt8();
result |= (byte_ & 0x7fn) << 14n;
if ((byte_ & 0x80n) != 0n) {
byte_ = bigUInt8();
result |= (byte_ & 0x7fn) << 21n;
if ((byte_ & 0x80n) != 0n) {
byte_ = bigUInt8();
result |= (byte_ & 0x7fn) << 28n;
if ((byte_ & 0x80n) != 0n) {
byte_ = bigUInt8();
result |= (byte_ & 0x7fn) << 35n;
if ((byte_ & 0x80n) != 0n) {
byte_ = bigUInt8();
result |= (byte_ & 0x7fn) << 42n;
if ((byte_ & 0x80n) != 0n) {
byte_ = bigUInt8();
result |= (byte_ & 0x7fn) << 49n;
if ((byte_ & 0x80n) != 0n) {
byte_ = bigUInt8();
result |= (byte_) << 56n;
// Creating BigInts is too performance-intensive; we'll use uint32 instead.
if (buffer.byteLength - cursor < 8) {
let byte = bigUInt8();
let result = byte & 0x7fn;
if ((byte & 0x80n) != 0n) {
byte = bigUInt8();
result |= (byte & 0x7fn) << 7n;
if ((byte & 0x80n) != 0n) {
byte = bigUInt8();
result |= (byte & 0x7fn) << 14n;
if ((byte & 0x80n) != 0n) {
byte = bigUInt8();
result |= (byte & 0x7fn) << 21n;
if ((byte & 0x80n) != 0n) {
byte = bigUInt8();
result |= (byte & 0x7fn) << 28n;
if ((byte & 0x80n) != 0n) {
byte = bigUInt8();
result |= (byte & 0x7fn) << 35n;
if ((byte & 0x80n) != 0n) {
byte = bigUInt8();
result |= (byte & 0x7fn) << 42n;
if ((byte & 0x80n) != 0n) {
byte = bigUInt8();
result |= (byte & 0x7fn) << 49n;
if ((byte & 0x80n) != 0n) {
byte = bigUInt8();
result |= (byte) << 56n;
}
}
}
}
}
}
}
}
return result;
}
const l32 = dataView.getUint32(cursor++, true);
let byte = l32 & 0xff;
let rl28 = byte & 0x7f;
let rh28 = 0;
if ((byte & 0x80) != 0) {
byte = l32 & 0xff00 >> 8;
cursor++;
rl28 |= (byte & 0x7f) << 7;
if ((byte & 0x80) != 0) {
byte = l32 & 0xff0000 >> 16;
cursor++;
rl28 |= (byte & 0x7f) << 14;
if ((byte & 0x80) != 0) {
byte = l32 & 0xff000000 >> 24;
cursor++;
rl28 |= (byte & 0x7f) << 21;
if ((byte & 0x80) != 0) {
const h32 = dataView.getUint32(cursor++, true);
byte = h32 & 0xff;
rh28 |= (byte & 0x7f);
if ((byte & 0x80) != 0) {
byte = h32 & 0xff00 >> 8;
cursor++;
rh28 |= (byte & 0x7f) << 7;
if ((byte & 0x80) != 0) {
byte = h32 & 0xff0000 >> 16;
cursor++;
rh28 |= (byte & 0x7f) << 14;
if ((byte & 0x80) != 0) {
byte = h32 & 0xff000000 >> 24;
cursor++;
rh28 |= (byte & 0x7f) << 21;
if ((byte & 0x80) != 0) {
return (BigInt(uint8()) << 56n) | BigInt(rh28) << 28n | BigInt(rl28);
}
}
}
Expand All @@ -255,15 +290,13 @@ export const BinaryReader = (config: Config) => {
}
}
}
return result;
}

function varInt32() {
return zigZag(varUInt32());
return BigInt(rh28) << 28n | BigInt(rl28);
}

function varInt64() {
return zigZagBigInt(varUInt64());
const v = varUInt64();
return (v >> 1n) ^ -(v & 1n); // zigZag decode
}

return {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,48 +17,89 @@
* under the License.
*/

export const read1 = (buffer: Uint8Array, cursor: number) => {
import { PlatformBuffer } from "../platformBuffer";

const read1 = (buffer: Uint8Array, cursor: number) => {
return String.fromCharCode(buffer[cursor]);
};
export const read2 = (buffer: Uint8Array, cursor: number) => {
const read2 = (buffer: Uint8Array, cursor: number) => {
return String.fromCharCode(buffer[cursor], buffer[cursor + 1]);
};
export const read3 = (buffer: Uint8Array, cursor: number) => {
const read3 = (buffer: Uint8Array, cursor: number) => {
return String.fromCharCode(buffer[cursor], buffer[cursor + 1], buffer[cursor + 2]);
};
export const read4 = (buffer: Uint8Array, cursor: number) => {
const read4 = (buffer: Uint8Array, cursor: number) => {
return String.fromCharCode(buffer[cursor], buffer[cursor + 1], buffer[cursor + 2], buffer[cursor + 3]);
};
export const read5 = (buffer: Uint8Array, cursor: number) => {
const read5 = (buffer: Uint8Array, cursor: number) => {
return String.fromCharCode(buffer[cursor], buffer[cursor + 1], buffer[cursor + 2], buffer[cursor + 3], buffer[cursor + 4]);
};
export const read6 = (buffer: Uint8Array, cursor: number) => {
const read6 = (buffer: Uint8Array, cursor: number) => {
return String.fromCharCode(buffer[cursor], buffer[cursor + 1], buffer[cursor + 2], buffer[cursor + 3], buffer[cursor + 4], buffer[cursor + 5]);
};
export const read7 = (buffer: Uint8Array, cursor: number) => {
const read7 = (buffer: Uint8Array, cursor: number) => {
return String.fromCharCode(buffer[cursor], buffer[cursor + 1], buffer[cursor + 2], buffer[cursor + 3], buffer[cursor + 4], buffer[cursor + 5], buffer[cursor + 6]);
};
export const read8 = (buffer: Uint8Array, cursor: number) => {
const read8 = (buffer: Uint8Array, cursor: number) => {
return String.fromCharCode(buffer[cursor], buffer[cursor + 1], buffer[cursor + 2], buffer[cursor + 3], buffer[cursor + 4], buffer[cursor + 5], buffer[cursor + 6], buffer[cursor + 7]);
};
export const read9 = (buffer: Uint8Array, cursor: number) => {
const read9 = (buffer: Uint8Array, cursor: number) => {
return String.fromCharCode(buffer[cursor], buffer[cursor + 1], buffer[cursor + 2], buffer[cursor + 3], buffer[cursor + 4], buffer[cursor + 5], buffer[cursor + 6], buffer[cursor + 7], buffer[cursor + 8]);
};
export const read10 = (buffer: Uint8Array, cursor: number) => {
const read10 = (buffer: Uint8Array, cursor: number) => {
return String.fromCharCode(buffer[cursor], buffer[cursor + 1], buffer[cursor + 2], buffer[cursor + 3], buffer[cursor + 4], buffer[cursor + 5], buffer[cursor + 6], buffer[cursor + 7], buffer[cursor + 8], buffer[cursor + 9]);
};
export const read11 = (buffer: Uint8Array, cursor: number) => {
const read11 = (buffer: Uint8Array, cursor: number) => {
return String.fromCharCode(buffer[cursor], buffer[cursor + 1], buffer[cursor + 2], buffer[cursor + 3], buffer[cursor + 4], buffer[cursor + 5], buffer[cursor + 6], buffer[cursor + 7], buffer[cursor + 8], buffer[cursor + 9], buffer[cursor + 10]);
};
export const read12 = (buffer: Uint8Array, cursor: number) => {
const read12 = (buffer: Uint8Array, cursor: number) => {
return String.fromCharCode(buffer[cursor], buffer[cursor + 1], buffer[cursor + 2], buffer[cursor + 3], buffer[cursor + 4], buffer[cursor + 5], buffer[cursor + 6], buffer[cursor + 7], buffer[cursor + 8], buffer[cursor + 9], buffer[cursor + 10], buffer[cursor + 11]);
};
export const read13 = (buffer: Uint8Array, cursor: number) => {
const read13 = (buffer: Uint8Array, cursor: number) => {
return String.fromCharCode(buffer[cursor], buffer[cursor + 1], buffer[cursor + 2], buffer[cursor + 3], buffer[cursor + 4], buffer[cursor + 5], buffer[cursor + 6], buffer[cursor + 7], buffer[cursor + 8], buffer[cursor + 9], buffer[cursor + 10], buffer[cursor + 11], buffer[cursor + 12]);
};
export const read14 = (buffer: Uint8Array, cursor: number) => {
const read14 = (buffer: Uint8Array, cursor: number) => {
return String.fromCharCode(buffer[cursor], buffer[cursor + 1], buffer[cursor + 2], buffer[cursor + 3], buffer[cursor + 4], buffer[cursor + 5], buffer[cursor + 6], buffer[cursor + 7], buffer[cursor + 8], buffer[cursor + 9], buffer[cursor + 10], buffer[cursor + 11], buffer[cursor + 12], buffer[cursor + 13]);
};
export const read15 = (buffer: Uint8Array, cursor: number) => {
const read15 = (buffer: Uint8Array, cursor: number) => {
return String.fromCharCode(buffer[cursor], buffer[cursor + 1], buffer[cursor + 2], buffer[cursor + 3], buffer[cursor + 4], buffer[cursor + 5], buffer[cursor + 6], buffer[cursor + 7], buffer[cursor + 8], buffer[cursor + 9], buffer[cursor + 10], buffer[cursor + 11], buffer[cursor + 12], buffer[cursor + 13], buffer[cursor + 14]);
};

export const readLatin1String = (buffer: PlatformBuffer, len: number, cursor: number) => {
switch (len) {
case 0:
return "";
case 1:
return read1(buffer, cursor);
case 2:
return read2(buffer, cursor);
case 3:
return read3(buffer, cursor);
case 4:
return read4(buffer, cursor);
case 5:
return read5(buffer, cursor);
case 6:
return read6(buffer, cursor);
case 7:
return read7(buffer, cursor);
case 8:
return read8(buffer, cursor);
case 9:
return read9(buffer, cursor);
case 10:
return read10(buffer, cursor);
case 11:
return read11(buffer, cursor);
case 12:
return read12(buffer, cursor);
case 13:
return read13(buffer, cursor);
case 14:
return read14(buffer, cursor);
case 15:
return read15(buffer, cursor);
default:
return buffer.latin1Slice(cursor, cursor + len);
}
};
Loading
Loading