From b798f30f16fdfa55a4df5d2d5d30074c68c10d1e Mon Sep 17 00:00:00 2001 From: Aras Abbasi Date: Tue, 20 Feb 2024 09:59:14 +0100 Subject: [PATCH] perf: improve TernarySearchTree (#2782) Co-authored-by: tsctx <91457664+tsctx@users.noreply.github.com> --- benchmarks/TernarySearchTree.mjs | 20 ++++++++++++++++++++ lib/core/tree.js | 6 +++++- test/node-test/tree.js | 7 +++++++ 3 files changed, 32 insertions(+), 1 deletion(-) create mode 100644 benchmarks/TernarySearchTree.mjs diff --git a/benchmarks/TernarySearchTree.mjs b/benchmarks/TernarySearchTree.mjs new file mode 100644 index 00000000000..413288a6af3 --- /dev/null +++ b/benchmarks/TernarySearchTree.mjs @@ -0,0 +1,20 @@ +import { bench, group, run } from 'mitata' +import { tree } from '../lib/core/tree.js' + +const contentLength = Buffer.from('Content-Length') +const contentLengthUpperCase = Buffer.from('Content-Length'.toUpperCase()) +const contentLengthLowerCase = Buffer.from('Content-Length'.toLowerCase()) + +group('tree.search', () => { + bench('content-length', () => { + tree.lookup(contentLengthLowerCase) + }) + bench('CONTENT-LENGTH', () => { + tree.lookup(contentLengthUpperCase) + }) + bench('Content-Length', () => { + tree.lookup(contentLength) + }) +}) + +await run() diff --git a/lib/core/tree.js b/lib/core/tree.js index 366fc7d3207..9b50767c6d3 100644 --- a/lib/core/tree.js +++ b/lib/core/tree.js @@ -83,7 +83,10 @@ class TstNode { while (node !== null && index < keylength) { let code = key[index] // A-Z - if (code >= 0x41 && code <= 0x5a) { + // First check if it is bigger than 0x5a. + // Lowercase letters have higher char codes than uppercase ones. + // Also we assume that headers will mostly contain lowercase characters. + if (code <= 0x5a && code >= 0x41) { // Lowercase for uppercase. code |= 32 } @@ -121,6 +124,7 @@ class TernarySearchTree { /** * @param {Uint8Array} key + * @return {any} */ lookup (key) { return this.node?.search(key)?.value ?? null diff --git a/test/node-test/tree.js b/test/node-test/tree.js index eee3fa85eac..44a7d7960ac 100644 --- a/test/node-test/tree.js +++ b/test/node-test/tree.js @@ -13,6 +13,13 @@ describe('Ternary Search Tree', () => { assert.throws(() => tst.insert(Buffer.from(''), '')) }) + test('looking up not inserted key returns null', () => { + assert.throws(() => new TernarySearchTree().insert(Buffer.from(''), '')) + const tst = new TernarySearchTree() + tst.insert(Buffer.from('a'), 'a') + assert.strictEqual(tst.lookup(Buffer.from('non-existant')), null) + }) + test('duplicate key', () => { const tst = new TernarySearchTree() const key = Buffer.from('a')