11package routing
22
33import (
4- "fmt"
5- "math"
64 "regexp"
75 "strings"
86)
@@ -21,8 +19,7 @@ type node struct {
2119 order int // the order at which the data was added. used to be pick the first one when matching multiple
2220 minOrder int // minimum order among all the child nodes and this node
2321
24- children []* node // child static nodes, indexed by the first byte of each child key
25- paramChildren []* node // child param nodes
22+ children []* node // child static nodes, indexed by the first byte of each child key
2623
2724 regex * regexp.Regexp // regular expression for a param node containing regular expression key
2825 paramIdx int // the parameter index, meaningful only for param node
@@ -33,257 +30,145 @@ type node struct {
3330func newStore () * store {
3431 return & store {
3532 root : & node {
36- static : true ,
37- children : make ([]* node , 256 ),
38- paramChildren : make ([]* node , 0 ),
39- paramIdx : - 1 ,
40- params : []string {},
33+ static : true ,
34+ children : make ([]* node , 256 ),
35+ paramIdx : - 1 ,
36+ params : []string {},
4137 },
4238 }
4339}
4440
4541func (s * store ) Add (key string , data interface {}) int {
4642 s .count ++
47- return s .root .add (key , data , s . count )
43+ return s .root .add (key , data )
4844}
4945
50- func (s * store ) Get (path string , pvalues [] string ) (data interface {}, pnames [] string ) {
51- data , pnames , _ = s .root .get (path , pvalues )
46+ func (s * store ) Get (path string ) (data interface {}) {
47+ data = s .root .get (path )
5248 return
5349}
5450
55- // Add adds a new node to the store with the given key and data
56- func ( n * node ) add ( key string , data interface {}, order int ) int {
57- matched := 0
51+ func ( s * store ) Count () int {
52+ return s . count
53+ }
5854
59- // find the common prefix
60- for ; matched < len (key ) && matched < len (n .key ); matched ++ {
61- if key [matched ] != n .key [matched ] {
62- break
63- }
55+ func (n * node ) add (key string , data interface {}) int {
56+ if n .static {
57+ return n .addStatic (key , data )
6458 }
59+ return n .addParam (key , data )
60+ }
6561
66- if matched == len (n .key ) {
67- if matched == len (key ) {
68- // the node key is the same as the key: make the current node as data node
69- // if the node is already a data node, ignore the new data since we only care the first matched node
70- if n .data == nil {
71- n .data = data
72- n .order = order
73- }
74- return n .paramIdx + 1
75- }
76-
77- // the node key is a prefix of the key: create a child node
78- newKey := key [matched :]
62+ func (n * node ) addStatic (key string , data interface {}) int {
63+ if len (key ) == 0 {
64+ n .data = data
65+ return n .paramIdx
66+ }
7967
80- // try adding to a static child
81- if child := n .children [newKey [0 ]]; child != nil {
82- if pn := child .add (newKey , data , order ); pn >= 0 {
83- return pn
84- }
85- }
86- // try adding to a param child
87- for _ , child := range n .paramChildren {
88- if pn := child .add (newKey , data , order ); pn >= 0 {
89- return pn
90- }
68+ c := key [0 ]
69+ if n .children [c ] == nil {
70+ n .children [c ] = & node {
71+ static : true ,
72+ children : make ([]* node , 256 ),
73+ paramIdx : - 1 ,
74+ params : append (n .params , n .key ),
9175 }
92-
93- return n .addChild (newKey , data , order )
9476 }
9577
96- if matched == 0 || ! n .static {
97- // no common prefix, or partial common prefix with a non-static node: should skip this node
98- return - 1
99- }
78+ return n .children [c ].addStatic (key [1 :], data )
79+ }
10080
101- // the node key shares a partial prefix with the key: split the node key
102- n1 := & node {
103- static : true ,
104- key : n .key [matched :],
105- data : n .data ,
106- order : n .order ,
107- minOrder : n .minOrder ,
108- paramChildren : n .paramChildren ,
109- children : n .children ,
110- paramIdx : n .paramIdx ,
111- params : n .params ,
81+ func (n * node ) addParam (key string , data interface {}) int {
82+ if len (key ) == 0 {
83+ n .data = data
84+ return n .paramIdx
11285 }
11386
114- n .key = key [0 :matched ]
115- n .data = nil
116- n .paramChildren = make ([]* node , 0 )
117- n .children = make ([]* node , 256 )
118- n .children [n1 .key [0 ]] = n1
119-
120- return n .add (key , data , order )
121- }
122-
123- // addChild creates static and param nodes to store the given data
124- func (n * node ) addChild (key string , data interface {}, order int ) int {
125- // find the first occurrence of a param token
12687 if key [0 ] == '/' {
12788 key = key [1 :]
12889 }
129- p0 := strings .Index (key , ":" )
130- if p0 == - 1 {
131- // no param tokens found: create a static node
132- child := & node {
133- static : true ,
134- key : key ,
135- minOrder : order ,
136- children : make ([]* node , 256 ),
137- paramChildren : make ([]* node , 0 ),
138- paramIdx : n .paramIdx ,
139- params : n .params ,
140- data : data ,
141- order : order ,
142- }
143- n .children [key [0 ]] = child
144- if n .data == nil {
145- // if the node is already a data node, ignore the new data since we only care about the first matched node
146- n .data = data
147- n .order = order
148- return n .paramIdx + 1
149- }
150- return child .paramIdx + 1
151- }
152- // param token found: create a static node for characters before the param token
153- child := & node {
154- static : true ,
155- key : key [:p0 ],
156- minOrder : order ,
157- children : make ([]* node , 256 ),
158- paramChildren : make ([]* node , 0 ),
159- paramIdx : n .paramIdx ,
160- params : n .params ,
161- }
162- n .children [key [0 ]] = child
163- n = child
164- key = key [p0 :]
16590
166- // add param node for the current param token
167- p1 := strings .Index (key , "/" )
168- if p1 == - 1 {
169- // the param token is at the end of the key
170- p1 = len (key )
171- }
172- pname := key [1 :p1 ]
173- pattern , err := regexp .Compile ("[^/]+" )
174- if err != nil {
175- // invalid param regex
176- return - 1
91+ idx := strings .IndexByte (key , '/' )
92+ if idx == - 1 {
93+ idx = len (key )
17794 }
178- child = & node {
179- static : false ,
180- key : pname ,
181- minOrder : order ,
182- children : make ([]* node , 256 ),
183- paramChildren : make ([]* node , 0 ),
184- paramIdx : n .paramIdx + len (n .paramChildren ) + 1 ,
185- params : append (n .params , pname ),
186- regex : pattern ,
187- }
188- n .paramChildren = append (n .paramChildren , child )
18995
190- if p1 == len (key ) {
191- // the param token is at the end of the key
192- child .data = data
193- child .order = order
194- return child .paramIdx + 1
195- }
96+ var child * node
97+ pathPart := key [:idx ]
19698
197- // process the rest of the key recursively
198- n = child
199- key = key [p1 :]
200- return n .addChild (key , data , order )
201- }
99+ // Check if a child node with the path part exists
100+ for _ , c := range n .children {
101+ if c .static && c .key == pathPart {
102+ child = c
103+ break
104+ }
105+ }
202106
203- func (n * node ) get (key string , pvalues []string ) (data interface {}, pnames []string , order int ) {
204- order = math .MaxInt32
205- for len (key ) > 0 {
206- if n .static {
207- // check if the node key is a prefix of the given key
208- // a slightly optimized version of strings.HasPrefix
209- nkl := len (n .key )
210- if nkl > len (key ) || n .key != key [:nkl ] {
211- return
107+ // If no child node exists, create a new one
108+ if child == nil {
109+ if pathPart [0 ] == ':' { // parameterized segment
110+ child = & node {
111+ static : false ,
112+ children : make ([]* node , 1 ),
113+ paramIdx : n .paramIdx + 1 ,
114+ params : append (n .params , pathPart [1 :]),
212115 }
213- key = key [nkl :]
214- } else if n .regex != nil {
215- // param node with regular expression
216- match := n .regex .FindStringIndex (key )
217- if match == nil || match [0 ] != 0 {
218- return
219- }
220- if n .paramIdx >= len (pvalues ) {
221- pvalues = append (pvalues , make ([]string , n .paramIdx - len (pvalues )+ 1 )... )
222- }
223- pvalues [n .paramIdx ] = key [0 :match [1 ]]
224- key = key [match [1 ]:]
225- } else {
226- // param node matching non-"/" characters
227- i := strings .IndexByte (key , '/' )
228- if i == - 1 {
229- if n .paramIdx >= len (pvalues ) {
230- pvalues = append (pvalues , make ([]string , n .paramIdx - len (pvalues )+ 1 )... )
231- }
232- pvalues [n .paramIdx ] = key
233- key = ""
234- } else {
235- if n .paramIdx >= len (pvalues ) {
236- pvalues = append (pvalues , make ([]string , n .paramIdx - len (pvalues )+ 1 )... )
237- }
238- pvalues [n .paramIdx ] = key [:i ]
239- key = key [i :]
116+ } else { // static segment
117+ child = & node {
118+ static : true ,
119+ key : pathPart ,
120+ children : make ([]* node , 256 ),
240121 }
241122 }
123+ n .children = append (n .children , child )
124+ }
242125
243- // find a static child that can match the rest of the key
244- if child := n .children [key [0 ]]; child != nil {
245- if len (n .paramChildren ) == 0 {
246- // use iteration instead of recursion when there are no param children
247- n = child
248- continue
249- }
250- data , pnames , order = child .get (key , pvalues )
251- }
126+ // Recurse into the child node with the remaining part of the key
127+ return child .addParam (key [idx :], data )
128+ }
252129
253- break
130+ func (n * node ) get (path string ) (data interface {}) {
131+ if n .static {
132+ return n .getStatic (path )
254133 }
134+ return n .getParam (path )
135+ }
255136
256- // capture data from this node, if any
257- if n .data != nil && (len (key ) == 0 || len (n .paramChildren ) == 0 && n .static ) {
258- if n .order < order {
259- data , pnames , order = n .data , n .params , n .order
260- }
137+ func (n * node ) getStatic (path string ) (data interface {}) {
138+ if len (path ) == 0 {
139+ return n .data
261140 }
262- // try matching param children
263- for _ , child := range n .paramChildren {
264- if child .minOrder >= order {
265- continue
266- }
267- tvalues := make ([]string , len (pvalues ))
268- copy (tvalues , pvalues )
269- if d , p , s := child .get (key , tvalues ); d != nil && s < order {
270- data , pnames , order = d , p , s
271- copy (pvalues [child .paramIdx :], tvalues [child .paramIdx :])
272- }
141+
142+ c := path [0 ]
143+ if n .children [c ] == nil {
144+ return nil
273145 }
274146
275- return
147+ return n .children [c ].getStatic (path [1 :])
148+ }
149+
150+ func (n * node ) getParam (path string ) (data interface {}) {
151+ if len (path ) == 0 {
152+ return n .data
153+ }
154+
155+ if n .children [0 ] == nil {
156+ return nil
157+ }
158+
159+ return n .children [0 ].getParam (path )
276160}
277161
278- func (n * node ) print (level int ) string {
279- r := fmt .Sprintf ("%v{key: %v, regex: %v, data: %v, order: %v, minOrder: %v, paramIdx: %v, params: %v}\n " , strings .Repeat (" " , level << 2 ), n .key , n .regex , n .data , n .order , n .minOrder , n .paramIdx , n .params )
162+ func (n * node ) String () string {
163+ return n .string ("" )
164+ }
165+
166+ func (n * node ) string (indent string ) string {
167+ s := indent + n .key + "\n "
280168 for _ , child := range n .children {
281169 if child != nil {
282- r += child .print ( level + 1 )
170+ s += child .string ( indent + " " )
283171 }
284172 }
285- for _ , child := range n .paramChildren {
286- r += child .print (level + 1 )
287- }
288- return r
173+ return s
289174}
0 commit comments