UNPKG

diginext-utils

Version:
158 lines 4.83 kB
// 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