a collection of lightweight TypeScript packages for AT Protocol, the protocol powering Bluesky

refactor(tid): faster encode/decode

mary.my.id a46b7efd a891529d

verified
+39 -9
+1 -1
.changeset/bright-snails-hide.md
··· 2 2 '@atcute/cbor': patch 3 3 --- 4 4 5 - quickly bail out to slow path on server runtimes 5 + quickly bail out to slow path on server runtimes
+5
.changeset/little-bars-care.md
··· 1 + --- 2 + '@atcute/tid': patch 3 + --- 4 + 5 + faster encode/decode
+5 -5
packages/utilities/tid/lib/index.ts
··· 2 2 3 3 import { random } from '#platform/random'; 4 4 5 - import { s32decode, s32encode } from './s32.ts'; 5 + import { S32_2CHAR_TABLE, s32decode, s32encode } from './s32.ts'; 6 6 7 7 let lastTimestamp = 0; 8 8 let lastCurrentTime = 0; ··· 13 13 * Creates a TID based off provided timestamp and clockid, with no validation. 14 14 */ 15 15 export const createRaw = (timestamp: number, clockid: number): string => { 16 - return s32encode(timestamp).padStart(11, '2') + s32encode(clockid).padStart(2, '2'); 16 + return s32encode(timestamp).padStart(11, '2') + S32_2CHAR_TABLE[clockid]!; 17 17 }; 18 18 19 19 /** ··· 59 59 throw new Error(`invalid TID`); 60 60 } 61 61 62 - const timestamp = s32decode(tid.slice(0, 11)); 63 - const clockid = s32decode(tid.slice(11, 13)); 62 + const timestamp = s32decode(tid, 0, 11); 63 + const clockid = s32decode(tid, 11, 2); 64 64 65 - return { timestamp: timestamp, clockid: clockid }; 65 + return { timestamp, clockid }; 66 66 }; 67 67 68 68 /**
+28 -3
packages/utilities/tid/lib/s32.ts
··· 1 1 const S32_CHAR = '234567abcdefghijklmnopqrstuvwxyz'; 2 2 3 + const S32_DECODE_TABLE = (() => { 4 + const table = new Int16Array(123); 5 + table.fill(-1); 6 + 7 + for (let i = 0; i < S32_CHAR.length; i++) { 8 + const code = S32_CHAR.charCodeAt(i); 9 + table[code] = i; 10 + } 11 + 12 + return table; 13 + })(); 14 + 15 + export const S32_2CHAR_TABLE = (() => { 16 + const table = Array.from<string>({ length: 1024 }); 17 + 18 + for (let i = 0; i < 1024; i++) { 19 + const hi = S32_CHAR.charAt((i >> 5) & 31); 20 + const lo = S32_CHAR.charAt(i & 31); 21 + table[i] = hi + lo; 22 + } 23 + 24 + return table; 25 + })(); 26 + 3 27 export const s32encode = (i: number): string => { 4 28 let s = ''; 5 29 ··· 12 36 return s; 13 37 }; 14 38 15 - export const s32decode = (s: string): number => { 39 + export const s32decode = (s: string, offset: number, length: number): number => { 16 40 let i = 0; 41 + const end = offset + length; 17 42 18 - for (const c of s) { 19 - i = i * 32 + S32_CHAR.indexOf(c); 43 + for (let idx = offset; idx < end; idx++) { 44 + i = i * 32 + S32_DECODE_TABLE[s.charCodeAt(idx)]!; 20 45 } 21 46 22 47 return i;