Reorganize to go get will work
This makes almost no changes to source, but touches every almost file. Also fixes error in gremlin test code.
This commit is contained in:
parent
e46a5bbe4a
commit
e0df752618
130 changed files with 8766 additions and 10167 deletions
248
graph/and-iterator.go
Normal file
248
graph/and-iterator.go
Normal file
|
|
@ -0,0 +1,248 @@
|
|||
// Defines the And iterator, one of the base iterators. And requires no
|
||||
// knowledge of the constituent TripleStore; its sole purpose is to act as an
|
||||
// intersection operator across the subiterators it is given. If one iterator
|
||||
// contains [1,3,5] and another [2,3,4] -- then And is an iterator that
|
||||
// 'contains' [3]
|
||||
//
|
||||
// It accomplishes this in one of two ways. If it is a Next()ed iterator (that
|
||||
// is, it is a top level iterator, or on the "Next() path", then it will Next()
|
||||
// it's primary iterator (helpfully, and.primary_it) and Check() the resultant
|
||||
// value against it's other iterators. If it matches all of them, then it
|
||||
// returns that value. Otherwise, it repeats the process.
|
||||
//
|
||||
// If it's on a Check() path, it merely Check()s every iterator, and returns the
|
||||
// logical AND of each result.
|
||||
|
||||
package graph
|
||||
|
||||
import (
|
||||
"container/list"
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// The And iterator. Consists of a BaseIterator and a number of subiterators, the primary of which will
|
||||
// be Next()ed if next is called.
|
||||
type AndIterator struct {
|
||||
BaseIterator
|
||||
internalIterators []Iterator
|
||||
itCount int
|
||||
primaryIt Iterator
|
||||
checkList *list.List
|
||||
}
|
||||
|
||||
// Creates a new And iterator.
|
||||
func NewAndIterator() *AndIterator {
|
||||
var and AndIterator
|
||||
BaseIteratorInit(&and.BaseIterator)
|
||||
and.internalIterators = make([]Iterator, 0, 20)
|
||||
and.checkList = nil
|
||||
return &and
|
||||
}
|
||||
|
||||
// Reset all internal iterators
|
||||
func (and *AndIterator) Reset() {
|
||||
and.primaryIt.Reset()
|
||||
for _, it := range and.internalIterators {
|
||||
it.Reset()
|
||||
}
|
||||
and.checkList = nil
|
||||
}
|
||||
|
||||
func (and *AndIterator) Clone() Iterator {
|
||||
newAnd := NewAndIterator()
|
||||
newAnd.AddSubIterator(and.primaryIt.Clone())
|
||||
newAnd.CopyTagsFrom(and)
|
||||
for _, it := range and.internalIterators {
|
||||
newAnd.AddSubIterator(it.Clone())
|
||||
}
|
||||
if and.checkList != nil {
|
||||
newAnd.optimizeCheck()
|
||||
}
|
||||
return newAnd
|
||||
}
|
||||
|
||||
// Returns a list.List of the subiterators, in order (primary iterator first).
|
||||
func (and *AndIterator) GetSubIterators() *list.List {
|
||||
l := list.New()
|
||||
l.PushBack(and.primaryIt)
|
||||
for _, it := range and.internalIterators {
|
||||
l.PushBack(it)
|
||||
}
|
||||
return l
|
||||
}
|
||||
|
||||
// Overrides BaseIterator TagResults, as it needs to add it's own results and
|
||||
// recurse down it's subiterators.
|
||||
func (and *AndIterator) TagResults(out *map[string]TSVal) {
|
||||
and.BaseIterator.TagResults(out)
|
||||
if and.primaryIt != nil {
|
||||
and.primaryIt.TagResults(out)
|
||||
}
|
||||
for _, it := range and.internalIterators {
|
||||
it.TagResults(out)
|
||||
}
|
||||
}
|
||||
|
||||
// DEPRECATED Returns the ResultTree for this iterator, recurses to it's subiterators.
|
||||
func (and *AndIterator) GetResultTree() *ResultTree {
|
||||
tree := NewResultTree(and.LastResult())
|
||||
tree.AddSubtree(and.primaryIt.GetResultTree())
|
||||
for _, it := range and.internalIterators {
|
||||
tree.AddSubtree(it.GetResultTree())
|
||||
}
|
||||
return tree
|
||||
}
|
||||
|
||||
// Prints information about this iterator.
|
||||
func (and *AndIterator) DebugString(indent int) string {
|
||||
var total string
|
||||
for i, it := range and.internalIterators {
|
||||
total += strings.Repeat(" ", indent+2)
|
||||
total += fmt.Sprintf("%d:\n%s\n", i, it.DebugString(indent+4))
|
||||
}
|
||||
var tags string
|
||||
for _, k := range and.Tags() {
|
||||
tags += fmt.Sprintf("%s;", k)
|
||||
}
|
||||
spaces := strings.Repeat(" ", indent+2)
|
||||
|
||||
return fmt.Sprintf("%s(%s %d\n%stags:%s\n%sprimary_it:\n%s\n%sother_its:\n%s)",
|
||||
strings.Repeat(" ", indent),
|
||||
and.Type(),
|
||||
and.GetUid(),
|
||||
spaces,
|
||||
tags,
|
||||
spaces,
|
||||
and.primaryIt.DebugString(indent+4),
|
||||
spaces,
|
||||
total)
|
||||
}
|
||||
|
||||
// Add a subiterator to this And iterator.
|
||||
//
|
||||
// The first iterator that is added becomes the primary iterator. This is
|
||||
// important. Calling Optimize() is the way to change the order based on
|
||||
// subiterator statistics. Without Optimize(), the order added is the order
|
||||
// used.
|
||||
func (and *AndIterator) AddSubIterator(sub Iterator) {
|
||||
if and.itCount > 0 {
|
||||
and.internalIterators = append(and.internalIterators, sub)
|
||||
and.itCount++
|
||||
return
|
||||
}
|
||||
and.primaryIt = sub
|
||||
and.itCount++
|
||||
}
|
||||
|
||||
// Returns the Next value from the And iterator. Because the And is the
|
||||
// intersection of its subiterators, it must choose one subiterator to produce a
|
||||
// candidate, and check this value against the subiterators. A productive choice
|
||||
// of primary iterator is therefore very important.
|
||||
func (and *AndIterator) Next() (TSVal, bool) {
|
||||
NextLogIn(and)
|
||||
var curr TSVal
|
||||
var exists bool
|
||||
for {
|
||||
|
||||
curr, exists = and.primaryIt.Next()
|
||||
if !exists {
|
||||
return NextLogOut(and, nil, false)
|
||||
}
|
||||
if and.checkSubIts(curr) {
|
||||
and.Last = curr
|
||||
return NextLogOut(and, curr, true)
|
||||
}
|
||||
}
|
||||
panic("Somehow broke out of Next() loop in AndIterator")
|
||||
}
|
||||
|
||||
// Checks a value against the non-primary iterators, in order.
|
||||
func (and *AndIterator) checkSubIts(val TSVal) bool {
|
||||
var subIsGood = true
|
||||
for _, it := range and.internalIterators {
|
||||
subIsGood = it.Check(val)
|
||||
if !subIsGood {
|
||||
break
|
||||
}
|
||||
}
|
||||
return subIsGood
|
||||
}
|
||||
|
||||
func (and *AndIterator) checkCheckList(val TSVal) bool {
|
||||
var isGood = true
|
||||
for e := and.checkList.Front(); e != nil; e = e.Next() {
|
||||
isGood = e.Value.(Iterator).Check(val)
|
||||
if !isGood {
|
||||
break
|
||||
}
|
||||
}
|
||||
return CheckLogOut(and, val, isGood)
|
||||
}
|
||||
|
||||
// Check a value against the entire iterator, in order.
|
||||
func (and *AndIterator) Check(val TSVal) bool {
|
||||
CheckLogIn(and, val)
|
||||
if and.checkList != nil {
|
||||
return and.checkCheckList(val)
|
||||
}
|
||||
mainGood := and.primaryIt.Check(val)
|
||||
if !mainGood {
|
||||
return CheckLogOut(and, val, false)
|
||||
}
|
||||
othersGood := and.checkSubIts(val)
|
||||
if !othersGood {
|
||||
return CheckLogOut(and, val, false)
|
||||
}
|
||||
and.Last = val
|
||||
return CheckLogOut(and, val, true)
|
||||
}
|
||||
|
||||
// Returns the approximate size of the And iterator. Because we're dealing
|
||||
// with an intersection, we know that the largest we can be is the size of the
|
||||
// smallest iterator. This is the heuristic we shall follow. Better heuristics
|
||||
// welcome.
|
||||
func (and *AndIterator) Size() (int64, bool) {
|
||||
val, b := and.primaryIt.Size()
|
||||
for _, it := range and.internalIterators {
|
||||
newval, newb := it.Size()
|
||||
if val > newval {
|
||||
val = newval
|
||||
}
|
||||
b = newb && b
|
||||
}
|
||||
return val, b
|
||||
}
|
||||
|
||||
// An And has no NextResult of its own -- that is, there are no other values
|
||||
// which satisfy our previous result that are not the result itself. Our
|
||||
// subiterators might, however, so just pass the call recursively.
|
||||
func (and *AndIterator) NextResult() bool {
|
||||
if and.primaryIt.NextResult() {
|
||||
return true
|
||||
}
|
||||
for _, it := range and.internalIterators {
|
||||
if it.NextResult() {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Perform and-specific cleanup, of which there currently is none.
|
||||
func (and *AndIterator) cleanUp() {
|
||||
}
|
||||
|
||||
// Close this iterator, and, by extension, close the subiterators.
|
||||
// Close should be idempotent, and it follows that if it's subiterators
|
||||
// follow this contract, the And follows the contract.
|
||||
func (and *AndIterator) Close() {
|
||||
and.cleanUp()
|
||||
and.primaryIt.Close()
|
||||
for _, it := range and.internalIterators {
|
||||
it.Close()
|
||||
}
|
||||
}
|
||||
|
||||
// Register this as an "and" iterator.
|
||||
func (and *AndIterator) Type() string { return "and" }
|
||||
Loading…
Add table
Add a link
Reference in a new issue