diginext-utils
Version:
README.md
158 lines • 4.83 kB
JavaScript
// const CHARS_BIGINT = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
const CHARS_BIGINT = 'cw7x5ke6iaIUbyS0Lh2nYPW3RqjOHEurB8TDlNmVzXop4sfdGAC1g9vZtJKQMF';
const BASE = BigInt(62);
// Pre-computed lookup table for decoding (array is faster than object)
const DECODE_MAP = (() => {
const map = new Array(123).fill(-1);
const chars = CHARS_BIGINT;
for (let i = 0; i < 62; i++) {
map[chars.charCodeAt(i)] = i;
}
return map;
})();
// Pre-computed base-62 characters as array (faster than string indexing)
const CHARS = CHARS_BIGINT.split('');
/**
* Convert number to base-62 (optimized for numbers up to MAX_SAFE_INTEGER)
*/
export function toBase62(num) {
var _a;
if (num === 0)
return '0';
const isNeg = num < 0;
let n = isNeg ? -num : num;
// Fixed buffer - max 11 chars for safe integer + sign
let i = 12;
const buf = new Array(13);
while (n > 0) {
buf[i--] = (_a = CHARS[n % 62]) !== null && _a !== void 0 ? _a : '';
n = Math.floor(n / 62); // Use Math.floor for large numbers (bitwise fails > 2^31)
}
if (isNeg)
buf[i--] = '-';
// Join from position i+1 to end
let result = '';
for (let j = i + 1; j <= 12; j++) {
result += buf[j];
}
return result;
}
/**
* Convert base-62 to number (optimized)
*/
export function fromBase62(str) {
const len = str.length;
if (len === 0 || str === '0')
return 0;
const isNeg = str.charCodeAt(0) === 45; // '-' = 45
let result = 0;
for (let i = isNeg ? 1 : 0; i < len; i++) {
const val = DECODE_MAP[str.charCodeAt(i)] || 0;
if (val === -1) {
throw new Error(`Invalid character '${str[i]}'`);
}
result = result * 62 + val;
}
return isNeg ? -result : result;
}
// ============== BigInt versions for arbitrary precision ==============
/**
* Convert BigInt to base-62
*/
export function toBase62Big(num) {
if (num === BigInt(0))
return '0';
const isNeg = num < BigInt(0);
let n = isNeg ? -num : num;
let result = '';
while (n > BigInt(0)) {
result = CHARS_BIGINT[Number(n % BASE)] + result;
n = n / BASE;
}
return isNeg ? '-' + result : result;
}
/**
* Convert base-62 to BigInt
*/
export function fromBase62Big(str) {
const len = str.length;
if (len === 0 || str === '0')
return BigInt(0);
const isNeg = str[0] === '-';
let result = BigInt(0);
for (let i = isNeg ? 1 : 0; i < len; i++) {
const val = DECODE_MAP[str.charCodeAt(i)] || 0;
if (val === -1) {
throw new Error(`Invalid character '${str[i]}'`);
}
result = result * BASE + BigInt(val);
}
return isNeg ? -result : result;
}
// // ============== Benchmark ==============
// console.log('Running benchmarks...\n');
// console.time('Encode 100k numbers');
// for (let i = 0; i < 100000; i++) {
// toBase62(i * 12345);
// }
// console.timeEnd('Encode 100k numbers');
// console.time('Decode 100k strings');
// for (let i = 0; i < 100000; i++) {
// fromBase62(toBase62(i * 12345));
// }
// console.timeEnd('Decode 100k strings');
// console.time('Encode 100k BigInt');
// for (let i = 0n; i < 100000n; i++) {
// toBase62Big(i * 12345n);
// }
// console.timeEnd('Encode 100k BigInt');
// console.time('Decode 100k BigInt');
// for (let i = 0n; i < 100000n; i++) {
// fromBase62Big(toBase62Big(i * 12345n));
// }
// console.timeEnd('Decode 100k BigInt');
// // Correctness test
// console.log('\nCorrectness test (number):');
// const testValues = [
// 0,
// 1,
// 2,
// 61,
// 62,
// 63,
// 66,
// -1,
// -62,
// 255,
// 131292,
// 13121992,
// 65535,
// 16777215,
// 4294967295,
// Number.MAX_SAFE_INTEGER,
// ];
// let allPassed = true;
// for (const n of testValues) {
// const encoded = toBase62(n);
// const decoded = fromBase62(encoded);
// const passed = decoded === n;
// if (!passed) allPassed = false;
// console.log(`${n} -> "${encoded}" -> ${decoded} ${passed ? '✓' : '✗ FAILED'}`);
// }
// console.log('\nCorrectness test (BigInt):');
// const testBigValues = [0n, 1n, 61n, 62n, -1n, 255n, 4294967295n, 9007199254740991n, 123456789012345678901234567890n];
// for (const n of testBigValues) {
// const encoded = toBase62Big(n);
// const decoded = fromBase62Big(encoded);
// const passed = decoded === n;
// if (!passed) allPassed = false;
// console.log(`${n} -> "${encoded}" -> ${decoded} ${passed ? '✓' : '✗ FAILED'}`);
// }
// console.log(`\nAll tests ${allPassed ? 'PASSED ✓' : 'FAILED ✗'}`);
// // Examples
// console.log('\nExamples:');
// [255, 65535, 16777215, 4294967295].forEach((n) => {
// const enc = toBase62(n);
// console.log(`${n} -> "${enc}" (${enc.length} chars)`);
// });
//# sourceMappingURL=base62.js.map