package exec
import (
"slices"
"github.com/freeeve/gochickpeas/gql/internal/eval"
"github.com/freeeve/gochickpeas/gql/internal/graph"
"github.com/freeeve/gochickpeas/gql/internal/plan"
)
type varWalk struct {
ctx *eval .Ctx
op *plan .BindOp
m *graph .NodeMatcher
rm *graph .RelMatcher
gate hopGate
bound graph .NodeID
haveBound bool
collectRels bool
max uint64
uniq *uniqEnv
collectPairs bool
pathRels []uint32
pathPairs [][2 ]graph .NodeID
used [][2 ]graph .NodeID
visited []graph .NodeID
scratch [][]nodePos
cand *[]graph .NodeID
relData *[]uint32
relRanges *[][2 ]int
pairData *[][2 ]graph .NodeID
pairRanges *[][2 ]int
nbufN []graph .NodeID
nbufP []uint32
}
type nodePos struct {
nb graph .NodeID
pos uint32
}
func (w *varWalk ) dfs (cur graph .NodeID , depth uint64 , st carryState ) {
if depth >= w .max {
return
}
d := int (depth )
for len (w .scratch ) <= d {
w .scratch = append (w .scratch , nil )
}
buf := w .scratch [d ][:0 ]
if w .gate .pred != nil || w .gate .carry != nil || w .collectRels {
w .nbufN , w .nbufP = w .ctx .G .AppendRelationshipsMatched (w .nbufN [:0 ], w .nbufP [:0 ], cur , w .op .Dir , w .rm )
for i , nb := range w .nbufN {
if p := w .nbufP [i ]; w .gate .pred == nil || w .gate .pred .keep (w .ctx , p ) {
buf = append (buf , nodePos {nb , p })
}
}
} else {
w .nbufN = w .ctx .G .AppendNeighborsMatched (w .nbufN [:0 ], cur , w .op .Dir , w .rm )
for _ , nb := range w .nbufN {
buf = append (buf , nodePos {nb , 0 })
}
}
w .scratch [d ] = buf
for i := 0 ; i < len (w .scratch [d ]); i ++ {
nb , pos := w .scratch [d ][i ].nb , w .scratch [d ][i ].pos
edge := [2 ]graph .NodeID {cur , nb }
if w .op .Dir == graph .Both && nb < cur {
edge = [2 ]graph .NodeID {nb , cur }
}
if containsEdge (w .used , edge ) {
continue
}
var pair [2 ]graph .NodeID
if w .uniq != nil && w .op .Uniq != nil {
pair [0 ], pair [1 ] = uniqPair (w .op .Dir , cur , nb )
if w .op .Uniq .Check && w .uniq .used (w .op .Uniq .Scope , pair [0 ], pair [1 ]) {
continue
}
}
if w .op .Acyclic && containsNode (w .visited , nb ) {
continue
}
next := st
if w .gate .carry != nil {
var ok bool
if next , ok = w .gate .carry .step (w .ctx , pos , st ); !ok {
continue
}
}
w .used = append (w .used , edge )
if w .op .Acyclic {
w .visited = append (w .visited , nb )
}
if w .collectRels {
w .pathRels = append (w .pathRels , pos )
}
if w .collectPairs {
w .pathPairs = append (w .pathPairs , pair )
}
nd := depth + 1
if nd >= w .op .Min && (!w .haveBound || w .bound == nb ) && w .ctx .G .NodeMatcherAccepts (w .m , nb ) {
*w .cand = append (*w .cand , nb )
if w .collectRels {
*w .relRanges = append (*w .relRanges , [2 ]int {len (*w .relData ), len (w .pathRels )})
*w .relData = append (*w .relData , w .pathRels ...)
}
if w .collectPairs {
*w .pairRanges = append (*w .pairRanges , [2 ]int {len (*w .pairData ), len (w .pathPairs )})
*w .pairData = append (*w .pairData , w .pathPairs ...)
}
}
w .dfs (nb , nd , next )
if w .collectRels {
w .pathRels = w .pathRels [:len (w .pathRels )-1 ]
}
if w .collectPairs {
w .pathPairs = w .pathPairs [:len (w .pathPairs )-1 ]
}
if w .op .Acyclic {
w .visited = w .visited [:len (w .visited )-1 ]
}
w .used = w .used [:len (w .used )-1 ]
}
}
func containsNode(visited []graph .NodeID , n graph .NodeID ) bool {
return slices .Contains (visited , n )
}
func containsEdge(used [][2 ]graph .NodeID , e [2 ]graph .NodeID ) bool {
return slices .Contains (used , e )
}
The pages are generated with Golds v0.8.7 . (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu .
PR and bug reports are welcome and can be submitted to the issue list .
Please follow @zigo_101 (reachable from the left QR code) to get the latest news of Golds .