|
|
@ -7,28 +7,28 @@ import ( |
|
|
|
) |
|
|
|
|
|
|
|
var DefaultMappableNodeFunc = func() mappableNode { |
|
|
|
return &binaryTree{} //newMNode()
|
|
|
|
return &binaryTree{} |
|
|
|
} |
|
|
|
|
|
|
|
type mappableNodeFunc func() mappableNode |
|
|
|
|
|
|
|
type mappableNode interface { |
|
|
|
Insert(node *tnode) |
|
|
|
Insert(node *proxyTrie) |
|
|
|
IsEmpty() bool |
|
|
|
Lookup(label rune) (*tnode, error) |
|
|
|
Lookup(label rune) (*proxyTrie, error) |
|
|
|
} |
|
|
|
|
|
|
|
type binaryTree struct { |
|
|
|
left *binaryTree |
|
|
|
right *binaryTree |
|
|
|
node *tnode |
|
|
|
node *proxyTrie |
|
|
|
} |
|
|
|
|
|
|
|
func BinaryTreeMapperFunc() mappableNode { |
|
|
|
return &binaryTree{} |
|
|
|
} |
|
|
|
|
|
|
|
func (b *binaryTree) Insert(node *tnode) { |
|
|
|
func (b *binaryTree) Insert(node *proxyTrie) { |
|
|
|
switch { |
|
|
|
// Edge.
|
|
|
|
case b.node == nil: |
|
|
@ -62,7 +62,7 @@ func (b *binaryTree) IsEmpty() bool { |
|
|
|
return b.left == nil && b.right == nil && b.node == nil |
|
|
|
} |
|
|
|
|
|
|
|
func (b *binaryTree) Lookup(label rune) (*tnode, error) { |
|
|
|
func (b *binaryTree) Lookup(label rune) (*proxyTrie, error) { |
|
|
|
switch { |
|
|
|
case b.node == nil: |
|
|
|
return nil, fmt.Errorf("not found") |
|
|
@ -88,32 +88,32 @@ func (b *binaryTree) String() string { |
|
|
|
b.left, b.right, b.node) |
|
|
|
} |
|
|
|
|
|
|
|
type mnode struct { |
|
|
|
keys map[rune]*tnode |
|
|
|
type mappedNode struct { |
|
|
|
keys map[rune]*proxyTrie |
|
|
|
} |
|
|
|
|
|
|
|
func newMNode() *mnode { |
|
|
|
return &mnode{ |
|
|
|
keys: make(map[rune]*tnode), |
|
|
|
func NewMappedNode() *mappedNode { |
|
|
|
return &mappedNode{ |
|
|
|
keys: make(map[rune]*proxyTrie), |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
func (m *mnode) Insert(node *tnode) { |
|
|
|
func (m *mappedNode) Insert(node *proxyTrie) { |
|
|
|
if node == nil { |
|
|
|
return |
|
|
|
} |
|
|
|
m.keys[node.label] = node |
|
|
|
} |
|
|
|
|
|
|
|
func (m *mnode) IsEmpty() bool { |
|
|
|
func (m *mappedNode) IsEmpty() bool { |
|
|
|
return len(m.keys) == 0 |
|
|
|
} |
|
|
|
|
|
|
|
func (m *mnode) String() string { |
|
|
|
func (m *mappedNode) String() string { |
|
|
|
var out string |
|
|
|
|
|
|
|
if len(m.keys) > 0 { |
|
|
|
out += "&mnode{\n" |
|
|
|
out += "&mappedNode{\n" |
|
|
|
i := 0 |
|
|
|
for k, v := range m.keys { |
|
|
|
i++ |
|
|
@ -122,10 +122,10 @@ func (m *mnode) String() string { |
|
|
|
out += "}" |
|
|
|
return out |
|
|
|
} |
|
|
|
return "&mnode{}" |
|
|
|
return "&mappedNode{}" |
|
|
|
} |
|
|
|
|
|
|
|
func (m *mnode) Lookup(label rune) (*tnode, error) { |
|
|
|
func (m *mappedNode) Lookup(label rune) (*proxyTrie, error) { |
|
|
|
node, ok := m.keys[label] |
|
|
|
if !ok { |
|
|
|
return nil, fmt.Errorf("not found") |
|
|
@ -133,17 +133,17 @@ func (m *mnode) Lookup(label rune) (*tnode, error) { |
|
|
|
return node, nil |
|
|
|
} |
|
|
|
|
|
|
|
type anode struct { |
|
|
|
keys []*tnode |
|
|
|
type arrayNode struct { |
|
|
|
keys []*proxyTrie |
|
|
|
} |
|
|
|
|
|
|
|
func ArrayMapperFunc() mappableNode { |
|
|
|
return &anode{ |
|
|
|
keys: make([]*tnode, 0), |
|
|
|
return &arrayNode{ |
|
|
|
keys: make([]*proxyTrie, 0), |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
func (a *anode) Insert(node *tnode) { |
|
|
|
func (a *arrayNode) Insert(node *proxyTrie) { |
|
|
|
for i := 0; i < len(a.keys); i++ { |
|
|
|
if a.keys[i].label == node.label { |
|
|
|
a.keys[i].handler = node.handler |
|
|
@ -153,15 +153,15 @@ func (a *anode) Insert(node *tnode) { |
|
|
|
a.keys = append(a.keys, node) |
|
|
|
} |
|
|
|
|
|
|
|
func (a *anode) IsEmpty() bool { |
|
|
|
func (a *arrayNode) IsEmpty() bool { |
|
|
|
return len(a.keys) == 0 |
|
|
|
} |
|
|
|
|
|
|
|
func (a *anode) String() string { |
|
|
|
return "&anode{}" |
|
|
|
func (a *arrayNode) String() string { |
|
|
|
return "&arrayNode{}" |
|
|
|
} |
|
|
|
|
|
|
|
func (a *anode) Lookup(label rune) (*tnode, error) { |
|
|
|
func (a *arrayNode) Lookup(label rune) (*proxyTrie, error) { |
|
|
|
for i := 0; i < len(a.keys); i++ { |
|
|
|
if a.keys[i].label == label { |
|
|
|
return a.keys[i], nil |
|
|
@ -170,7 +170,7 @@ func (a *anode) Lookup(label rune) (*tnode, error) { |
|
|
|
return nil, fmt.Errorf("no such key") |
|
|
|
} |
|
|
|
|
|
|
|
type tnode struct { |
|
|
|
type proxyTrie struct { |
|
|
|
// label is the first character matching the current node's prefix.
|
|
|
|
label rune |
|
|
|
|
|
|
@ -185,22 +185,22 @@ type tnode struct { |
|
|
|
// of the child nodes' labels. This allows comapratively fast lookups for
|
|
|
|
// child node prefixes.
|
|
|
|
keys mappableNode |
|
|
|
//children []*tnode
|
|
|
|
//children []*proxyTrie
|
|
|
|
|
|
|
|
KeyFunc func() mappableNode |
|
|
|
} |
|
|
|
|
|
|
|
// NewTRootNode returns a root radix trie node.
|
|
|
|
func NewTRootNode() *tnode { |
|
|
|
return &tnode{ |
|
|
|
keys: newMNode(), |
|
|
|
// NewProxyTrie returns a root radix trie node.
|
|
|
|
func NewProxyTrie() *proxyTrie { |
|
|
|
return &proxyTrie{ |
|
|
|
keys: &binaryTree{}, |
|
|
|
KeyFunc: DefaultMappableNodeFunc, |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// NewTNode returns a new radix trie node for use within a radix trie root node.
|
|
|
|
func NewTNode(label rune, prefix string, fn mappableNodeFunc) *tnode { |
|
|
|
return &tnode{ |
|
|
|
// NewTrieNode returns a new radix trie node for use within a radix trie root node.
|
|
|
|
func NewTrieNode(label rune, prefix string, fn mappableNodeFunc) *proxyTrie { |
|
|
|
return &proxyTrie{ |
|
|
|
label: label, |
|
|
|
prefix: prefix, |
|
|
|
keys: fn(), |
|
|
@ -238,7 +238,7 @@ func longestPrefix(s1, s2 string) string { |
|
|
|
//
|
|
|
|
// This function makes additional assignments internally so as to match the
|
|
|
|
// returned values making their purpose a bit more clear.
|
|
|
|
func (t *tnode) getEdge(pattern string) (trie *tnode, newPattern string, commonPrefix string, split bool, newLeaf bool) { |
|
|
|
func (t *proxyTrie) getEdge(pattern string) (trie *proxyTrie, newPattern string, commonPrefix string, split bool, newLeaf bool) { |
|
|
|
var err error |
|
|
|
newPattern = pattern |
|
|
|
label := rune(newPattern[0]) |
|
|
@ -292,12 +292,12 @@ func (t *tnode) getEdge(pattern string) (trie *tnode, newPattern string, commonP |
|
|
|
|
|
|
|
// Insert a new handler into the trie using pattern `pattern`. Returns the
|
|
|
|
// generated node.
|
|
|
|
func (t *tnode) Insert(pattern string, handler http.Handler) *tnode { |
|
|
|
func (t *proxyTrie) Insert(pattern string, handler http.Handler) *proxyTrie { |
|
|
|
edge, newpattern, common, split, newLeaf := t.getEdge(pattern) |
|
|
|
|
|
|
|
// Root node detection.
|
|
|
|
if edge.label == rune(0) && edge.prefix == "" { |
|
|
|
node := NewTNode(rune(pattern[0]), pattern, t.KeyFunc) |
|
|
|
node := NewTrieNode(rune(pattern[0]), pattern, t.KeyFunc) |
|
|
|
node.handler = handler |
|
|
|
edge.keys.Insert(node) |
|
|
|
return node |
|
|
@ -325,7 +325,7 @@ func (t *tnode) Insert(pattern string, handler http.Handler) *tnode { |
|
|
|
// the incoming pattern is simply "ab" since we need to split the prefix
|
|
|
|
// ("ab") and create a new node with the old suffix ("c").
|
|
|
|
if rightPrefix == "" { |
|
|
|
node := NewTNode(rune(leftPrefix[0]), leftPrefix, t.KeyFunc) |
|
|
|
node := NewTrieNode(rune(leftPrefix[0]), leftPrefix, t.KeyFunc) |
|
|
|
node.handler = edge.handler |
|
|
|
node.keys = edge.keys |
|
|
|
edge.prefix = common |
|
|
@ -346,8 +346,8 @@ func (t *tnode) Insert(pattern string, handler http.Handler) *tnode { |
|
|
|
// Do not mistake left and right for a binary radix trie, which this is
|
|
|
|
// not. This is just inline semantics to make it easier to reaspon about
|
|
|
|
// when the edge nodes are re-parented.
|
|
|
|
lnode := NewTNode(rune(leftPrefix[0]), leftPrefix, t.KeyFunc) |
|
|
|
rnode := NewTNode(rune(rightPrefix[0]), rightPrefix, t.KeyFunc) |
|
|
|
lnode := NewTrieNode(rune(leftPrefix[0]), leftPrefix, t.KeyFunc) |
|
|
|
rnode := NewTrieNode(rune(rightPrefix[0]), rightPrefix, t.KeyFunc) |
|
|
|
|
|
|
|
lnode.handler = edge.handler |
|
|
|
rnode.handler = handler |
|
|
@ -364,7 +364,7 @@ func (t *tnode) Insert(pattern string, handler http.Handler) *tnode { |
|
|
|
} else { |
|
|
|
// No node split is required so we simply attach a new node to the
|
|
|
|
// current edge.
|
|
|
|
node := NewTNode(rune(newpattern[0]), newpattern, t.KeyFunc) |
|
|
|
node := NewTrieNode(rune(newpattern[0]), newpattern, t.KeyFunc) |
|
|
|
node.handler = handler |
|
|
|
edge.keys.Insert(node) |
|
|
|
} |
|
|
@ -373,24 +373,24 @@ func (t *tnode) Insert(pattern string, handler http.Handler) *tnode { |
|
|
|
} |
|
|
|
|
|
|
|
// IsEdge returns whether the node is an edge node.
|
|
|
|
func (t *tnode) IsEdge() bool { |
|
|
|
func (t *proxyTrie) IsEdge() bool { |
|
|
|
return t.handler == nil |
|
|
|
} |
|
|
|
|
|
|
|
// IsLeaf returns whether the node is a leaf node.
|
|
|
|
func (t *tnode) IsLeaf() bool { |
|
|
|
func (t *proxyTrie) IsLeaf() bool { |
|
|
|
return t.handler != nil |
|
|
|
} |
|
|
|
|
|
|
|
// IsRoot returns whether the node is the root node.
|
|
|
|
func (t *tnode) IsRoot() bool { |
|
|
|
func (t *proxyTrie) IsRoot() bool { |
|
|
|
return t.label == rune(0) && t.prefix == "" && t.handler == nil |
|
|
|
} |
|
|
|
|
|
|
|
// Lookup accepts a single pattern string and traverses the radix trie,
|
|
|
|
// returning the handler associated with the pattern or nil if the pattern
|
|
|
|
// cannot be found.
|
|
|
|
func (t *tnode) Lookup(pattern string) http.Handler { |
|
|
|
func (t *proxyTrie) Lookup(pattern string) http.Handler { |
|
|
|
n := t.lookup(pattern) |
|
|
|
if n != nil { |
|
|
|
return n.handler |
|
|
@ -398,7 +398,7 @@ func (t *tnode) Lookup(pattern string) http.Handler { |
|
|
|
return nil |
|
|
|
} |
|
|
|
|
|
|
|
func (t *tnode) lookup(pattern string) *tnode { |
|
|
|
func (t *proxyTrie) lookup(pattern string) *proxyTrie { |
|
|
|
var err error |
|
|
|
node := t |
|
|
|
label := rune(pattern[0]) |
|
|
@ -457,8 +457,8 @@ func (t *tnode) lookup(pattern string) *tnode { |
|
|
|
// your application around it as it is currently path agnostic. Care must be
|
|
|
|
// taken to ensure that the handlers attached to any given pattern will fail as
|
|
|
|
// expected when passed unexpected URLs.
|
|
|
|
func (t *tnode) LongestMatch(pattern string) http.Handler { |
|
|
|
var last *tnode |
|
|
|
func (t *proxyTrie) LongestMatch(pattern string) http.Handler { |
|
|
|
var last *proxyTrie |
|
|
|
var err error |
|
|
|
node := t |
|
|
|
last = node |
|
|
@ -497,13 +497,13 @@ func (t *tnode) LongestMatch(pattern string) http.Handler { |
|
|
|
} |
|
|
|
|
|
|
|
// String representation of the trie.
|
|
|
|
func (t *tnode) String() string { |
|
|
|
return fmt.Sprintf(`&tnode{label="%c", prefix="%s", handler="%v" keys="%v"}`, |
|
|
|
func (t *proxyTrie) String() string { |
|
|
|
return fmt.Sprintf(`&proxyTrie{label="%c", prefix="%s", handler="%v" keys="%v"}`, |
|
|
|
t.label, t.prefix, t.handler, t.keys) |
|
|
|
} |
|
|
|
|
|
|
|
// SwitchKeyFunc changes the keying function to fn.
|
|
|
|
func (t *tnode) SwitchKeyFunc(fn mappableNodeFunc) { |
|
|
|
func (t *proxyTrie) SwitchKeyFunc(fn mappableNodeFunc) { |
|
|
|
t.keys = fn() |
|
|
|
t.KeyFunc = fn |
|
|
|
} |