UNPKG

spica

Version:

Supervisor, Coroutine, Channel, select, AtomicPromise, Cancellation, Cache, List, Queue, Stack, and some utils.

78 lines (70 loc) 2.29 kB
import { min } from './alias'; /* ASCII文字のパーセントエンコーディングを避ければマルチバイト文字のみのエンコーディングとなるため 常に2単位以上の圧縮となる。2単位での圧縮率でもデルタ25%、ハフマン33%となるためハフマンを採用。 */ const ASCII = [...Array(256)].reduce<string>((acc, _, i) => acc + String.fromCharCode(i), ''); function isHEX(code: number): boolean { return 0x41 <= code && code < 0x47 || 0x30 <= code && code < 0x3a; } interface Options { start: number; next: number; } export function encode(input: string, table: Uint8Array, opts: Options): string { let output = ''; let buffer = 0; let count = 0; for (let i = opts.next = opts.start; i + 2 < input.length; opts.next = ++i) { if (input[i] !== '%') break; const code1 = input.charCodeAt(++i); if (!isHEX(code1)) break; const code2 = input.charCodeAt(++i); if (!isHEX(code2)) break; const delta1 = table[code1]; assert(delta1 >>> 4 === 0); const delta2 = table[code2]; assert(delta2 >>> 4 === 0); const hcode = 1 << 8 | delta1 << 4 | delta2; let hlen = 9; while (hlen !== 0) { assert(count < 8); const cnt = min(hlen, 8 - count); assert(cnt > 0); buffer |= (hcode >>> hlen - cnt & (1 << cnt) - 1) << 8 - count - cnt; assert(buffer >>> 8 === 0); count += cnt; assert(count <= 8); hlen -= cnt; assert(hlen >= 0); if (count !== 8) continue; output += ASCII[buffer]; buffer = 0; count = 0; } } if (count !== 0) { assert(count < 8); output += ASCII[buffer]; } assert(output.length <= input.length); return output; } export function decode(input: string, table: Uint8Array, opts: Options): string { let output = ''; let buffer = 0; let count = 0; for (let i = opts.next = opts.start; i < input.length; opts.next = ++i) { buffer <<= 8; buffer |= input.charCodeAt(i); count += 8; assert(count <= 16); if ((buffer >>> count - 1 & 1) === 0) break; if (count < 9) continue; const delta = buffer >>> count - 9 & 0xff; output += `%${ASCII[table[delta >>> 4]]}${ASCII[table[delta & 0x0f]]}`; count -= 9; } return output; }