in matchtree.go [370:447]
func (t *andLineMatchTree) matches(cp *contentProvider, cost int, known map[matchTree]bool) (bool, bool) {
matches, sure := t.andMatchTree.matches(cp, cost, known)
if !(sure && matches) {
return matches, sure
}
// find child with fewest candidates
min := maxUInt32
fewestChildren := 0
for ix, child := range t.children {
v, ok := child.(*substrMatchTree)
// make sure we are running a content search and that all candidates are a
// substrMatchTree
if !ok || v.fileName {
return matches, sure
}
if len(v.current) < min {
min = len(v.current)
fewestChildren = ix
}
}
type lineRange struct {
start int
end int
}
lines := make([]lineRange, 0, len(t.children[fewestChildren].(*substrMatchTree).current))
prev := -1
for _, candidate := range t.children[fewestChildren].(*substrMatchTree).current {
line, byteStart, byteEnd := candidate.line(cp.newlines(), cp.fileSize)
if line == prev {
continue
}
prev = line
lines = append(lines, lineRange{byteStart, byteEnd})
}
// children keeps track of the children's candidates we have already seen.
children := make([][]*candidateMatch, 0, len(t.children)-1)
for j, child := range t.children {
if j == fewestChildren {
continue
}
children = append(children, child.(*substrMatchTree).current)
}
nextLine:
for i := 0; i < len(lines); i++ {
hits := 1
nextChild:
for j := range children {
nextCandidate:
for len(children[j]) > 0 {
candidate := children[j][0]
bo := int(cp.findOffset(false, candidate.runeOffset))
if bo < lines[i].start {
children[j] = children[j][1:]
continue nextCandidate
}
if bo <= lines[i].end {
hits++
continue nextChild
}
// move the `lines` iterator forward until bo <= line.end
for i < len(lines) && bo > lines[i].end {
i++
}
i--
continue nextLine
}
}
// return early once we found any line that contains matches from all children
if hits == len(t.children) {
return matches, true
}
}
return false, true
}