get and add methods get rewritten in an iterative manner instead of recursive.

This commit is contained in:
Alexander Andreev 2023-05-28 01:46:57 +04:00
parent 538f1bd676
commit 89c2333a4f
Signed by: Arav
GPG Key ID: D22A817D95815393

132
httpr.go
View File

@ -41,83 +41,93 @@ type node struct {
handler http.HandlerFunc handler http.HandlerFunc
} }
func (n *node) get(path path, idx int) (http.HandlerFunc, Params) { func (n *node) get(path path) (http.HandlerFunc, Params) {
// Check if this node is a catch-all endpoint. pathLen := len(path)
if n.endpoint[0] == '*' { curNode := n
var p Params = Params{}
p[n.endpoint[1:]] = strings.Join(path[idx:], "/")
return n.handler, p
}
// If this endpoint is a parameter, then add its name to a path's part. outer:
// This will be used further to fill Params. for i := range path {
if n.endpoint[0] == ':' { // Check if this node is a catch-all endpoint.
path[idx] = n.endpoint + ":" + path[idx] if curNode.endpoint[0] == '*' {
} var p Params = Params{}
p[curNode.endpoint[1:]] = strings.Join(path[i:], "/")
if len(path) == idx+1 { return curNode.handler, p
var params Params = make(Params)
for _, part := range path {
if part[0] == ':' {
param := strings.Split(part[1:], ":")
params[param[0]] = param[1]
}
} }
return n.handler, params // If this is a parametrised endpoint, then add its name to
} // a path's part. It will be used further to parse parameters.
if curNode.endpoint[0] == ':' {
if len(path) > idx+1 { path[i] = curNode.endpoint + ":" + path[i]
var wildcardOrParam *node
for _, next := range n.children {
if next.endpoint == path[idx+1] {
return next.get(path, idx+1)
}
if next.endpoint[0] == ':' || next.endpoint[0] == '*' {
wildcardOrParam = next
}
} }
if wildcardOrParam != nil { if pathLen == i+1 {
return wildcardOrParam.get(path, idx+1) var params Params = make(Params)
for _, part := range path {
if part[0] == ':' {
param := strings.Split(part[1:], ":")
params[param[0]] = param[1]
}
}
return n.handler, params
}
if pathLen > i+1 {
var paramNode *node
for _, next := range n.children {
if next.endpoint == path[i+1] {
curNode = next
continue outer
}
if next.endpoint[0] == ':' || next.endpoint[0] == '*' {
paramNode = next
}
}
if paramNode != nil {
curNode = paramNode
continue
}
} }
} }
return nil, nil return nil, nil
} }
func (n *node) add(path path, idx int, handler http.HandlerFunc) error { func (n *node) add(path path, handler http.HandlerFunc) error {
// If it is a last part of path, then set a handler to this node. pathLen := len(path)
if len(path) == idx+1 { curNode := n
n.endpoint = path[idx]
n.handler = handler
return nil
}
// Check if next part is a parameter and if it is, then look for outer:
// an already existing endpoint with a different key. for i := range path {
if path[idx+1][0] == '*' || path[idx+1][0] == ':' { if pathLen == i+1 {
for _, child := range n.children { if curNode.handler != nil {
if (child.endpoint[0] == '*' || child.endpoint[0] == ':') && path[idx+1] != child.endpoint { return errors.New("attempt to redefine a handler for already existing path")
return errors.New("there is already a catch-all or regular param in there! You cannot add a second one")
} }
} curNode.endpoint = path[i]
} curNode.handler = handler
// Check for an already existing endpoint.
for _, child := range n.children {
if child.endpoint == path[idx+1] {
child.add(path, idx+1, handler)
return nil return nil
} }
}
// No endpoint was found. for _, child := range n.children {
new_child := &node{endpoint: path[idx+1]} firstChar := path[i+1][0]
new_child.add(path, idx+1, handler) if (firstChar == ':' || firstChar == '*') && firstChar == child.endpoint[0] {
n.children = append(n.children, new_child) curNode = child
continue outer
}
if child.endpoint == path[i+1] {
curNode = child
continue outer
}
}
newChild := &node{endpoint: path[i+1]}
curNode.children = append(curNode.children, newChild)
curNode = newChild
}
return nil return nil
} }