Files
ConfigKit/internal/engine/path_prefix.go

139 lines
2.7 KiB
Go

package engine
type pathPrefixIndex struct {
root pathPrefixNode
}
type pathPrefixNode struct {
children map[string]*pathPrefixNode
ids []int
minimumID int
hasMinimum bool
}
func (node *pathPrefixNode) includeID(id int) {
if !node.hasMinimum || id < node.minimumID {
node.minimumID = id
node.hasMinimum = true
}
}
func (index *pathPrefixIndex) insert(pointer string, id int) {
node := &index.root
node.includeID(id)
visitCanonicalPointerTokens(pointer, func(token string) bool {
if node.children == nil {
node.children = make(map[string]*pathPrefixNode)
}
child := node.children[token]
if child == nil {
child = &pathPrefixNode{}
node.children[token] = child
}
node = child
node.includeID(id)
return true
})
node.ids = append(node.ids, id)
}
func (index *pathPrefixIndex) visitAncestors(pointer string, visit func(int)) {
node := &index.root
for _, id := range node.ids {
visit(id)
}
visitCanonicalPointerTokens(pointer, func(token string) bool {
child := node.children[token]
if child == nil {
return false
}
node = child
for _, id := range node.ids {
visit(id)
}
return true
})
}
func (index *pathPrefixIndex) visitDescendants(pointer string, visit func(int)) {
root := index.nodeAt(pointer)
if root == nil {
return
}
var walk func(*pathPrefixNode)
walk = func(node *pathPrefixNode) {
for _, id := range node.ids {
visit(id)
}
for _, child := range node.children {
walk(child)
}
}
walk(root)
}
func (index *pathPrefixIndex) earliestIntersectingID(pointer string) (int, bool) {
bestID, found := 0, false
consider := func(id int) {
if !found || id < bestID {
bestID = id
found = true
}
}
node := &index.root
for _, id := range node.ids {
consider(id)
}
complete := visitCanonicalPointerTokens(pointer, func(token string) bool {
child := node.children[token]
if child == nil {
return false
}
node = child
for _, id := range node.ids {
consider(id)
}
return true
})
if complete && node.hasMinimum {
consider(node.minimumID)
}
return bestID, found
}
func (index *pathPrefixIndex) nodeAt(pointer string) *pathPrefixNode {
node := &index.root
complete := visitCanonicalPointerTokens(pointer, func(token string) bool {
child := node.children[token]
if child == nil {
return false
}
node = child
return true
})
if !complete {
return nil
}
return node
}
func visitCanonicalPointerTokens(pointer string, visit func(string) bool) bool {
if pointer == "" {
return true
}
start := 1
for {
end := start
for end < len(pointer) && pointer[end] != '/' {
end++
}
if !visit(pointer[start:end]) {
return false
}
if end == len(pointer) {
return true
}
start = end + 1
}
}