Skip to content

Commit

Permalink
perf: improve TernarySearchTree
Browse files Browse the repository at this point in the history
  • Loading branch information
Uzlopak committed Feb 19, 2024
1 parent d4ce0b1 commit 58de077
Show file tree
Hide file tree
Showing 3 changed files with 33 additions and 2 deletions.
20 changes: 20 additions & 0 deletions benchmarks/TernarySearchTree.mjs
Original file line number Diff line number Diff line change
@@ -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()
8 changes: 6 additions & 2 deletions lib/core/tree.js
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
Expand All @@ -109,7 +112,7 @@ class TernarySearchTree {

/**
* @param {Uint8Array} key
* @param {any} value
* @param {void}
* */
insert (key, value) {
if (this.node === null) {
Expand All @@ -121,6 +124,7 @@ class TernarySearchTree {

/**
* @param {Uint8Array} key
* @return {TstNode | null}
*/
lookup (key) {
return this.node?.search(key)?.value ?? null
Expand Down
7 changes: 7 additions & 0 deletions test/node-test/tree.js
Original file line number Diff line number Diff line change
Expand Up @@ -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')
Expand Down

0 comments on commit 58de077

Please sign in to comment.