diff --git a/src/js/hntrie.js b/src/js/hntrie.js index 366451af3..01c9c430d 100644 --- a/src/js/hntrie.js +++ b/src/js/hntrie.js @@ -181,12 +181,14 @@ const HNTrieContainer = class { if ( ineedle === 0 ) { return -1; } ineedle -= 1; let c = this.buf[ineedle]; - let v, i0; + let v, i0, diff; // find first segment with a first-character match for (;;) { v = this.buf32[icell+2]; i0 = char0 + (v & 0x00FFFFFF); - if ( this.buf[i0] === c ) { break; } + diff = this.buf[i0] - c; + if ( diff === 0 ) { break; } + if ( diff > 0 ) { return -1; } icell = this.buf32[icell+0]; if ( icell === 0 ) { return -1; } } @@ -254,7 +256,7 @@ const HNTrieContainer = class { } // const char0 = this.buf32[HNTRIE_CHAR0_SLOT]; - let inext; + let iprevious = iroot, diff, inext; // find a matching cell: move down for (;;) { const vseg = this.buf32[icell+2]; @@ -263,21 +265,38 @@ const HNTrieContainer = class { // remainder is at label boundary? if yes, no need to add // the rest since the shortest match is always reported if ( this.buf[lhnchar-1] === 0x2E /* '.' */ ) { return -1; } + iprevious = icell; icell = this.buf32[icell+1]; continue; } let isegchar0 = char0 + (vseg & 0x00FFFFFF); // if first character is no match, move to next descendant - if ( this.buf[isegchar0] !== this.buf[lhnchar-1] ) { + diff = this.buf[isegchar0] - this.buf[lhnchar-1]; + // current cell character greater than target character: insert + // a new node before current cell + if ( diff > 0 ) { + const inew = this.addCell(icell, 0, this.addSegment(lhnchar)); + if ( icell === this.buf32[iprevious+0] ) { + this.buf32[iprevious+0] = inew; + } else /* if ( icell === this.buf32[iprevious+1] ) */ { + this.buf32[iprevious+1] = inew; + } + return 1; + } + // current cell character lesser than target character: keep + // looking + if ( diff !== 0 ) { inext = this.buf32[icell+0]; + // no match found: insert a new leaf descendant if ( inext === 0 ) { this.buf32[icell+0] = this.addCell(0, 0, this.addSegment(lhnchar)); return 1; } + iprevious = icell; icell = inext; continue; } - // 1st character was tested + // current cell character matches: 1st character was tested let isegchar = 1; lhnchar -= 1; // find 1st mismatch in rest of segment @@ -286,7 +305,8 @@ const HNTrieContainer = class { for (;;) { if ( isegchar === lsegchar ) { break; } if ( lhnchar === 0 ) { break; } - if ( this.buf[isegchar0+isegchar] !== this.buf[lhnchar-1] ) { break; } + diff = this.buf[isegchar0+isegchar] - this.buf[lhnchar-1]; + if ( diff !== 0 ) { break; } isegchar += 1; lhnchar -= 1; } @@ -304,6 +324,7 @@ const HNTrieContainer = class { // needle remainder: yes else { if ( inext !== 0 ) { + iprevious = icell; icell = inext; continue; } @@ -326,14 +347,19 @@ const HNTrieContainer = class { this.buf32[icell+1], lsegchar - isegchar << 24 | isegchar0 + isegchar ); - this.buf32[icell+1] = inext; // needle remainder: no = need boundary cell if ( lhnchar === 0 ) { this.buf32[icell+1] = this.addCell(0, inext, 0); } // needle remainder: yes = need new cell for remaining characters else { - this.buf32[inext+0] = this.addCell(0, 0, this.addSegment(lhnchar)); + const isegment = this.addSegment(lhnchar); + if ( diff > 0 ) { + this.buf32[icell+1] = this.addCell(inext, 0, isegment); + } else { + this.buf32[icell+1] = inext; + this.buf32[inext+0] = this.addCell(0, 0, isegment); + } } } return 1;