Add private canonical path prefix index
This commit is contained in:
138
internal/engine/path_prefix.go
Normal file
138
internal/engine/path_prefix.go
Normal file
@@ -0,0 +1,138 @@
|
||||
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
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user