diff --git a/pkgs/trie/trie.go b/pkgs/trie/trie.go index 9fd84ba..367bba3 100644 --- a/pkgs/trie/trie.go +++ b/pkgs/trie/trie.go @@ -4,7 +4,17 @@ const ( WORD_ANY = 0 ) +type VisitCtrl int + +const ( + VisitContinue = 0 + VisitBreak = 1 + VisitSkip = 2 +) + type Node[T any] struct { + Word any + Parent *Node[T] WordNexts map[string]*Node[T] AnyNext *Node[T] Value T @@ -43,7 +53,10 @@ func (n *Node[T]) Create(word string) *Node[T] { node, ok := n.WordNexts[word] if !ok { - node = &Node[T]{} + node = &Node[T]{ + Word: word, + Parent: n, + } n.WordNexts[word] = node } @@ -52,16 +65,80 @@ func (n *Node[T]) Create(word string) *Node[T] { func (n *Node[T]) CreateAny() *Node[T] { if n.AnyNext == nil { - n.AnyNext = &Node[T]{} + n.AnyNext = &Node[T]{ + Word: WORD_ANY, + Parent: n, + } } return n.AnyNext } +func (n *Node[T]) IsEmpty() bool { + return len(n.WordNexts) == 0 && n.AnyNext == nil +} + +// 将自己从树中移除。如果cleanParent为true,则会一直向上清除所有没有子节点的节点 +func (n *Node[T]) RemoveSelf(cleanParent bool) { + if n.Parent == nil { + return + } + + if n.Word == WORD_ANY { + if n.Parent.AnyNext == n { + n.Parent.AnyNext = nil + } + } else if n.Parent.WordNexts != nil && n.Parent.WordNexts[n.Word.(string)] == n { + delete(n.Parent.WordNexts, n.Word.(string)) + } + + if cleanParent { + if n.Parent.IsEmpty() { + n.Parent.RemoveSelf(true) + } + } + + n.Parent = nil +} + +func (n *Node[T]) Iterate(visitorFn func(word string, node *Node[T], isWordNode bool) VisitCtrl) { + if n.WordNexts != nil { + for word, node := range n.WordNexts { + ret := visitorFn(word, node, true) + if ret == VisitBreak { + return + } + + if ret == VisitSkip { + continue + } + + node.Iterate(visitorFn) + } + } + + if n.AnyNext != nil { + ret := visitorFn("", n.AnyNext, false) + if ret == VisitBreak { + return + } + + if ret == VisitSkip { + return + } + + n.AnyNext.Iterate(visitorFn) + } +} + type Trie[T any] struct { Root Node[T] } +func NewTrie[T any]() *Trie[T] { + return &Trie[T]{} +} + func (t *Trie[T]) Walk(words []string, visitorFn func(word string, wordIndex int, node *Node[T], isWordNode bool)) bool { ptr := &t.Root @@ -109,3 +186,17 @@ func (t *Trie[T]) Create(words []any) *Node[T] { return ptr } + +func (t *Trie[T]) CreateWords(words []string) *Node[T] { + ptr := &t.Root + + for _, word := range words { + ptr = ptr.Create(word) + } + + return ptr +} + +func (n *Trie[T]) Iterate(visitorFn func(word string, node *Node[T], isWordNode bool) VisitCtrl) { + n.Root.Iterate(visitorFn) +} diff --git a/sdks/storage/cdsapi/object.go b/sdks/storage/cdsapi/object.go index a6708f9..32d7243 100644 --- a/sdks/storage/cdsapi/object.go +++ b/sdks/storage/cdsapi/object.go @@ -30,7 +30,7 @@ const ObjectListPath = "/object/list" type ObjectList struct { UserID cdssdk.UserID `form:"userID" binding:"required"` PackageID cdssdk.PackageID `form:"packageID" binding:"required"` - Path string `form:"path" binding:"required"` + Path string `form:"path"` // 允许为空字符串 IsPrefix bool `form:"isPrefix"` } type ObjectListResp struct {