Move maxParams logic to router
diff --git a/router.go b/router.go index bdee266..ce19f86 100644 --- a/router.go +++ b/router.go
@@ -116,6 +116,9 @@ // pool to recycle Param slices psPool sync.Pool + // max number of params any of the pathes contains + maxParams int + // Enables automatic redirection if the current route can't be matched but a // handler for the path with (without) the trailing slash exists. // For example if /foo/ is requested but a route only exists for /foo, the @@ -175,12 +178,14 @@ func (r *Router) paramsGet() *Params { if vp := r.psPool.Get(); vp != nil { psp := vp.(*Params) - *psp = (*psp)[0:0] // reset slice - return psp + if cap(*psp) >= r.maxParams { + *psp = (*psp)[0:0] // reset slice + return psp + } } // Allocate new slice if none is available - ps := make(Params, 0, 20) // TODO + ps := make(Params, 0, r.maxParams) return &ps } @@ -248,6 +253,11 @@ r.trees[method] = root } + // Update maxParams + if pc := countParams(path); pc > r.maxParams { + r.maxParams = pc + } + root.addRoute(path, handle) }
diff --git a/tree.go b/tree.go index f248a57..e1359ef 100644 --- a/tree.go +++ b/tree.go
@@ -13,18 +13,14 @@ return b } -func countParams(path string) uint8 { - var n uint +func countParams(path string) (n int) { for i := 0; i < len(path); i++ { if path[i] != ':' && path[i] != '*' { continue } n++ } - if n >= 255 { - return 255 - } - return uint8(n) + return n } func toLower(b byte) byte { @@ -46,7 +42,6 @@ pfx string // first len(children) bytes are indices, rest is path prefix wildChild bool nType nodeType - maxParams uint8 priority uint32 children []*node handle Handle @@ -83,18 +78,12 @@ func (n *node) addRoute(path string, handle Handle) { fullPath := path n.priority++ - numParams := countParams(path) // non-empty tree if len(n.pfx) > 0 { prefix := n.pfx[len(n.children):] walk: for { - // Update maxParams of the current node - if numParams > n.maxParams { - n.maxParams = numParams - } - // Find the longest common prefix. // This also implies that the common prefix contains no ':' or '*' // since the existing key can't contain those chars. @@ -109,16 +98,9 @@ child := node{ pfx: n.pfx[:len(n.children)] + prefix[i:], wildChild: n.wildChild, + priority: n.priority - 1, children: n.children, handle: n.handle, - priority: n.priority - 1, - } - - // Update maxParams (max of all children) - for i := range child.children { - if child.children[i].maxParams > child.maxParams { - child.maxParams = child.children[i].maxParams - } } n.children = []*node{&child} @@ -137,12 +119,6 @@ n.priority++ prefix = n.pfx[len(n.children):] - // Update maxParams of the child node - if numParams > n.maxParams { - n.maxParams = numParams - } - numParams-- - // Check if the wildcard matches if len(path) >= len(prefix) && prefix == path[:len(prefix)] { // check for longer wildcard, e.g. :name and :names @@ -180,14 +156,12 @@ if c != ':' && c != '*' { // []byte for proper unicode char conversion, see #65 n.pfx = n.pfx[:len(n.children)] + string([]byte{c}) + n.pfx[len(n.children):] - child := &node{ - maxParams: numParams, - } + child := new(node) n.children = append(n.children, child) n.incrementChildPrio(len(n.children) - 1) n = child } - n.insertChild(numParams, path, fullPath, handle) + n.insertChild(path, fullPath, handle) return } else if i == len(path) { // Make node a (in-path) leaf @@ -199,15 +173,15 @@ return } } else { // Empty tree - n.insertChild(numParams, path, fullPath, handle) + n.insertChild(path, fullPath, handle) } } -func (n *node) insertChild(numParams uint8, path, fullPath string, handle Handle) { +func (n *node) insertChild(path, fullPath string, handle Handle) { var offset int // already handled bytes of the path // find prefix until first wildcard (beginning with ':'' or '*'') - for i, max := 0, len(path); numParams > 0; i++ { + for i, max := 0, len(path); i < max; i++ { c := path[i] if c != ':' && c != '*' { continue @@ -248,14 +222,12 @@ } child := &node{ - nType: param, - maxParams: numParams, + nType: param, } n.children = []*node{child} n.wildChild = true n = child n.priority++ - numParams-- // if the path doesn't end with the wildcard, then there // will be another non-wildcard subpath starting with '/' @@ -264,15 +236,14 @@ offset = end child := &node{ - maxParams: numParams, - priority: 1, + priority: 1, } n.children = []*node{child} n = child } } else { // catchAll - if end != max || numParams > 1 { + if end != max { panic("catch-all routes are only allowed at the end of the path in path '" + fullPath + "'") } @@ -293,7 +264,6 @@ pfx: "/", wildChild: true, nType: catchAll, - maxParams: 1, } n.children = []*node{child} n = child @@ -301,11 +271,10 @@ // second node: node holding the variable child = &node{ - pfx: path[i:], - nType: catchAll, - maxParams: 1, - handle: handle, - priority: 1, + pfx: path[i:], + nType: catchAll, + priority: 1, + handle: handle, } n.children = []*node{child}
diff --git a/tree_test.go b/tree_test.go index eb83499..87ccdc6 100644 --- a/tree_test.go +++ b/tree_test.go
@@ -15,7 +15,7 @@ func printChildren(n *node, prefix string) { indices := n.pfx[:len(n.children)] path := n.pfx[len(n.children):] - fmt.Printf(" %02d:%02d %s%s [%d:%s] %v %t %d \r\n", n.priority, n.maxParams, prefix, path, len(n.children), indices, n.handle, n.wildChild, n.nType) + fmt.Printf(" %02d %s%s [%d:%s] %v %t %d \r\n", n.priority, prefix, path, len(n.children), indices, n.handle, n.wildChild, n.nType) for l := len(path); l > 0; l-- { prefix += " " } @@ -89,33 +89,11 @@ return prio } -func checkMaxParams(t *testing.T, n *node) uint8 { - var maxParams uint8 - for i := range n.children { - params := checkMaxParams(t, n.children[i]) - if params > maxParams { - maxParams = params - } - } - if n.nType != static && !n.wildChild { - maxParams++ - } - - if n.maxParams != maxParams { - t.Errorf( - "maxParams mismatch for node '%s': is %d, should be %d", - n.pfx[:len(n.children)], n.maxParams, maxParams, - ) - } - - return maxParams -} - func TestCountParams(t *testing.T) { if countParams("/path/:param1/static/*catch-all") != 2 { t.Fail() } - if countParams(strings.Repeat("/:param", 256)) != 255 { + if countParams(strings.Repeat("/:param", 256)) != 256 { t.Fail() } } @@ -157,7 +135,6 @@ }) checkPriorities(t, tree) - checkMaxParams(t, tree) } func TestTreeWildcard(t *testing.T) { @@ -203,7 +180,6 @@ }) checkPriorities(t, tree) - checkMaxParams(t, tree) } func catchPanic(testFunc func()) (recv interface{}) {