From f5f9e050717ad0b983d2d11f9038affbc360ae8f Mon Sep 17 00:00:00 2001 From: Raymond Hill Date: Tue, 30 Apr 2019 06:47:54 -0400 Subject: [PATCH] Order HNTrie nodes alphabetically to allow for early bailout This commit implements the alphabetical ordering of HNTrie nodes, so as to make it possible to bail out early at HNTrie.matches() time. Contrary to what I expected, there is no performance gain observed to HNTrie.matches() as per benchmarks -- I find the results perplexing. Because of this I will revert this commit immediately. The purpose of this commit is to record the changes so that I can bring them back to life in the future whenever I want to investigate further. --- src/js/hntrie.js | 42 ++++++++++++++++++++++++++++++++++-------- 1 file changed, 34 insertions(+), 8 deletions(-) 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;