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

Utils: Optimize hex buffer conversion functions #10818

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open
Changes from all 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
84 changes: 75 additions & 9 deletions lib/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -413,19 +413,85 @@ export function formatSQLArray(arr: unknown[], args?: unknown[]) {
return [...'?'.repeat(arr.length)].join(', ');
}

export function bufFromHex(hex: string) {
const buf = new Uint8Array(Math.ceil(hex.length / 2));
bufWriteHex(buf, hex);
/**
* Nibble lookup table to convert ASCII character codes to their hexadecimal values (0-15).
* Invalid characters are marked with 0xFF.
*/
const nibbleLookup = (() => {
const lookup = new Uint8Array(256);
for (let i = 0; i < 256; i++) {
lookup[i] = 0xFF; // Mark as invalid by default
}
'0123456789abcdef'.split('').forEach((char, index) => {
lookup[char.charCodeAt(0)] = index;
});
'0123456789ABCDEF'.split('').forEach((char, index) => {
lookup[char.charCodeAt(0)] = index;
});
return lookup;
})();

/**
* Byte-to-hex lookup table for efficient conversion from bytes to hexadecimal strings.
*/
const byteToHexTable = (() => {
const table = new Array<string>(256);
for (let i = 0; i < 256; i++) {
table[i] = (i < 16 ? '0' : '') + i.toString(16);
}
return table;
})();

export function bufFromHex(hex: string): Uint8Array {
const len = hex.length;
const buf = new Uint8Array(Math.ceil(len / 2));
let j = 0;

for (let i = 0; i < len; i += 2) {
const hiChar = hex.charCodeAt(i);
const loChar = i + 1 < len ? hex.charCodeAt(i + 1) : 0x30; // '0' if no character
const hi = nibbleLookup[hiChar];
const lo = nibbleLookup[loChar];

if (hi === 0xFF || lo === 0xFF) {
throw new Error(
`Invalid hex character encountered: '${hex[i]}' or '${hex[i + 1] || '0'}'`
);
}

buf[j++] = (hi << 4) | lo;
}

return buf;
}
export function bufWriteHex(buf: Uint8Array, hex: string, offset = 0) {
const size = Math.ceil(hex.length / 2);
for (let i = 0; i < size; i++) {
buf[offset + i] = parseInt(hex.slice(i * 2, i * 2 + 2).padEnd(2, '0'), 16);

export function bufWriteHex(buf: Uint8Array, hex: string, offset = 0): void {
const len = hex.length;
let j = offset;

for (let i = 0; i < len; i += 2) {
const hiChar = hex.charCodeAt(i);
const loChar = i + 1 < len ? hex.charCodeAt(i + 1) : 0x30; // '0' if no character
const hi = nibbleLookup[hiChar];
const lo = nibbleLookup[loChar];

if (hi === 0xFF || lo === 0xFF) {
throw new Error(
`Invalid hex character encountered: '${hex[i]}' or '${hex[i + 1] || '0'}'`
);
}

buf[j++] = (hi << 4) | lo;
}
}
export function bufReadHex(buf: Uint8Array, start = 0, end?: number) {
return [...buf.slice(start, end)].map(val => val.toString(16).padStart(2, '0')).join('');

export function bufReadHex(buf: Uint8Array, start = 0, end?: number): string {
if (end === undefined) end = buf.length;
let out = '';
for (let i = start; i < end; i++) {
out += byteToHexTable[buf[i]];
}
return out;
}

export class Multiset<T> extends Map<T, number> {
Expand Down
Loading