Improved performance

This commit is contained in:
2024-03-14 23:26:59 +01:00
parent dd98b11eea
commit 99ad93e410
7 changed files with 77 additions and 60 deletions

79
Tree.go
View File

@ -79,11 +79,11 @@ func (tree *Tree[T]) Add(path string, data T) {
}
// Lookup finds the data for the given path.
func (tree *Tree[T]) Lookup(path string) (T, []keyValue) {
var params []keyValue
func (tree *Tree[T]) Lookup(path string) (T, []Parameter) {
var params []Parameter
data := tree.LookupNoAlloc(path, func(key string, value string) {
params = append(params, keyValue{key, value})
params = append(params, Parameter{key, value})
})
return data, params
@ -92,44 +92,28 @@ func (tree *Tree[T]) Lookup(path string) (T, []keyValue) {
// LookupNoAlloc finds the data for the given path without using any memory allocations.
func (tree *Tree[T]) LookupNoAlloc(path string, addParameter func(key string, value string)) T {
var (
i uint
offset uint
lastWildcardOffset uint
lastWildcard *treeNode[T]
empty T
node = &tree.root
i uint
offset uint
wildcardOffset uint
wildcard *treeNode[T]
node = &tree.root
)
// Skip the first loop iteration if the starting characters are equal
if len(path) > 0 && len(node.prefix) > 0 && path[0] == node.prefix[0] {
i = 1
}
begin:
// Search tree for equal parts until we can no longer proceed
for {
// We reached the end.
if i == uint(len(path)) {
// node: /blog|
// path: /blog|
if i-offset == uint(len(node.prefix)) {
return node.data
}
// node: /|*any
// path: /|image.png
if lastWildcard != nil {
addParameter(lastWildcard.prefix, path[lastWildcardOffset:])
return lastWildcard.data
}
// node: /blog|feed
// path: /blog|
return empty
}
for i < uint(len(path)) {
// The node we just checked is entirely included in our path.
// node: /|
// path: /|blog
if i-offset == uint(len(node.prefix)) {
if node.wildcard != nil {
lastWildcard = node.wildcard
lastWildcardOffset = i
wildcard = node.wildcard
wildcardOffset = i
}
char := path[i]
@ -176,28 +160,35 @@ begin:
// node: /|*any
// path: /|image.png
if lastWildcard != nil {
addParameter(lastWildcard.prefix, path[lastWildcardOffset:])
return lastWildcard.data
}
return empty
goto notFound
}
// We got a conflict.
// node: /b|ag
// path: /b|riefcase
if path[i] != node.prefix[i-offset] {
if lastWildcard != nil {
addParameter(lastWildcard.prefix, path[lastWildcardOffset:])
return lastWildcard.data
}
return empty
goto notFound
}
i++
}
// node: /blog|
// path: /blog|
if i-offset == uint(len(node.prefix)) {
return node.data
}
// node: /|*any
// path: /|image.png
notFound:
if wildcard != nil {
addParameter(wildcard.prefix, path[wildcardOffset:])
return wildcard.data
}
var empty T
return empty
}
// Map binds all handlers to a new one provided by the callback.