// Pre-resolved pattern matchers (port of the Rust NativeNodeMatcher /// NativeRelMatcher): a node pattern's label and inline-property names are// resolved to snapshot handles once per operator, so the per-candidate// accept test is a bitmap contains plus a direct column read instead of// interner lookups.
package graphimport (chickpeas)// RelMatcher is an expand's relationship types pre-resolved to interned// ids. Wraps the engine's RelMatch, which has the exact semantics the seam// needs: no types matches all, unknown names drop, all-unknown matches// nothing.typeRelMatcherstruct { m chickpeas.RelMatch}// propPredKind discriminates one inline-property predicate.type propPredKind uint8const (// predNoColumn: the key has no column, so every node reads absent for // it -- matching only a Null value. predNoColumn propPredKind = iota// predStrEq: a string equality with the comparison text pre-interned // to its atom once; the per-candidate check is an id compare. atomOK // false means the text is absent from the interner, so nothing can // equal it. predStrEq// predGeneric: read the stored value and compare via value.Equal // (numeric coercion, bool, Null-absent), byte-identical to NodePropEq. predGeneric)// propPred is one inline {key: value} predicate with its key pre-resolved// to a column reader.type propPred struct { kind propPredKind read func(pos uint32) (value.Value, bool) atom uint32 atomOK bool readAtom func(pos uint32) (uint32, bool) expected value.Value}// labelTest is one compiled label membership check: a dense label probes// a word bitmap (one load and mask), the rest the compressed node set. An// empty test (unknown label) rejects every candidate. A set-backed test// counts its probes and self-densifies past adaptiveDenseProbes: probe// volume, not label density, is what amortizes the id-space-proportional// bitmap, and the engine caches it per label so one hot execution pays// the build for every later compile. Matchers are compiled per stage per// execution and evaluated single-threaded, so the plain counter is safe.type labelTest struct { bits []uint64 set *nodeset.Set label string probes uint32}// adaptiveDenseProbes is the set-probe count past which a label test// requests the floor-free bitmap (LabelDenseForced); heavy levels probe// millions of times, so the ~2 ms build repays within one execution.const adaptiveDenseProbes = 1 << 16func ( *labelTest) ( *chickpeas.Snapshot, uint32) bool {if .bits != nil { := int() >> 6return < len(.bits) && .bits[]>>(&63)&1 == 1 }if .set == nil {returnfalse } .probes++if .probes >= adaptiveDenseProbes {if .bits = .LabelDenseForced(.label); .bits != nil { := int() >> 6return < len(.bits) && .bits[]>>(&63)&1 == 1 } }return .set.Contains()}// NodeMatcher is a node pattern's labels and inline properties pre-resolved// to snapshot handles.typeNodeMatcherstruct { labels []labelTest props []propPred}// CompileNodeMatcher resolves each label to its membership test (the// engine's dense word bitmap when the label has one, the node set// otherwise) and each inline key to its column once, so the per-candidate// NodeMatcherAccepts avoids re-interning constant names.func ( *SnapshotGraph) ( []string, []PropSpec) *NodeMatcher { := &NodeMatcher{labels: make([]labelTest, len()), props: make([]propPred, len())}for , := range {if , := .g.NodesWithLabel(); { .labels[] = labelTest{bits: .g.LabelDense(), set: , label: } } }for , := range { , := .g.ColIndexed(.Key)if ! { .props[] = propPred{kind: predNoColumn, expected: .Val}continue }if , := .Val.AsStr(); { := propPred{kind: predStrEq, readAtom: strColReader()}if , := .g.ValueFromString(); { .atom, .atomOK = .StrID() } .props[] = continue } .props[] = propPred{kind: predGeneric, read: .colReader(), expected: .Val} }return}// NodeMatcherAccepts reports whether node carries every label and matches// every inline property of the compiled matcher.func ( *SnapshotGraph) ( *NodeMatcher, chickpeas.NodeID) bool {for := range .labels {if !.labels[].contains(.g, uint32()) {returnfalse } }for := range .props { := &.props[]switch .kind {casepredNoColumn:if !.expected.IsNull() {returnfalse }casepredStrEq: , := .readAtom(uint32())if ! || !.atomOK || != .atom {returnfalse }casepredGeneric: , := .read(uint32())if ! {if !.expected.IsNull() {returnfalse } } elseif !value.Equal(, .expected) {returnfalse } } }returntrue}// CompileRelMatcher pre-resolves relationship-type names via the engine's// Match (empty = all, unknown names drop, all-unknown = none).func ( *SnapshotGraph) ( []string) *RelMatcher {return &RelMatcher{m: .g.Match(...)}}// FilterMatchedTail compacts ids[start:] in place to the matcher-accepted// entries and returns the shortened slice; rels, when non-nil, is a// parallel array compacted identically from relStart. Result-identical to// testing each candidate with NodeMatcherAccepts -- the batch form exists// so a whole expansion tail filters through one call, with the dominant// matcher shape (one dense label, no inline properties) reduced to a// hoisted word-bitmap loop: no per-candidate dispatch at all. Set-backed// labels keep the per-candidate test, whose adaptive densification then// upgrades later batches.func ( *SnapshotGraph) ( *NodeMatcher, []chickpeas.NodeID, int, []uint32, int) ([]chickpeas.NodeID, []uint32) {iflen(.props) == 0 && len(.labels) == 1 && .labels[0].bits != nil { := .labels[0].bits := for , := range [:] { := int() >> 6if < len() && []>>(uint32()&63)&1 == 1 { [] = if != nil { [+(-)] = [+] } ++ } }if != nil { = [:+(-)] }return [:], } := for , := range [:] {if .NodeMatcherAccepts(, ) { [] = if != nil { [+(-)] = [+] } ++ } }if != nil { = [:+(-)] }return [:], }// strColReader reads the stored atom id at a position, folding the dense// string column's atom-0-means-missing convention to absent (the raw// StrCol.ID does not).func strColReader( chickpeas.Col) func( uint32) (uint32, bool) { := .Str()returnfunc( uint32) (uint32, bool) { , := .ID()if ! || == 0 {return0, false }return , true }}// colReader narrows a column once by dtype and returns a positional runtime// -value reader (strings resolved through the interner, empty folding to// absent per the engine's Prop convention).func ( *SnapshotGraph) ( chickpeas.Col) func( uint32) (value.Value, bool) {switch .Dtype() {casechickpeas.DtypeI64: := .I64()returnfunc( uint32) (value.Value, bool) { , := .Get()if ! {returnvalue.Value{}, false }returnvalue.Int(), true }casechickpeas.DtypeF64: := .F64()returnfunc( uint32) (value.Value, bool) { , := .Get()if ! {returnvalue.Value{}, false }returnvalue.Float(), true }casechickpeas.DtypeBool: := .Bool()returnfunc( uint32) (value.Value, bool) { , := .Get()if ! {returnvalue.Value{}, false }returnvalue.Bool(), true }default: := strColReader()returnfunc( uint32) (value.Value, bool) { , := ()if ! {returnvalue.Value{}, false } , := .g.ResolveString()if ! || == "" {returnvalue.Value{}, false }returnvalue.Str(), true } }}
The pages are generated with Goldsv0.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.