Spaces:
Sleeping
Sleeping
File size: 1,801 Bytes
2a1c46d | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 | // entityTries.js
// Builds integer-keyed tries so the decoder never allocates a string object
// during lookup β every key is a plain charCode number.
//
// trie1: Map<code0, entity>
// trie2: Map<code0, Map<code1, entity>>
// trie3: Map<code0, Map<code1, Map<code2, entity>>>
import { ALL_ENTITIES } from './entities.js';
// Reverse map: character sequence β "&name;"
const CHAR_TO_ENTITY = new Map();
for (const [name, chars] of Object.entries(ALL_ENTITIES)) {
CHAR_TO_ENTITY.set(chars, `&${name};`);
}
export const trie1 = new Map(); // code0 β entity string
export const trie2 = new Map(); // code0 β Map β entity string
export const trie3 = new Map(); // code0 β Map β Map β entity string
for (const [chars, entity] of CHAR_TO_ENTITY) {
const len = chars.length;
if (len === 1) {
const c0 = chars.charCodeAt(0);
// Keep shortest match only if no longer match already claimed this code
// (longer matches are inserted in the same pass so we just overwrite β
// trie1 is only consulted after trie2/trie3 both miss, so no conflict)
trie1.set(c0, entity);
} else if (len === 2) {
const c0 = chars.charCodeAt(0);
const c1 = chars.charCodeAt(1);
let inner = trie2.get(c0);
if (inner === undefined) { inner = new Map(); trie2.set(c0, inner); }
inner.set(c1, entity);
} else if (len === 3) {
const c0 = chars.charCodeAt(0);
const c1 = chars.charCodeAt(1);
const c2 = chars.charCodeAt(2);
let mid = trie3.get(c0);
if (mid === undefined) { mid = new Map(); trie3.set(c0, mid); }
let inner = mid.get(c1);
if (inner === undefined) { inner = new Map(); mid.set(c1, inner); }
inner.set(c2, entity);
}
// HTML5 has no named entity whose character sequence is longer than 3 chars
} |