@@ -24,16 +24,13 @@ import (
2424
2525// -----------------------------------------------------------------------------
2626
27- func notZero [T comparable ]( v T ) bool {
27+ func zero [T any ]() T {
2828 var zero T
29- return v != zero
29+ return zero
3030}
3131
32- func min (a , b int ) int {
33- if a <= b {
34- return a
35- }
36- return b
32+ func notZero [T comparable ](v T ) bool {
33+ return v != zero [T ]()
3734}
3835
3936func longestCommonPrefix (a , b string ) int {
@@ -87,18 +84,19 @@ type context interface {
8784}
8885
8986// Node is a node in the radix tree.
90- type Node [T context ] struct {
87+ type Node [H any ] struct {
9188 path string
9289 indices string
90+ children []* Node [H ]
91+ h H
92+ ok bool // h is valid if ok is true
9393 wildChild bool
9494 nType nodeType
9595 priority uint32
96- children []* Node [T ]
97- handle func (ctx T )
9896}
9997
10098// Increments priority of the given child and reorders if necessary
101- func (n * Node [T ]) incrementChildPrio (pos int ) int {
99+ func (n * Node [H ]) incrementChildPrio (pos int ) int {
102100 cs := n .children
103101 cs [pos ].priority ++
104102 prio := cs [pos ].priority
@@ -122,7 +120,7 @@ func (n *Node[T]) incrementChildPrio(pos int) int {
122120
123121// AddRoute adds a node with the given handle to the path.
124122// Not concurrency-safe!
125- func (n * Node [T ]) AddRoute (path string , handle func ( ctx T ) ) {
123+ func (n * Node [H ]) AddRoute (path string , handle H ) {
126124 fullPath := path
127125 n .priority ++
128126
@@ -142,21 +140,22 @@ walk:
142140
143141 // Split edge
144142 if i < len (n .path ) {
145- child := Node [T ]{
143+ child := Node [H ]{
146144 path : n .path [i :],
147145 wildChild : n .wildChild ,
148146 nType : static ,
149147 indices : n .indices ,
150148 children : n .children ,
151- handle : n .handle ,
149+ h : n .h ,
150+ ok : n .ok ,
152151 priority : n .priority - 1 ,
153152 }
154153
155- n .children = []* Node [T ]{& child }
154+ n .children = []* Node [H ]{& child }
156155 // []byte for proper unicode char conversion, see #65
157156 n .indices = string ([]byte {n .path [i ]})
158157 n .path = path [:i ]
159- n .handle = nil
158+ n .h , n . ok = zero [ H ](), false
160159 n .wildChild = false
161160 }
162161
@@ -212,7 +211,7 @@ walk:
212211 if idxc != ':' && idxc != '*' {
213212 // []byte for proper unicode char conversion, see #65
214213 n .indices += string ([]byte {idxc })
215- child := & Node [T ]{}
214+ child := & Node [H ]{}
216215 n .children = append (n .children , child )
217216 n .incrementChildPrio (len (n .indices ) - 1 )
218217 n = child
@@ -222,15 +221,15 @@ walk:
222221 }
223222
224223 // Otherwise add handle to current node
225- if n .handle != nil {
224+ if n .ok {
226225 panic ("a handle is already registered for path '" + fullPath + "'" )
227226 }
228- n .handle = handle
227+ n .h , n . ok = handle , true
229228 return
230229 }
231230}
232231
233- func (n * Node [T ]) insertChild (path , fullPath string , handle func ( ctx T ) ) {
232+ func (n * Node [H ]) insertChild (path , fullPath string , handle H ) {
234233 for {
235234 // Find prefix until first wildcard
236235 wildcard , i , valid := findWildcard (path )
@@ -265,28 +264,28 @@ func (n *Node[T]) insertChild(path, fullPath string, handle func(ctx T)) {
265264 }
266265
267266 n .wildChild = true
268- child := & Node [T ]{
267+ child := & Node [H ]{
269268 nType : param ,
270269 path : wildcard ,
271270 }
272- n .children = []* Node [T ]{child }
271+ n .children = []* Node [H ]{child }
273272 n = child
274273 n .priority ++
275274
276275 // If the path doesn't end with the wildcard, then there
277276 // will be another non-wildcard subpath starting with '/'
278277 if len (wildcard ) < len (path ) {
279278 path = path [len (wildcard ):]
280- child := & Node [T ]{
279+ child := & Node [H ]{
281280 priority : 1 ,
282281 }
283- n .children = []* Node [T ]{child }
282+ n .children = []* Node [H ]{child }
284283 n = child
285284 continue
286285 }
287286
288287 // Otherwise we're done. Insert the handle in the new leaf
289- n .handle = handle
288+ n .h , n . ok = handle , true
290289 return
291290 }
292291
@@ -308,39 +307,40 @@ func (n *Node[T]) insertChild(path, fullPath string, handle func(ctx T)) {
308307 n .path = path [:i ]
309308
310309 // First node: catchAll node with empty path
311- child := & Node [T ]{
310+ child := & Node [H ]{
312311 wildChild : true ,
313312 nType : catchAll ,
314313 }
315- n .children = []* Node [T ]{child }
314+ n .children = []* Node [H ]{child }
316315 n .indices = string ('/' )
317316 n = child
318317 n .priority ++
319318
320319 // Second node: node holding the variable
321- child = & Node [T ]{
320+ child = & Node [H ]{
322321 path : path [i :],
323322 nType : catchAll ,
324- handle : handle ,
323+ h : handle ,
324+ ok : true ,
325325 priority : 1 ,
326326 }
327- n .children = []* Node [T ]{child }
327+ n .children = []* Node [H ]{child }
328328
329329 return
330330 }
331331
332332 // If no wildcard was found, simply insert the path and handle
333333 n .path = path
334- n .handle = handle
334+ n .h , n . ok = handle , true
335335}
336336
337- // GetValue returns the handle registered with the given path (key). The values of
338- // wildcards are saved to a map .
337+ // Route returns the handle registered with the given path (key). The values of
338+ // wildcard values are set on the context via UnderlyingSetPathParam .
339339//
340340// If no handle can be found, a TSR (trailing slash redirect) recommendation is
341341// made if a handle exists with an extra (without the) trailing slash for the
342342// given path.
343- func (n * Node [T ]) GetValue ( path string , ctx T ) (handle func ( ctx T ) , tsr bool ) {
343+ func Route [ T context , H any ] (n * Node [H ], path string , ctx T ) (handle H , tsr bool ) {
344344walk: // Outer loop for walking the tree
345345 for {
346346 prefix := n .path
@@ -363,7 +363,7 @@ walk: // Outer loop for walking the tree
363363 // Nothing found.
364364 // We can recommend to redirect to the same URL without a
365365 // trailing slash if a leaf exists for that path.
366- tsr = (path == "/" && n .handle != nil )
366+ tsr = (path == "/" && n .ok )
367367 return
368368 }
369369
@@ -395,13 +395,13 @@ walk: // Outer loop for walking the tree
395395 return
396396 }
397397
398- if handle = n .handle ; handle != nil {
398+ if handle = n .h ; n . ok {
399399 return
400400 } else if len (n .children ) == 1 {
401401 // No handle found. Check if a handle for this path + a
402402 // trailing slash exists for TSR recommendation
403403 n = n .children [0 ]
404- tsr = (n .path == "/" && n .handle != nil ) || (n .path == "" && n .indices == "/" )
404+ tsr = (n .path == "/" && n .ok ) || (n .path == "" && n .indices == "/" )
405405 }
406406 return
407407
@@ -411,7 +411,7 @@ walk: // Outer loop for walking the tree
411411 ctx .UnderlyingSetPathParam (n .path [2 :], path )
412412 }
413413
414- handle = n .handle
414+ handle = n .h
415415 return
416416
417417 default :
@@ -421,7 +421,7 @@ walk: // Outer loop for walking the tree
421421 } else if path == prefix {
422422 // We should have reached the node containing the handle.
423423 // Check if this node has a handle registered.
424- if handle = n .handle ; handle != nil {
424+ if handle = n .h ; n . ok {
425425 return
426426 }
427427
@@ -443,8 +443,8 @@ walk: // Outer loop for walking the tree
443443 for i , c := range []byte (n .indices ) {
444444 if c == '/' {
445445 n = n .children [i ]
446- tsr = (len (n .path ) == 1 && n .handle != nil ) ||
447- (n .nType == catchAll && n .children [0 ].handle != nil )
446+ tsr = (len (n .path ) == 1 && n .ok ) ||
447+ (n .nType == catchAll && n .children [0 ].ok )
448448 return
449449 }
450450 }
@@ -455,7 +455,7 @@ walk: // Outer loop for walking the tree
455455 // extra trailing slash if a leaf exists for that path
456456 tsr = (path == "/" ) ||
457457 (len (prefix ) == len (path )+ 1 && prefix [len (path )] == '/' &&
458- path == prefix [:len (prefix )- 1 ] && n .handle != nil )
458+ path == prefix [:len (prefix )- 1 ] && n .ok )
459459 return
460460 }
461461}
@@ -467,7 +467,7 @@ walk: // Outer loop for walking the tree
467467//
468468// It returns the case-corrected path and a bool indicating whether the lookup
469469// was successful.
470- func (n * Node [T ]) FindCaseInsensitivePath (path string , fixTrailingSlash bool ) (fixedPath string , found bool ) {
470+ func (n * Node [H ]) FindCaseInsensitivePath (path string , fixTrailingSlash bool ) (fixedPath string , found bool ) {
471471 const stackBufSize = 128
472472
473473 // Use a static sized buffer on the stack in the common case.
@@ -504,7 +504,7 @@ func shiftNRuneBytes(rb [4]byte, n int) [4]byte {
504504}
505505
506506// Recursive case-insensitive lookup function used by n.findCaseInsensitivePath
507- func (n * Node [T ]) findCaseInsensitivePathRec (path string , ciPath []byte , rb [4 ]byte , fixTrailingSlash bool ) []byte {
507+ func (n * Node [H ]) findCaseInsensitivePathRec (path string , ciPath []byte , rb [4 ]byte , fixTrailingSlash bool ) []byte {
508508 npLen := len (n .path )
509509
510510walk: // Outer loop for walking the tree
@@ -593,7 +593,7 @@ walk: // Outer loop for walking the tree
593593
594594 // Nothing found. We can recommend to redirect to the same URL
595595 // without a trailing slash if a leaf exists for that path
596- if fixTrailingSlash && path == "/" && n .handle != nil {
596+ if fixTrailingSlash && path == "/" && n .ok {
597597 return ciPath
598598 }
599599 return nil
@@ -628,13 +628,13 @@ walk: // Outer loop for walking the tree
628628 return nil
629629 }
630630
631- if n .handle != nil {
631+ if n .ok {
632632 return ciPath
633633 } else if fixTrailingSlash && len (n .children ) == 1 {
634634 // No handle found. Check if a handle for this path + a
635635 // trailing slash exists
636636 n = n .children [0 ]
637- if n .path == "/" && n .handle != nil {
637+ if n .path == "/" && n .ok {
638638 return append (ciPath , '/' )
639639 }
640640 }
@@ -649,7 +649,7 @@ walk: // Outer loop for walking the tree
649649 } else {
650650 // We should have reached the node containing the handle.
651651 // Check if this node has a handle registered.
652- if n .handle != nil {
652+ if n .ok {
653653 return ciPath
654654 }
655655
@@ -659,8 +659,8 @@ walk: // Outer loop for walking the tree
659659 for i , c := range []byte (n .indices ) {
660660 if c == '/' {
661661 n = n .children [i ]
662- if (len (n .path ) == 1 && n .handle != nil ) ||
663- (n .nType == catchAll && n .children [0 ].handle != nil ) {
662+ if (len (n .path ) == 1 && n .ok ) ||
663+ (n .nType == catchAll && n .children [0 ].ok ) {
664664 return append (ciPath , '/' )
665665 }
666666 return nil
@@ -678,7 +678,7 @@ walk: // Outer loop for walking the tree
678678 return ciPath
679679 }
680680 if len (path )+ 1 == npLen && n .path [len (path )] == '/' &&
681- strings .EqualFold (path [1 :], n .path [1 :len (path )]) && n .handle != nil {
681+ strings .EqualFold (path [1 :], n .path [1 :len (path )]) && n .ok {
682682 return append (ciPath , n .path ... )
683683 }
684684 }
0 commit comments