Simplify Nexter interface

This change allows a Nexter to be used in the same manner as a scanner
using a for graph.Next(it) {} construction.

It is important that graph.Next(it) and any associated it.Result() calls
operate on the same iterator.
This commit is contained in:
kortschak 2014-08-01 09:15:02 +09:30
parent f8e28e066e
commit b1a70d99aa
31 changed files with 168 additions and 233 deletions

View file

@ -87,7 +87,7 @@ func (it *Int64) DebugString(indent int) string {
// Next() on an Int64 all iterator is a simple incrementing counter.
// Return the next integer, and mark it as the result.
func (it *Int64) Next() (graph.Value, bool) {
func (it *Int64) Next() bool {
graph.NextLogIn(it)
if it.at == -1 {
return graph.NextLogOut(it, nil, false)

View file

@ -151,25 +151,20 @@ func (it *And) AddSubIterator(sub graph.Iterator) {
it.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 (it *And) Next() (graph.Value, bool) {
// Returns advances 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 (it *And) Next() bool {
graph.NextLogIn(it)
var curr graph.Value
var exists bool
for {
curr, exists = graph.Next(it.primaryIt)
if !exists {
return graph.NextLogOut(it, nil, false)
}
for graph.Next(it.primaryIt) {
curr := it.primaryIt.Result()
if it.subItsContain(curr) {
it.result = curr
return graph.NextLogOut(it, curr, true)
}
}
panic("unreachable")
return graph.NextLogOut(it, nil, false)
}
func (it *And) Result() graph.Value {

View file

@ -36,10 +36,10 @@ func TestTag(t *testing.T) {
t.Errorf("Cannot get tag back, got %s", out[0])
}
val, ok := and.Next()
if !ok {
if !and.Next() {
t.Errorf("And did not next")
}
val := and.Result()
if val != 234 {
t.Errorf("Unexpected value")
}
@ -76,18 +76,15 @@ func TestAndAndFixedIterators(t *testing.T) {
t.Error("not accurate")
}
val, ok := and.Next()
if val != 3 || ok == false {
if !and.Next() || and.Result() != 3 {
t.Error("Incorrect first value")
}
val, ok = and.Next()
if val != 4 || ok == false {
if !and.Next() || and.Result() != 4 {
t.Error("Incorrect second value")
}
val, ok = and.Next()
if ok {
if and.Next() {
t.Error("Too many values")
}
@ -117,8 +114,7 @@ func TestNonOverlappingFixedIterators(t *testing.T) {
t.Error("not accurate")
}
_, ok := and.Next()
if ok {
if and.Next() {
t.Error("Too many values")
}
@ -131,18 +127,15 @@ func TestAllIterators(t *testing.T) {
and.AddSubIterator(all2)
and.AddSubIterator(all1)
val, ok := and.Next()
if val.(int64) != 4 || ok == false {
if !and.Next() || and.Result() != int64(4) {
t.Error("Incorrect first value")
}
val, ok = and.Next()
if val.(int64) != 5 || ok == false {
if !and.Next() || and.Result() != int64(5) {
t.Error("Incorrect second value")
}
val, ok = and.Next()
if ok {
if and.Next() {
t.Error("Too many values")
}

View file

@ -135,8 +135,8 @@ func (it *Fixed) Contains(v graph.Value) bool {
return graph.ContainsLogOut(it, v, false)
}
// Return the next stored value from the iterator.
func (it *Fixed) Next() (graph.Value, bool) {
// Next advances the iterator.
func (it *Fixed) Next() bool {
graph.NextLogIn(it)
if it.lastIndex == len(it.values) {
return graph.NextLogOut(it, nil, false)

View file

@ -158,16 +158,13 @@ func (it *HasA) Contains(val graph.Value) bool {
// result iterator (a triple iterator based on the last checked value) and returns true if
// another match is made.
func (it *HasA) NextContains() bool {
for {
linkVal, ok := graph.Next(it.resultIt)
if !ok {
break
}
for graph.Next(it.resultIt) {
link := it.resultIt.Result()
if glog.V(4) {
glog.V(4).Infoln("Quad is", it.ts.Quad(linkVal))
glog.V(4).Infoln("Quad is", it.ts.Quad(link))
}
if it.primaryIt.Contains(linkVal) {
it.result = it.ts.TripleDirection(linkVal, it.dir)
if it.primaryIt.Contains(link) {
it.result = it.ts.TripleDirection(link, it.dir)
return true
}
}
@ -188,20 +185,20 @@ func (it *HasA) NextPath() bool {
return it.NextContains()
}
// Get the next result from this iterator. This is simpler than Contains. We have a
// Next advances the iterator. This is simpler than Contains. We have a
// subiterator we can get a value from, and we can take that resultant triple,
// pull our direction out of it, and return that.
func (it *HasA) Next() (graph.Value, bool) {
func (it *HasA) Next() bool {
graph.NextLogIn(it)
if it.resultIt != nil {
it.resultIt.Close()
}
it.resultIt = &Null{}
tID, ok := graph.Next(it.primaryIt)
if !ok {
if !graph.Next(it.primaryIt) {
return graph.NextLogOut(it, 0, false)
}
tID := it.primaryIt.Result()
name := it.ts.Quad(tID).Get(it.dir)
val := it.ts.ValueOf(name)
it.result = val

View file

@ -79,8 +79,8 @@ func (it *Null) DebugString(indent int) string {
return strings.Repeat(" ", indent) + "(null)"
}
func (it *Null) Next() (graph.Value, bool) {
return nil, false
func (it *Null) Next() bool {
return false
}
func (it *Null) Result() graph.Value {

View file

@ -153,23 +153,23 @@ func (it *LinksTo) Optimize() (graph.Iterator, bool) {
}
// Next()ing a LinksTo operates as described above.
func (it *LinksTo) Next() (graph.Value, bool) {
func (it *LinksTo) Next() bool {
graph.NextLogIn(it)
val, ok := graph.Next(it.nextIt)
if !ok {
// Subiterator is empty, get another one
candidate, ok := graph.Next(it.primaryIt)
if !ok {
// We're out of nodes in our subiterator, so we're done as well.
return graph.NextLogOut(it, 0, false)
}
it.nextIt.Close()
it.nextIt = it.ts.TripleIterator(it.dir, candidate)
// Recurse -- return the first in the next set.
return it.Next()
if graph.Next(it.nextIt) {
it.result = it.nextIt.Result()
return graph.NextLogOut(it, it.nextIt, true)
}
it.result = val
return graph.NextLogOut(it, val, ok)
// Subiterator is empty, get another one
if !graph.Next(it.primaryIt) {
// We're out of nodes in our subiterator, so we're done as well.
return graph.NextLogOut(it, 0, false)
}
it.nextIt.Close()
it.nextIt = it.ts.TripleIterator(it.dir, it.primaryIt.Result())
// Recurse -- return the first in the next set.
return it.Next()
}
func (it *LinksTo) Result() graph.Value {

View file

@ -33,10 +33,10 @@ func TestLinksTo(t *testing.T) {
}
fixed.Add(val)
lto := NewLinksTo(ts, fixed, quad.Object)
val, ok := lto.Next()
if !ok {
if !lto.Next() {
t.Error("At least one triple matches the fixed object")
}
val = lto.Result()
if val != 2 {
t.Errorf("Quad index 2, such as %s, should match %s", ts.Quad(2), ts.Quad(val))
}

View file

@ -51,8 +51,6 @@ func NewOptional(it graph.Iterator) *Optional {
}
}
func (it *Optional) CanNext() bool { return false }
func (it *Optional) UID() uint64 {
return it.uid
}

View file

@ -141,35 +141,34 @@ func (it *Or) AddSubIterator(sub graph.Iterator) {
it.itCount++
}
// Returns the Next value from the Or graph.iterator. Because the Or is the
// union of its subiterators, it must produce from all subiterators -- unless
// it's shortcircuiting, in which case, it's the first one that returns anything.
func (it *Or) Next() (graph.Value, bool) {
// Next advances the Or graph.iterator. Because the Or is the union of its
// subiterators, it must produce from all subiterators -- unless it it
// shortcircuiting, in which case, it is the first one that returns anything.
func (it *Or) Next() bool {
graph.NextLogIn(it)
var curr graph.Value
var exists bool
firstTime := false
var first bool
for {
if it.currentIterator == -1 {
it.currentIterator = 0
firstTime = true
first = true
}
curIt := it.internalIterators[it.currentIterator]
curr, exists = graph.Next(curIt)
if !exists {
if it.isShortCircuiting && !firstTime {
return graph.NextLogOut(it, nil, false)
}
it.currentIterator++
if it.currentIterator == it.itCount {
return graph.NextLogOut(it, nil, false)
}
} else {
it.result = curr
return graph.NextLogOut(it, curr, true)
if graph.Next(curIt) {
it.result = curIt.Result()
return graph.NextLogOut(it, it.result, true)
}
if it.isShortCircuiting && !first {
break
}
it.currentIterator++
if it.currentIterator == it.itCount {
break
}
}
panic("unreachable")
return graph.NextLogOut(it, nil, false)
}
func (it *Or) Result() graph.Value {

View file

@ -23,12 +23,8 @@ import (
func iterated(it graph.Iterator) []int {
var res []int
for {
val, ok := graph.Next(it)
if !ok {
break
}
res = append(res, val.(int))
for graph.Next(it) {
res = append(res, it.Result().(int))
}
return res
}

View file

@ -129,12 +129,8 @@ func (qs *queryShape) MakeNode(it graph.Iterator) *Node {
}
case graph.Fixed:
n.IsFixed = true
for {
val, more := graph.Next(it)
if !more {
break
}
n.Values = append(n.Values, qs.ts.NameOf(val))
for graph.Next(it) {
n.Values = append(n.Values, qs.ts.NameOf(it.Result()))
}
case graph.HasA:
hasa := it.(*HasA)

View file

@ -127,20 +127,15 @@ func (it *Comparison) Clone() graph.Iterator {
return out
}
func (it *Comparison) Next() (graph.Value, bool) {
var val graph.Value
var ok bool
for {
val, ok = graph.Next(it.subIt)
if !ok {
return nil, false
}
func (it *Comparison) Next() bool {
for graph.Next(it.subIt) {
val := it.subIt.Result()
if it.doComparison(val) {
break
it.result = val
return true
}
}
it.result = val
return val, ok
return false
}
// DEPRECATED

View file

@ -69,12 +69,8 @@ func TestValueComparison(t *testing.T) {
vc := NewComparison(simpleFixedIterator(), test.operator, test.operand, ts)
var got []string
for {
val, ok := vc.Next()
if !ok {
break
}
got = append(got, ts.NameOf(val))
for vc.Next() {
got = append(got, ts.NameOf(vc.Result()))
}
if !reflect.DeepEqual(got, test.expect) {
t.Errorf("Failed to show %s, got:%q expect:%q", test.message, got, test.expect)