mirror of
https://github.com/yusing/godoxy.git
synced 2026-04-25 10:18:59 +02:00
feat: trie implementation
This commit is contained in:
111
internal/utils/trie/walk.go
Normal file
111
internal/utils/trie/walk.go
Normal file
@@ -0,0 +1,111 @@
|
||||
package trie
|
||||
|
||||
import (
|
||||
"maps"
|
||||
"slices"
|
||||
)
|
||||
|
||||
type YieldFunc = func(part string, value any) bool
|
||||
type YieldKeyFunc = func(key string) bool
|
||||
type Iterator = func(YieldFunc)
|
||||
type KeyIterator = func(YieldKeyFunc)
|
||||
|
||||
// WalkAll walks all nodes in the trie, yields full key and series
|
||||
func (node *Node) Walk(yield YieldFunc) {
|
||||
node.walkAll(yield)
|
||||
}
|
||||
|
||||
func (node *Node) walkAll(yield YieldFunc) bool {
|
||||
if !node.value.IsNil() {
|
||||
if !yield(node.key, node.value.Load()) {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
for _, v := range node.children.Range {
|
||||
if !v.walkAll(yield) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (node *Node) WalkKeys(yield YieldKeyFunc) {
|
||||
node.walkKeys(yield)
|
||||
}
|
||||
|
||||
func (node *Node) walkKeys(yield YieldKeyFunc) bool {
|
||||
if !node.value.IsNil() {
|
||||
return !yield(node.key)
|
||||
}
|
||||
for _, v := range node.children.Range {
|
||||
if !v.walkKeys(yield) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (node *Node) Keys() []string {
|
||||
return slices.Collect(node.WalkKeys)
|
||||
}
|
||||
|
||||
func (node *Node) Map() map[string]any {
|
||||
return maps.Collect(node.Walk)
|
||||
}
|
||||
|
||||
func (tree Root) Query(key *Key) Iterator {
|
||||
if !key.hasWildcard {
|
||||
return func(yield YieldFunc) {
|
||||
if v, ok := tree.Node.Get(key); ok {
|
||||
yield(key.full, v)
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
return func(yield YieldFunc) {
|
||||
tree.walkQuery(key.segments, tree.Node, yield, false)
|
||||
}
|
||||
}
|
||||
|
||||
func (tree Root) walkQuery(patternParts []string, node *Node, yield YieldFunc, recursive bool) bool {
|
||||
if len(patternParts) == 0 {
|
||||
if !node.value.IsNil() { // end
|
||||
if !yield(node.key, node.value.Load()) {
|
||||
return true
|
||||
}
|
||||
} else if recursive {
|
||||
return tree.walkAll(yield)
|
||||
}
|
||||
return true
|
||||
}
|
||||
pat := patternParts[0]
|
||||
|
||||
switch pat {
|
||||
case "**":
|
||||
// ** matches zero or more segments
|
||||
// Option 1: ** matches zero segment, move to next pattern part
|
||||
if !tree.walkQuery(patternParts[1:], node, yield, false) {
|
||||
return false
|
||||
}
|
||||
// Option 2: ** matches one or more segments
|
||||
for _, child := range node.children.Range {
|
||||
if !tree.walkQuery(patternParts, child, yield, true) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
case "*":
|
||||
// * matches any single segment
|
||||
for _, child := range node.children.Range {
|
||||
if !tree.walkQuery(patternParts[1:], child, yield, false) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
default:
|
||||
// Exact match
|
||||
if child, ok := node.children.Load(pat); ok {
|
||||
return tree.walkQuery(patternParts[1:], child, yield, false)
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
Reference in New Issue
Block a user