Skip to content

Commit b5cfc93

Browse files
authored
Merge pull request #176 from xushiwei/q
radix.Node: generic handler
2 parents 3958231 + f4fcc3a commit b5cfc93

File tree

3 files changed

+104
-104
lines changed

3 files changed

+104
-104
lines changed

radix/tree.go

Lines changed: 51 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -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

3936
func 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) {
344344
walk: // 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

510510
walk: // 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

Comments
 (0)