Canonicalise iterator receiver names

This apparently meaningless churn improves godoc readability.
This commit is contained in:
kortschak 2014-06-28 21:36:50 +09:30
parent dc65ebce9e
commit 60d5c60817
10 changed files with 432 additions and 435 deletions

View file

@ -45,70 +45,69 @@ func NewInt64AllIterator(min, max int64) *Int64AllIterator {
} }
// Start back at the beginning // Start back at the beginning
func (a *Int64AllIterator) Reset() { func (it *Int64AllIterator) Reset() {
a.at = a.min it.at = it.min
} }
func (a *Int64AllIterator) Close() { func (it *Int64AllIterator) Close() {}
}
func (a *Int64AllIterator) Clone() Iterator { func (it *Int64AllIterator) Clone() Iterator {
out := NewInt64AllIterator(a.min, a.max) out := NewInt64AllIterator(it.min, it.max)
out.CopyTagsFrom(a) out.CopyTagsFrom(it)
return out return out
} }
// Prints the All iterator as just an "all". // Prints the All iterator as just an "all".
func (a *Int64AllIterator) DebugString(indent int) string { func (it *Int64AllIterator) DebugString(indent int) string {
return fmt.Sprintf("%s(%s)", strings.Repeat(" ", indent), a.Type()) return fmt.Sprintf("%s(%s)", strings.Repeat(" ", indent), it.Type())
} }
// Next() on an Int64 all iterator is a simple incrementing counter. // Next() on an Int64 all iterator is a simple incrementing counter.
// Return the next integer, and mark it as the result. // Return the next integer, and mark it as the result.
func (a *Int64AllIterator) Next() (TSVal, bool) { func (it *Int64AllIterator) Next() (TSVal, bool) {
NextLogIn(a) NextLogIn(it)
if a.at == -1 { if it.at == -1 {
return NextLogOut(a, nil, false) return NextLogOut(it, nil, false)
} }
val := a.at val := it.at
a.at = a.at + 1 it.at = it.at + 1
if a.at > a.max { if it.at > it.max {
a.at = -1 it.at = -1
} }
a.Last = val it.Last = val
return NextLogOut(a, val, true) return NextLogOut(it, val, true)
} }
// The number of elements in an Int64AllIterator is the size of the range. // The number of elements in an Int64AllIterator is the size of the range.
// The size is exact. // The size is exact.
func (a *Int64AllIterator) Size() (int64, bool) { func (it *Int64AllIterator) Size() (int64, bool) {
Size := ((a.max - a.min) + 1) Size := ((it.max - it.min) + 1)
return Size, true return Size, true
} }
// Check() for an Int64AllIterator is merely seeing if the passed value is // Check() for an Int64AllIterator is merely seeing if the passed value is
// withing the range, assuming the value is an int64. // withing the range, assuming the value is an int64.
func (a *Int64AllIterator) Check(tsv TSVal) bool { func (it *Int64AllIterator) Check(tsv TSVal) bool {
CheckLogIn(a, tsv) CheckLogIn(it, tsv)
v := tsv.(int64) v := tsv.(int64)
if a.min <= v && v <= a.max { if it.min <= v && v <= it.max {
a.Last = v it.Last = v
return CheckLogOut(a, v, true) return CheckLogOut(it, v, true)
} }
return CheckLogOut(a, v, false) return CheckLogOut(it, v, false)
} }
// The type of this iterator is an "all". This is important, as it puts it in // The type of this iterator is an "all". This is important, as it puts it in
// the class of "all iterators. // the class of "all iterators.
func (a *Int64AllIterator) Type() string { return "all" } func (it *Int64AllIterator) Type() string { return "all" }
// There's nothing to optimize about this little iterator. // There's nothing to optimize about this little iterator.
func (a *Int64AllIterator) Optimize() (Iterator, bool) { return a, false } func (it *Int64AllIterator) Optimize() (Iterator, bool) { return it, false }
// Stats for an Int64AllIterator are simple. Super cheap to do any operation, // Stats for an Int64AllIterator are simple. Super cheap to do any operation,
// and as big as the range. // and as big as the range.
func (a *Int64AllIterator) GetStats() *IteratorStats { func (it *Int64AllIterator) GetStats() *IteratorStats {
s, _ := a.Size() s, _ := it.Size()
return &IteratorStats{ return &IteratorStats{
CheckCost: 1, CheckCost: 1,
NextCost: 1, NextCost: 1,

View file

@ -41,80 +41,80 @@ func NewAndIterator() *AndIterator {
} }
// Reset all internal iterators // Reset all internal iterators
func (and *AndIterator) Reset() { func (it *AndIterator) Reset() {
and.primaryIt.Reset() it.primaryIt.Reset()
for _, it := range and.internalIterators { for _, sub := range it.internalIterators {
it.Reset() sub.Reset()
} }
and.checkList = nil it.checkList = nil
} }
func (and *AndIterator) Clone() Iterator { func (it *AndIterator) Clone() Iterator {
newAnd := NewAndIterator() and := NewAndIterator()
newAnd.AddSubIterator(and.primaryIt.Clone()) and.AddSubIterator(it.primaryIt.Clone())
newAnd.CopyTagsFrom(and) and.CopyTagsFrom(it)
for _, it := range and.internalIterators { for _, sub := range it.internalIterators {
newAnd.AddSubIterator(it.Clone()) and.AddSubIterator(sub.Clone())
} }
if and.checkList != nil { if it.checkList != nil {
newAnd.optimizeCheck() and.optimizeCheck()
} }
return newAnd return and
} }
// Returns a list.List of the subiterators, in order (primary iterator first). // Returns a list.List of the subiterators, in order (primary iterator first).
func (and *AndIterator) GetSubIterators() *list.List { func (it *AndIterator) GetSubIterators() *list.List {
l := list.New() l := list.New()
l.PushBack(and.primaryIt) l.PushBack(it.primaryIt)
for _, it := range and.internalIterators { for _, sub := range it.internalIterators {
l.PushBack(it) l.PushBack(sub)
} }
return l return l
} }
// Overrides BaseIterator TagResults, as it needs to add it's own results and // Overrides BaseIterator TagResults, as it needs to add it's own results and
// recurse down it's subiterators. // recurse down it's subiterators.
func (and *AndIterator) TagResults(out *map[string]TSVal) { func (it *AndIterator) TagResults(out *map[string]TSVal) {
and.BaseIterator.TagResults(out) it.BaseIterator.TagResults(out)
if and.primaryIt != nil { if it.primaryIt != nil {
and.primaryIt.TagResults(out) it.primaryIt.TagResults(out)
} }
for _, it := range and.internalIterators { for _, sub := range it.internalIterators {
it.TagResults(out) sub.TagResults(out)
} }
} }
// DEPRECATED Returns the ResultTree for this iterator, recurses to it's subiterators. // DEPRECATED Returns the ResultTree for this iterator, recurses to it's subiterators.
func (and *AndIterator) GetResultTree() *ResultTree { func (it *AndIterator) GetResultTree() *ResultTree {
tree := NewResultTree(and.LastResult()) tree := NewResultTree(it.LastResult())
tree.AddSubtree(and.primaryIt.GetResultTree()) tree.AddSubtree(it.primaryIt.GetResultTree())
for _, it := range and.internalIterators { for _, sub := range it.internalIterators {
tree.AddSubtree(it.GetResultTree()) tree.AddSubtree(sub.GetResultTree())
} }
return tree return tree
} }
// Prints information about this iterator. // Prints information about this iterator.
func (and *AndIterator) DebugString(indent int) string { func (it *AndIterator) DebugString(indent int) string {
var total string var total string
for i, it := range and.internalIterators { for i, sub := range it.internalIterators {
total += strings.Repeat(" ", indent+2) total += strings.Repeat(" ", indent+2)
total += fmt.Sprintf("%d:\n%s\n", i, it.DebugString(indent+4)) total += fmt.Sprintf("%d:\n%s\n", i, sub.DebugString(indent+4))
} }
var tags string var tags string
for _, k := range and.Tags() { for _, k := range it.Tags() {
tags += fmt.Sprintf("%s;", k) tags += fmt.Sprintf("%s;", k)
} }
spaces := strings.Repeat(" ", indent+2) spaces := strings.Repeat(" ", indent+2)
return fmt.Sprintf("%s(%s %d\n%stags:%s\n%sprimary_it:\n%s\n%sother_its:\n%s)", return fmt.Sprintf("%s(%s %d\n%stags:%s\n%sprimary_it:\n%s\n%sother_its:\n%s)",
strings.Repeat(" ", indent), strings.Repeat(" ", indent),
and.Type(), it.Type(),
and.GetUid(), it.GetUid(),
spaces, spaces,
tags, tags,
spaces, spaces,
and.primaryIt.DebugString(indent+4), it.primaryIt.DebugString(indent+4),
spaces, spaces,
total) total)
} }
@ -125,43 +125,42 @@ func (and *AndIterator) DebugString(indent int) string {
// important. Calling Optimize() is the way to change the order based on // important. Calling Optimize() is the way to change the order based on
// subiterator statistics. Without Optimize(), the order added is the order // subiterator statistics. Without Optimize(), the order added is the order
// used. // used.
func (and *AndIterator) AddSubIterator(sub Iterator) { func (it *AndIterator) AddSubIterator(sub Iterator) {
if and.itCount > 0 { if it.itCount > 0 {
and.internalIterators = append(and.internalIterators, sub) it.internalIterators = append(it.internalIterators, sub)
and.itCount++ it.itCount++
return return
} }
and.primaryIt = sub it.primaryIt = sub
and.itCount++ it.itCount++
} }
// Returns the Next value from the And iterator. Because the And is the // 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 // intersection of its subiterators, it must choose one subiterator to produce a
// candidate, and check this value against the subiterators. A productive choice // candidate, and check this value against the subiterators. A productive choice
// of primary iterator is therefore very important. // of primary iterator is therefore very important.
func (and *AndIterator) Next() (TSVal, bool) { func (it *AndIterator) Next() (TSVal, bool) {
NextLogIn(and) NextLogIn(it)
var curr TSVal var curr TSVal
var exists bool var exists bool
for { for {
curr, exists = it.primaryIt.Next()
curr, exists = and.primaryIt.Next()
if !exists { if !exists {
return NextLogOut(and, nil, false) return NextLogOut(it, nil, false)
} }
if and.checkSubIts(curr) { if it.checkSubIts(curr) {
and.Last = curr it.Last = curr
return NextLogOut(and, curr, true) return NextLogOut(it, curr, true)
} }
} }
panic("Somehow broke out of Next() loop in AndIterator") panic("Somehow broke out of Next() loop in AndIterator")
} }
// Checks a value against the non-primary iterators, in order. // Checks a value against the non-primary iterators, in order.
func (and *AndIterator) checkSubIts(val TSVal) bool { func (it *AndIterator) checkSubIts(val TSVal) bool {
var subIsGood = true var subIsGood = true
for _, it := range and.internalIterators { for _, sub := range it.internalIterators {
subIsGood = it.Check(val) subIsGood = sub.Check(val)
if !subIsGood { if !subIsGood {
break break
} }
@ -169,43 +168,43 @@ func (and *AndIterator) checkSubIts(val TSVal) bool {
return subIsGood return subIsGood
} }
func (and *AndIterator) checkCheckList(val TSVal) bool { func (it *AndIterator) checkCheckList(val TSVal) bool {
var isGood = true var isGood = true
for e := and.checkList.Front(); e != nil; e = e.Next() { for e := it.checkList.Front(); e != nil; e = e.Next() {
isGood = e.Value.(Iterator).Check(val) isGood = e.Value.(Iterator).Check(val)
if !isGood { if !isGood {
break break
} }
} }
return CheckLogOut(and, val, isGood) return CheckLogOut(it, val, isGood)
} }
// Check a value against the entire iterator, in order. // Check a value against the entire iterator, in order.
func (and *AndIterator) Check(val TSVal) bool { func (it *AndIterator) Check(val TSVal) bool {
CheckLogIn(and, val) CheckLogIn(it, val)
if and.checkList != nil { if it.checkList != nil {
return and.checkCheckList(val) return it.checkCheckList(val)
} }
mainGood := and.primaryIt.Check(val) mainGood := it.primaryIt.Check(val)
if !mainGood { if !mainGood {
return CheckLogOut(and, val, false) return CheckLogOut(it, val, false)
} }
othersGood := and.checkSubIts(val) othersGood := it.checkSubIts(val)
if !othersGood { if !othersGood {
return CheckLogOut(and, val, false) return CheckLogOut(it, val, false)
} }
and.Last = val it.Last = val
return CheckLogOut(and, val, true) return CheckLogOut(it, val, true)
} }
// Returns the approximate size of the And iterator. Because we're dealing // 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 // 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 // smallest iterator. This is the heuristic we shall follow. Better heuristics
// welcome. // welcome.
func (and *AndIterator) Size() (int64, bool) { func (it *AndIterator) Size() (int64, bool) {
val, b := and.primaryIt.Size() val, b := it.primaryIt.Size()
for _, it := range and.internalIterators { for _, sub := range it.internalIterators {
newval, newb := it.Size() newval, newb := sub.Size()
if val > newval { if val > newval {
val = newval val = newval
} }
@ -217,12 +216,12 @@ func (and *AndIterator) Size() (int64, bool) {
// An And has no NextResult of its own -- that is, there are no other values // 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 // which satisfy our previous result that are not the result itself. Our
// subiterators might, however, so just pass the call recursively. // subiterators might, however, so just pass the call recursively.
func (and *AndIterator) NextResult() bool { func (it *AndIterator) NextResult() bool {
if and.primaryIt.NextResult() { if it.primaryIt.NextResult() {
return true return true
} }
for _, it := range and.internalIterators { for _, sub := range it.internalIterators {
if it.NextResult() { if sub.NextResult() {
return true return true
} }
} }
@ -230,19 +229,18 @@ func (and *AndIterator) NextResult() bool {
} }
// Perform and-specific cleanup, of which there currently is none. // Perform and-specific cleanup, of which there currently is none.
func (and *AndIterator) cleanUp() { func (it *AndIterator) cleanUp() {}
}
// Close this iterator, and, by extension, close the subiterators. // Close this iterator, and, by extension, close the subiterators.
// Close should be idempotent, and it follows that if it's subiterators // Close should be idempotent, and it follows that if it's subiterators
// follow this contract, the And follows the contract. // follow this contract, the And follows the contract.
func (and *AndIterator) Close() { func (it *AndIterator) Close() {
and.cleanUp() it.cleanUp()
and.primaryIt.Close() it.primaryIt.Close()
for _, it := range and.internalIterators { for _, sub := range it.internalIterators {
it.Close() sub.Close()
} }
} }
// Register this as an "and" iterator. // Register this as an "and" iterator.
func (and *AndIterator) Type() string { return "and" } func (it *AndIterator) Type() string { return "and" }

View file

@ -37,10 +37,10 @@ import (
// Optimizes the AndIterator, by picking the most efficient way to Next() and // Optimizes the AndIterator, by picking the most efficient way to Next() and
// Check() its subiterators. For SQL fans, this is equivalent to JOIN. // Check() its subiterators. For SQL fans, this is equivalent to JOIN.
func (and *AndIterator) Optimize() (Iterator, bool) { func (it *AndIterator) Optimize() (Iterator, bool) {
// First, let's get the list of iterators, in order (first one is Next()ed, // First, let's get the list of iterators, in order (first one is Next()ed,
// the rest are Check()ed) // the rest are Check()ed)
oldItList := and.GetSubIterators() oldItList := it.GetSubIterators()
// And call Optimize() on our subtree, replacing each one in the order we // And call Optimize() on our subtree, replacing each one in the order we
// found them. it_list is the newly optimized versions of these, and changed // found them. it_list is the newly optimized versions of these, and changed
@ -54,10 +54,10 @@ func (and *AndIterator) Optimize() (Iterator, bool) {
// If we can find only one subiterator which is equivalent to this whole and, // If we can find only one subiterator which is equivalent to this whole and,
// we can replace the And... // we can replace the And...
out := and.optimizeReplacement(itList) out := it.optimizeReplacement(itList)
if out != nil { if out != nil {
// ...Move the tags to the replacement... // ...Move the tags to the replacement...
moveTagsTo(out, and) moveTagsTo(out, it)
// ...Close everyone except `out`, our replacement... // ...Close everyone except `out`, our replacement...
closeIteratorList(itList, out) closeIteratorList(itList, out)
// ...And return it. // ...And return it.
@ -80,14 +80,14 @@ func (and *AndIterator) Optimize() (Iterator, bool) {
} }
// Move the tags hanging on us (like any good replacement). // Move the tags hanging on us (like any good replacement).
newAnd.CopyTagsFrom(and) newAnd.CopyTagsFrom(it)
newAnd.optimizeCheck() newAnd.optimizeCheck()
// And close ourselves but not our subiterators -- some may still be alive in // And close ourselves but not our subiterators -- some may still be alive in
// the new And (they were unchanged upon calling Optimize() on them, at the // the new And (they were unchanged upon calling Optimize() on them, at the
// start). // start).
and.cleanUp() it.cleanUp()
return newAnd, true return newAnd, true
} }
@ -104,7 +104,7 @@ func closeIteratorList(l *list.List, except Iterator) {
// Find if there is a single subiterator which is a valid replacement for this // Find if there is a single subiterator which is a valid replacement for this
// AndIterator. // AndIterator.
func (and *AndIterator) optimizeReplacement(itList *list.List) Iterator { func (_ *AndIterator) optimizeReplacement(itList *list.List) Iterator {
// If we were created with no SubIterators, we're as good as Null. // If we were created with no SubIterators, we're as good as Null.
if itList.Len() == 0 { if itList.Len() == 0 {
return &NullIterator{} return &NullIterator{}
@ -190,8 +190,8 @@ func optimizeOrder(l *list.List) *list.List {
// optimizeCheck(l) creates an alternate check list, containing the same contents // optimizeCheck(l) creates an alternate check list, containing the same contents
// but with a new ordering, however it wishes. // but with a new ordering, however it wishes.
func (and *AndIterator) optimizeCheck() { func (it *AndIterator) optimizeCheck() {
subIts := and.GetSubIterators() subIts := it.GetSubIterators()
out := list.New() out := list.New()
// Find the iterator with the lowest Check() cost, push it to the front, repeat. // Find the iterator with the lowest Check() cost, push it to the front, repeat.
@ -211,15 +211,15 @@ func (and *AndIterator) optimizeCheck() {
subIts.Remove(best) subIts.Remove(best)
} }
and.checkList = out it.checkList = out
} }
// If we're replacing ourselves by a single iterator, we need to grab the // If we're replacing ourselves by a single iterator, we need to grab the
// result tags from the iterators that, while still valid and would hold // result tags from the iterators that, while still valid and would hold
// the same values as this and, are not going to stay. // the same values as this and, are not going to stay.
// getSubTags() returns a map of the tags for all the subiterators. // getSubTags() returns a map of the tags for all the subiterators.
func (and *AndIterator) getSubTags() map[string]bool { func (it *AndIterator) getSubTags() map[string]bool {
subs := and.GetSubIterators() subs := it.GetSubIterators()
tags := make(map[string]bool) tags := make(map[string]bool)
for e := subs.Front(); e != nil; e = e.Next() { for e := subs.Front(); e != nil; e = e.Next() {
it := e.Value.(Iterator) it := e.Value.(Iterator)
@ -227,23 +227,23 @@ func (and *AndIterator) getSubTags() map[string]bool {
tags[tag] = true tags[tag] = true
} }
} }
for _, tag := range and.Tags() { for _, tag := range it.Tags() {
tags[tag] = true tags[tag] = true
} }
return tags return tags
} }
// moveTagsTo() gets the tags for all of the And's subiterators and the // moveTagsTo() gets the tags for all of the src's subiterators and the
// And itself, and moves them to `out`. // src itself, and moves them to dst.
func moveTagsTo(out Iterator, and *AndIterator) { func moveTagsTo(dst Iterator, src *AndIterator) {
tagmap := and.getSubTags() tagmap := src.getSubTags()
for _, tag := range out.Tags() { for _, tag := range dst.Tags() {
if tagmap[tag] { if tagmap[tag] {
delete(tagmap, tag) delete(tagmap, tag)
} }
} }
for k, _ := range tagmap { for k, _ := range tagmap {
out.AddTag(k) dst.AddTag(k)
} }
} }
@ -308,13 +308,13 @@ func hasOneUsefulIterator(l *list.List) Iterator {
// and.GetStats() lives here in and-iterator-optimize.go because it may // and.GetStats() lives here in and-iterator-optimize.go because it may
// in the future return different statistics based on how it is optimized. // in the future return different statistics based on how it is optimized.
// For now, however, it's pretty static. // For now, however, it's pretty static.
func (and *AndIterator) GetStats() *IteratorStats { func (it *AndIterator) GetStats() *IteratorStats {
primaryStats := and.primaryIt.GetStats() primaryStats := it.primaryIt.GetStats()
CheckCost := primaryStats.CheckCost CheckCost := primaryStats.CheckCost
NextCost := primaryStats.NextCost NextCost := primaryStats.NextCost
Size := primaryStats.Size Size := primaryStats.Size
for _, it := range and.internalIterators { for _, sub := range it.internalIterators {
stats := it.GetStats() stats := sub.GetStats()
NextCost += stats.CheckCost NextCost += stats.CheckCost
CheckCost += stats.CheckCost CheckCost += stats.CheckCost
if Size > stats.Size { if Size > stats.Size {

View file

@ -60,98 +60,97 @@ func NewFixedIteratorWithCompare(compareFn Equality) *FixedIterator {
return &it return &it
} }
func (f *FixedIterator) Reset() { func (it *FixedIterator) Reset() {
f.lastIndex = 0 it.lastIndex = 0
} }
func (f *FixedIterator) Close() { func (it *FixedIterator) Close() {}
}
func (f *FixedIterator) Clone() Iterator { func (it *FixedIterator) Clone() Iterator {
out := NewFixedIteratorWithCompare(f.cmp) out := NewFixedIteratorWithCompare(it.cmp)
for _, val := range f.values { for _, val := range it.values {
out.AddValue(val) out.AddValue(val)
} }
out.CopyTagsFrom(f) out.CopyTagsFrom(it)
return out return out
} }
// Add a value to the iterator. The array now contains this value. // Add a value to the iterator. The array now contains this value.
// TODO(barakmich): This ought to be a set someday, disallowing repeated values. // TODO(barakmich): This ought to be a set someday, disallowing repeated values.
func (f *FixedIterator) AddValue(v TSVal) { func (it *FixedIterator) AddValue(v TSVal) {
f.values = append(f.values, v) it.values = append(it.values, v)
} }
// Print some information about the iterator. // Print some information about the iterator.
func (f *FixedIterator) DebugString(indent int) string { func (it *FixedIterator) DebugString(indent int) string {
value := "" value := ""
if len(f.values) > 0 { if len(it.values) > 0 {
value = fmt.Sprint(f.values[0]) value = fmt.Sprint(it.values[0])
} }
return fmt.Sprintf("%s(%s tags: %s Size: %d id0: %d)", return fmt.Sprintf("%s(%s tags: %s Size: %d id0: %d)",
strings.Repeat(" ", indent), strings.Repeat(" ", indent),
f.Type(), it.Type(),
f.FixedTags(), it.FixedTags(),
len(f.values), len(it.values),
value, value,
) )
} }
// Register this iterator as a Fixed iterator. // Register this iterator as a Fixed iterator.
func (f *FixedIterator) Type() string { func (it *FixedIterator) Type() string {
return "fixed" return "fixed"
} }
// Check if the passed value is equal to one of the values stored in the iterator. // Check if the passed value is equal to one of the values stored in the iterator.
func (f *FixedIterator) Check(v TSVal) bool { func (it *FixedIterator) Check(v TSVal) bool {
// Could be optimized by keeping it sorted or using a better datastructure. // Could be optimized by keeping it sorted or using a better datastructure.
// However, for fixed iterators, which are by definition kind of tiny, this // However, for fixed iterators, which are by definition kind of tiny, this
// isn't a big issue. // isn't a big issue.
CheckLogIn(f, v) CheckLogIn(it, v)
for _, x := range f.values { for _, x := range it.values {
if f.cmp(x, v) { if it.cmp(x, v) {
f.Last = x it.Last = x
return CheckLogOut(f, v, true) return CheckLogOut(it, v, true)
} }
} }
return CheckLogOut(f, v, false) return CheckLogOut(it, v, false)
} }
// Return the next stored value from the iterator. // Return the next stored value from the iterator.
func (f *FixedIterator) Next() (TSVal, bool) { func (it *FixedIterator) Next() (TSVal, bool) {
NextLogIn(f) NextLogIn(it)
if f.lastIndex == len(f.values) { if it.lastIndex == len(it.values) {
return NextLogOut(f, nil, false) return NextLogOut(it, nil, false)
} }
out := f.values[f.lastIndex] out := it.values[it.lastIndex]
f.Last = out it.Last = out
f.lastIndex++ it.lastIndex++
return NextLogOut(f, out, true) return NextLogOut(it, out, true)
} }
// Optimize() for a Fixed iterator is simple. Returns a Null iterator if it's empty // Optimize() for a Fixed iterator is simple. Returns a Null iterator if it's empty
// (so that other iterators upstream can treat this as null) or there is no // (so that other iterators upstream can treat this as null) or there is no
// optimization. // optimization.
func (f *FixedIterator) Optimize() (Iterator, bool) { func (it *FixedIterator) Optimize() (Iterator, bool) {
if len(f.values) == 1 && f.values[0] == nil { if len(it.values) == 1 && it.values[0] == nil {
return &NullIterator{}, true return &NullIterator{}, true
} }
return f, false return it, false
} }
// Size is the number of values stored. // Size is the number of values stored.
func (f *FixedIterator) Size() (int64, bool) { func (it *FixedIterator) Size() (int64, bool) {
return int64(len(f.values)), true return int64(len(it.values)), true
} }
// As we right now have to scan the entire list, Next and Check are linear with the // As we right now have to scan the entire list, Next and Check are linear with the
// size. However, a better data structure could remove these limits. // size. However, a better data structure could remove these limits.
func (a *FixedIterator) GetStats() *IteratorStats { func (it *FixedIterator) GetStats() *IteratorStats {
return &IteratorStats{ return &IteratorStats{
CheckCost: int64(len(a.values)), CheckCost: int64(len(it.values)),
NextCost: int64(len(a.values)), NextCost: int64(len(it.values)),
Size: int64(len(a.values)), Size: int64(len(it.values)),
} }
} }

View file

@ -36,8 +36,9 @@ package graph
import ( import (
"container/list" "container/list"
"fmt" "fmt"
"github.com/barakmich/glog"
"strings" "strings"
"github.com/barakmich/glog"
) )
// A HasaIterator consists of a reference back to the TripleStore that it references, // A HasaIterator consists of a reference back to the TripleStore that it references,
@ -63,94 +64,93 @@ func NewHasaIterator(ts TripleStore, subIt Iterator, dir string) *HasaIterator {
} }
// Return our sole subiterator, in a list.List. // Return our sole subiterator, in a list.List.
func (h *HasaIterator) GetSubIterators() *list.List { func (it *HasaIterator) GetSubIterators() *list.List {
l := list.New() l := list.New()
l.PushBack(h.primaryIt) l.PushBack(it.primaryIt)
return l return l
} }
func (h *HasaIterator) Reset() { func (it *HasaIterator) Reset() {
h.primaryIt.Reset() it.primaryIt.Reset()
if h.resultIt != nil { if it.resultIt != nil {
h.resultIt.Close() it.resultIt.Close()
} }
} }
func (h *HasaIterator) Clone() Iterator { func (it *HasaIterator) Clone() Iterator {
out := NewHasaIterator(h.ts, h.primaryIt.Clone(), h.direction) out := NewHasaIterator(it.ts, it.primaryIt.Clone(), it.direction)
out.CopyTagsFrom(h) out.CopyTagsFrom(it)
return out return out
} }
// Direction accessor. // Direction accessor.
func (h *HasaIterator) Direction() string { return h.direction } func (it *HasaIterator) Direction() string { return it.direction }
// Pass the Optimize() call along to the subiterator. If it becomes Null, // Pass the Optimize() call along to the subiterator. If it becomes Null,
// then the HasA becomes Null (there are no triples that have any directions). // then the HasA becomes Null (there are no triples that have any directions).
func (h *HasaIterator) Optimize() (Iterator, bool) { func (it *HasaIterator) Optimize() (Iterator, bool) {
newPrimary, changed := it.primaryIt.Optimize()
newPrimary, changed := h.primaryIt.Optimize()
if changed { if changed {
h.primaryIt = newPrimary it.primaryIt = newPrimary
if h.primaryIt.Type() == "null" { if it.primaryIt.Type() == "null" {
return h.primaryIt, true return it.primaryIt, true
} }
} }
return h, false return it, false
} }
// Pass the TagResults down the chain. // Pass the TagResults down the chain.
func (h *HasaIterator) TagResults(out *map[string]TSVal) { func (it *HasaIterator) TagResults(out *map[string]TSVal) {
h.BaseIterator.TagResults(out) it.BaseIterator.TagResults(out)
h.primaryIt.TagResults(out) it.primaryIt.TagResults(out)
} }
// DEPRECATED Return results in a ResultTree. // DEPRECATED Return results in a ResultTree.
func (h *HasaIterator) GetResultTree() *ResultTree { func (it *HasaIterator) GetResultTree() *ResultTree {
tree := NewResultTree(h.LastResult()) tree := NewResultTree(it.LastResult())
tree.AddSubtree(h.primaryIt.GetResultTree()) tree.AddSubtree(it.primaryIt.GetResultTree())
return tree return tree
} }
// Print some information about this iterator. // Print some information about this iterator.
func (h *HasaIterator) DebugString(indent int) string { func (it *HasaIterator) DebugString(indent int) string {
var tags string var tags string
for _, k := range h.Tags() { for _, k := range it.Tags() {
tags += fmt.Sprintf("%s;", k) tags += fmt.Sprintf("%s;", k)
} }
return fmt.Sprintf("%s(%s %d tags:%s direction:%s\n%s)", strings.Repeat(" ", indent), h.Type(), h.GetUid(), tags, h.direction, h.primaryIt.DebugString(indent+4)) return fmt.Sprintf("%s(%s %d tags:%s direction:%s\n%s)", strings.Repeat(" ", indent), it.Type(), it.GetUid(), tags, it.direction, it.primaryIt.DebugString(indent+4))
} }
// Check a value against our internal iterator. In order to do this, we must first open a new // Check a value against our internal iterator. In order to do this, we must first open a new
// iterator of "triples that have `val` in our direction", given to us by the triple store, // iterator of "triples that have `val` in our direction", given to us by the triple store,
// and then Next() values out of that iterator and Check() them against our subiterator. // and then Next() values out of that iterator and Check() them against our subiterator.
func (h *HasaIterator) Check(val TSVal) bool { func (it *HasaIterator) Check(val TSVal) bool {
CheckLogIn(h, val) CheckLogIn(it, val)
if glog.V(4) { if glog.V(4) {
glog.V(4).Infoln("Id is", h.ts.GetNameFor(val)) glog.V(4).Infoln("Id is", it.ts.GetNameFor(val))
} }
// TODO(barakmich): Optimize this // TODO(barakmich): Optimize this
if h.resultIt != nil { if it.resultIt != nil {
h.resultIt.Close() it.resultIt.Close()
} }
h.resultIt = h.ts.GetTripleIterator(h.direction, val) it.resultIt = it.ts.GetTripleIterator(it.direction, val)
return CheckLogOut(h, val, h.GetCheckResult()) return CheckLogOut(it, val, it.GetCheckResult())
} }
// GetCheckResult() is shared code between Check() and GetNextResult() -- calls next on the // GetCheckResult() is shared code between Check() and GetNextResult() -- calls next on the
// result iterator (a triple iterator based on the last checked value) and returns true if // result iterator (a triple iterator based on the last checked value) and returns true if
// another match is made. // another match is made.
func (h *HasaIterator) GetCheckResult() bool { func (it *HasaIterator) GetCheckResult() bool {
for { for {
linkVal, ok := h.resultIt.Next() linkVal, ok := it.resultIt.Next()
if !ok { if !ok {
break break
} }
if glog.V(4) { if glog.V(4) {
glog.V(4).Infoln("Triple is", h.ts.GetTriple(linkVal).ToString()) glog.V(4).Infoln("Triple is", it.ts.GetTriple(linkVal).ToString())
} }
if h.primaryIt.Check(linkVal) { if it.primaryIt.Check(linkVal) {
h.Last = h.ts.GetTripleDirection(linkVal, h.direction) it.Last = it.ts.GetTripleDirection(linkVal, it.direction)
return true return true
} }
} }
@ -158,37 +158,37 @@ func (h *HasaIterator) GetCheckResult() bool {
} }
// Get the next result that matches this branch. // Get the next result that matches this branch.
func (h *HasaIterator) NextResult() bool { func (it *HasaIterator) NextResult() bool {
// Order here is important. If the subiterator has a NextResult, then we // Order here is important. If the subiterator has a NextResult, then we
// need do nothing -- there is a next result, and we shouldn't move forward. // need do nothing -- there is a next result, and we shouldn't move forward.
// However, we then need to get the next result from our last Check(). // However, we then need to get the next result from our last Check().
// //
// The upshot is, the end of NextResult() bubbles up from the bottom of the // The upshot is, the end of NextResult() bubbles up from the bottom of the
// iterator tree up, and we need to respect that. // iterator tree up, and we need to respect that.
if h.primaryIt.NextResult() { if it.primaryIt.NextResult() {
return true return true
} }
return h.GetCheckResult() return it.GetCheckResult()
} }
// Get the next result from this iterator. This is simpler than Check. We have a // Get the next result from this iterator. This is simpler than Check. We have a
// subiterator we can get a value from, and we can take that resultant triple, // subiterator we can get a value from, and we can take that resultant triple,
// pull our direction out of it, and return that. // pull our direction out of it, and return that.
func (h *HasaIterator) Next() (TSVal, bool) { func (it *HasaIterator) Next() (TSVal, bool) {
NextLogIn(h) NextLogIn(it)
if h.resultIt != nil { if it.resultIt != nil {
h.resultIt.Close() it.resultIt.Close()
} }
h.resultIt = &NullIterator{} it.resultIt = &NullIterator{}
tID, ok := h.primaryIt.Next() tID, ok := it.primaryIt.Next()
if !ok { if !ok {
return NextLogOut(h, 0, false) return NextLogOut(it, 0, false)
} }
name := h.ts.GetTriple(tID).Get(h.direction) name := it.ts.GetTriple(tID).Get(it.direction)
val := h.ts.GetIdFor(name) val := it.ts.GetIdFor(name)
h.Last = val it.Last = val
return NextLogOut(h, val, true) return NextLogOut(it, val, true)
} }
// GetStats() returns the statistics on the HasA iterator. This is curious. Next // GetStats() returns the statistics on the HasA iterator. This is curious. Next
@ -197,8 +197,8 @@ func (h *HasaIterator) Next() (TSVal, bool) {
// one sticks -- potentially expensive, depending on fanout. Size, however, is // one sticks -- potentially expensive, depending on fanout. Size, however, is
// potentially smaller. we know at worst it's the size of the subiterator, but // potentially smaller. we know at worst it's the size of the subiterator, but
// if there are many repeated values, it could be much smaller in totality. // if there are many repeated values, it could be much smaller in totality.
func (h *HasaIterator) GetStats() *IteratorStats { func (it *HasaIterator) GetStats() *IteratorStats {
subitStats := h.primaryIt.GetStats() subitStats := it.primaryIt.GetStats()
// TODO(barakmich): These should really come from the triplestore itself // TODO(barakmich): These should really come from the triplestore itself
// and be optimized. // and be optimized.
faninFactor := int64(1) faninFactor := int64(1)
@ -213,12 +213,12 @@ func (h *HasaIterator) GetStats() *IteratorStats {
} }
// Close the subiterator, the result iterator (if any) and the HasA. // Close the subiterator, the result iterator (if any) and the HasA.
func (h *HasaIterator) Close() { func (it *HasaIterator) Close() {
if h.resultIt != nil { if it.resultIt != nil {
h.resultIt.Close() it.resultIt.Close()
} }
h.primaryIt.Close() it.primaryIt.Close()
} }
// Register this iterator as a HasA. // Register this iterator as a HasA.
func (h *HasaIterator) Type() string { return "hasa" } func (it *HasaIterator) Type() string { return "hasa" }

View file

@ -20,8 +20,9 @@ package graph
import ( import (
"container/list" "container/list"
"fmt" "fmt"
"github.com/barakmich/glog"
"strings" "strings"
"github.com/barakmich/glog"
) )
var iterator_n int = 0 var iterator_n int = 0
@ -120,50 +121,50 @@ type BaseIterator struct {
} }
// Called by subclases. // Called by subclases.
func BaseIteratorInit(b *BaseIterator) { func BaseIteratorInit(it *BaseIterator) {
// Your basic iterator is nextable // Your basic iterator is nextable
b.nextable = true it.nextable = true
b.uid = iterator_n it.uid = iterator_n
if glog.V(2) { if glog.V(2) {
iterator_n++ iterator_n++
} }
} }
func (b *BaseIterator) GetUid() int { func (it *BaseIterator) GetUid() int {
return b.uid return it.uid
} }
// Adds a tag to the iterator. Most iterators don't need to override. // Adds a tag to the iterator. Most iterators don't need to override.
func (b *BaseIterator) AddTag(tag string) { func (it *BaseIterator) AddTag(tag string) {
if b.tags == nil { if it.tags == nil {
b.tags = make([]string, 0) it.tags = make([]string, 0)
} }
b.tags = append(b.tags, tag) it.tags = append(it.tags, tag)
} }
func (b *BaseIterator) AddFixedTag(tag string, value TSVal) { func (it *BaseIterator) AddFixedTag(tag string, value TSVal) {
if b.fixedTags == nil { if it.fixedTags == nil {
b.fixedTags = make(map[string]TSVal) it.fixedTags = make(map[string]TSVal)
} }
b.fixedTags[tag] = value it.fixedTags[tag] = value
} }
// Returns the tags. // Returns the tags.
func (b *BaseIterator) Tags() []string { func (it *BaseIterator) Tags() []string {
return b.tags return it.tags
} }
func (b *BaseIterator) FixedTags() map[string]TSVal { func (it *BaseIterator) FixedTags() map[string]TSVal {
return b.fixedTags return it.fixedTags
} }
func (b *BaseIterator) CopyTagsFrom(other_it Iterator) { func (it *BaseIterator) CopyTagsFrom(other_it Iterator) {
for _, tag := range other_it.Tags() { for _, tag := range other_it.Tags() {
b.AddTag(tag) it.AddTag(tag)
} }
for k, v := range other_it.FixedTags() { for k, v := range other_it.FixedTags() {
b.AddFixedTag(k, v) it.AddFixedTag(k, v)
} }
} }
@ -185,55 +186,55 @@ func (n *BaseIterator) GetStats() *IteratorStats {
} }
// DEPRECATED // DEPRECATED
func (b *BaseIterator) GetResultTree() *ResultTree { func (it *BaseIterator) GetResultTree() *ResultTree {
tree := NewResultTree(b.LastResult()) tree := NewResultTree(it.LastResult())
return tree return tree
} }
// Nothing in a base iterator. // Nothing in a base iterator.
func (n *BaseIterator) Next() (TSVal, bool) { func (it *BaseIterator) Next() (TSVal, bool) {
return nil, false return nil, false
} }
func (n *BaseIterator) NextResult() bool { func (it *BaseIterator) NextResult() bool {
return false return false
} }
// Returns the last result of an iterator. // Returns the last result of an iterator.
func (n *BaseIterator) LastResult() TSVal { func (it *BaseIterator) LastResult() TSVal {
return n.Last return it.Last
} }
// If you're empty and you know it, clap your hands. // If you're empty and you know it, clap your hands.
func (n *BaseIterator) Size() (int64, bool) { func (it *BaseIterator) Size() (int64, bool) {
return 0, true return 0, true
} }
// No subiterators. Only those with subiterators need to do anything here. // No subiterators. Only those with subiterators need to do anything here.
func (n *BaseIterator) GetSubIterators() *list.List { func (it *BaseIterator) GetSubIterators() *list.List {
return nil return nil
} }
// Accessor // Accessor
func (b *BaseIterator) Nextable() bool { return b.nextable } func (it *BaseIterator) Nextable() bool { return it.nextable }
// Fill the map based on the tags assigned to this iterator. Default // Fill the map based on the tags assigned to this iterator. Default
// functionality works well for most iterators. // functionality works well for most iterators.
func (a *BaseIterator) TagResults(out_map *map[string]TSVal) { func (it *BaseIterator) TagResults(out_map *map[string]TSVal) {
for _, tag := range a.Tags() { for _, tag := range it.Tags() {
(*out_map)[tag] = a.LastResult() (*out_map)[tag] = it.LastResult()
} }
for tag, value := range a.FixedTags() { for tag, value := range it.FixedTags() {
(*out_map)[tag] = value (*out_map)[tag] = value
} }
} }
// Nothing to clean up. // Nothing to clean up.
//func (a *BaseIterator) Close() {} //func (a *BaseIterator) Close() {}
func (a *NullIterator) Close() {} func (it *NullIterator) Close() {}
func (a *BaseIterator) Reset() {} func (it *BaseIterator) Reset() {}
// Here we define the simplest base iterator -- the Null iterator. It contains nothing. // Here we define the simplest base iterator -- the Null iterator. It contains nothing.
// It is the empty set. Often times, queries that contain one of these match nothing, // It is the empty set. Often times, queries that contain one of these match nothing,
@ -244,26 +245,25 @@ type NullIterator struct {
// Fairly useless New function. // Fairly useless New function.
func NewNullIterator() *NullIterator { func NewNullIterator() *NullIterator {
var n NullIterator return &NullIterator{}
return &n
} }
func (n *NullIterator) Clone() Iterator { return NewNullIterator() } func (it *NullIterator) Clone() Iterator { return NewNullIterator() }
// Name the null iterator. // Name the null iterator.
func (n *NullIterator) Type() string { return "null" } func (it *NullIterator) Type() string { return "null" }
// A good iterator will close itself when it returns true. // A good iterator will close itself when it returns true.
// Null has nothing it needs to do. // Null has nothing it needs to do.
func (n *NullIterator) Optimize() (Iterator, bool) { return n, false } func (it *NullIterator) Optimize() (Iterator, bool) { return it, false }
// Print the null iterator. // Print the null iterator.
func (n *NullIterator) DebugString(indent int) string { func (it *NullIterator) DebugString(indent int) string {
return strings.Repeat(" ", indent) + "(null)" return strings.Repeat(" ", indent) + "(null)"
} }
// A null iterator costs nothing. Use it! // A null iterator costs nothing. Use it!
func (n *NullIterator) GetStats() *IteratorStats { func (it *NullIterator) GetStats() *IteratorStats {
return &IteratorStats{0, 0, 0} return &IteratorStats{0, 0, 0}
} }

View file

@ -28,8 +28,9 @@ package graph
import ( import (
"fmt" "fmt"
"github.com/barakmich/glog"
"strings" "strings"
"github.com/barakmich/glog"
) )
// An optional iterator has the subconstraint iterator we wish to be optional // An optional iterator has the subconstraint iterator we wish to be optional
@ -49,24 +50,24 @@ func NewOptionalIterator(it Iterator) *OptionalIterator {
return &o return &o
} }
func (o *OptionalIterator) Reset() { func (it *OptionalIterator) Reset() {
o.subIt.Reset() it.subIt.Reset()
o.lastCheck = false it.lastCheck = false
} }
func (o *OptionalIterator) Close() { func (it *OptionalIterator) Close() {
o.subIt.Close() it.subIt.Close()
} }
func (o *OptionalIterator) Clone() Iterator { func (it *OptionalIterator) Clone() Iterator {
out := NewOptionalIterator(o.subIt.Clone()) out := NewOptionalIterator(it.subIt.Clone())
out.CopyTagsFrom(o) out.CopyTagsFrom(it)
return out return out
} }
// Nexting the iterator is unsupported -- error and return an empty set. // Nexting the iterator is unsupported -- error and return an empty set.
// (As above, a reasonable alternative would be to Next() an all iterator) // (As above, a reasonable alternative would be to Next() an all iterator)
func (o *OptionalIterator) Next() (TSVal, bool) { func (it *OptionalIterator) Next() (TSVal, bool) {
glog.Errorln("Nexting an un-nextable iterator") glog.Errorln("Nexting an un-nextable iterator")
return nil, false return nil, false
} }
@ -74,9 +75,9 @@ func (o *OptionalIterator) Next() (TSVal, bool) {
// An optional iterator only has a next result if, (a) last time we checked // An optional iterator only has a next result if, (a) last time we checked
// we had any results whatsoever, and (b) there was another subresult in our // we had any results whatsoever, and (b) there was another subresult in our
// optional subbranch. // optional subbranch.
func (o *OptionalIterator) NextResult() bool { func (it *OptionalIterator) NextResult() bool {
if o.lastCheck { if it.lastCheck {
return o.subIt.NextResult() return it.subIt.NextResult()
} }
return false return false
} }
@ -84,48 +85,48 @@ func (o *OptionalIterator) NextResult() bool {
// Check() is the real hack of this iterator. It always returns true, regardless // Check() is the real hack of this iterator. It always returns true, regardless
// of whether the subiterator matched. But we keep track of whether the subiterator // of whether the subiterator matched. But we keep track of whether the subiterator
// matched for results purposes. // matched for results purposes.
func (o *OptionalIterator) Check(val TSVal) bool { func (it *OptionalIterator) Check(val TSVal) bool {
checked := o.subIt.Check(val) checked := it.subIt.Check(val)
o.lastCheck = checked it.lastCheck = checked
o.Last = val it.Last = val
return true return true
} }
// If we failed the check, then the subiterator should not contribute to the result // If we failed the check, then the subiterator should not contribute to the result
// set. Otherwise, go ahead and tag it. // set. Otherwise, go ahead and tag it.
func (o *OptionalIterator) TagResults(out *map[string]TSVal) { func (it *OptionalIterator) TagResults(out *map[string]TSVal) {
if o.lastCheck == false { if it.lastCheck == false {
return return
} }
o.subIt.TagResults(out) it.subIt.TagResults(out)
} }
// Registers the optional iterator. // Registers the optional iterator.
func (o *OptionalIterator) Type() string { return "optional" } func (it *OptionalIterator) Type() string { return "optional" }
// Prints the optional and it's subiterator. // Prints the optional and it's subiterator.
func (o *OptionalIterator) DebugString(indent int) string { func (it *OptionalIterator) DebugString(indent int) string {
return fmt.Sprintf("%s(%s tags:%s\n%s)", return fmt.Sprintf("%s(%s tags:%s\n%s)",
strings.Repeat(" ", indent), strings.Repeat(" ", indent),
o.Type(), it.Type(),
o.Tags(), it.Tags(),
o.subIt.DebugString(indent+4)) it.subIt.DebugString(indent+4))
} }
// There's nothing to optimize for an optional. Optimize the subiterator and // There's nothing to optimize for an optional. Optimize the subiterator and
// potentially replace it. // potentially replace it.
func (o *OptionalIterator) Optimize() (Iterator, bool) { func (it *OptionalIterator) Optimize() (Iterator, bool) {
newSub, changed := o.subIt.Optimize() newSub, changed := it.subIt.Optimize()
if changed { if changed {
o.subIt.Close() it.subIt.Close()
o.subIt = newSub it.subIt = newSub
} }
return o, false return it, false
} }
// We're only as expensive as our subiterator. Except, we can't be nexted. // We're only as expensive as our subiterator. Except, we can't be nexted.
func (o *OptionalIterator) GetStats() *IteratorStats { func (it *OptionalIterator) GetStats() *IteratorStats {
subStats := o.subIt.GetStats() subStats := it.subIt.GetStats()
return &IteratorStats{ return &IteratorStats{
CheckCost: subStats.CheckCost, CheckCost: subStats.CheckCost,
NextCost: int64(1 << 62), NextCost: int64(1 << 62),

View file

@ -54,68 +54,68 @@ func NewShortCircuitOrIterator() *OrIterator {
} }
// Reset all internal iterators // Reset all internal iterators
func (or *OrIterator) Reset() { func (it *OrIterator) Reset() {
for _, it := range or.internalIterators { for _, sub := range it.internalIterators {
it.Reset() sub.Reset()
} }
or.currentIterator = -1 it.currentIterator = -1
} }
func (or *OrIterator) Clone() Iterator { func (it *OrIterator) Clone() Iterator {
var newOr *OrIterator var or *OrIterator
if or.isShortCircuiting { if it.isShortCircuiting {
newOr = NewShortCircuitOrIterator() or = NewShortCircuitOrIterator()
} else { } else {
newOr = NewOrIterator() or = NewOrIterator()
} }
for _, it := range or.internalIterators { for _, sub := range it.internalIterators {
newOr.AddSubIterator(it.Clone()) or.AddSubIterator(sub.Clone())
} }
or.CopyTagsFrom(or) it.CopyTagsFrom(it)
return newOr return or
} }
// Returns a list.List of the subiterators, in order. // Returns a list.List of the subiterators, in order.
func (or *OrIterator) GetSubIterators() *list.List { func (it *OrIterator) GetSubIterators() *list.List {
l := list.New() l := list.New()
for _, it := range or.internalIterators { for _, sub := range it.internalIterators {
l.PushBack(it) l.PushBack(sub)
} }
return l return l
} }
// Overrides BaseIterator TagResults, as it needs to add it's own results and // Overrides BaseIterator TagResults, as it needs to add it's own results and
// recurse down it's subiterators. // recurse down it's subiterators.
func (or *OrIterator) TagResults(out *map[string]TSVal) { func (it *OrIterator) TagResults(out *map[string]TSVal) {
or.BaseIterator.TagResults(out) it.BaseIterator.TagResults(out)
or.internalIterators[or.currentIterator].TagResults(out) it.internalIterators[it.currentIterator].TagResults(out)
} }
// DEPRECATED Returns the ResultTree for this iterator, recurses to it's subiterators. // DEPRECATED Returns the ResultTree for this iterator, recurses to it's subiterators.
func (or *OrIterator) GetResultTree() *ResultTree { func (it *OrIterator) GetResultTree() *ResultTree {
tree := NewResultTree(or.LastResult()) tree := NewResultTree(it.LastResult())
for _, it := range or.internalIterators { for _, sub := range it.internalIterators {
tree.AddSubtree(it.GetResultTree()) tree.AddSubtree(sub.GetResultTree())
} }
return tree return tree
} }
// Prints information about this iterator. // Prints information about this iterator.
func (or *OrIterator) DebugString(indent int) string { func (it *OrIterator) DebugString(indent int) string {
var total string var total string
for i, it := range or.internalIterators { for i, sub := range it.internalIterators {
total += strings.Repeat(" ", indent+2) total += strings.Repeat(" ", indent+2)
total += fmt.Sprintf("%d:\n%s\n", i, it.DebugString(indent+4)) total += fmt.Sprintf("%d:\n%s\n", i, sub.DebugString(indent+4))
} }
var tags string var tags string
for _, k := range or.Tags() { for _, k := range it.Tags() {
tags += fmt.Sprintf("%s;", k) tags += fmt.Sprintf("%s;", k)
} }
spaces := strings.Repeat(" ", indent+2) spaces := strings.Repeat(" ", indent+2)
return fmt.Sprintf("%s(%s\n%stags:%s\n%sits:\n%s)", return fmt.Sprintf("%s(%s\n%stags:%s\n%sits:\n%s)",
strings.Repeat(" ", indent), strings.Repeat(" ", indent),
or.Type(), it.Type(),
spaces, spaces,
tags, tags,
spaces, spaces,
@ -123,49 +123,49 @@ func (or *OrIterator) DebugString(indent int) string {
} }
// Add a subiterator to this Or iterator. Order matters. // Add a subiterator to this Or iterator. Order matters.
func (or *OrIterator) AddSubIterator(sub Iterator) { func (it *OrIterator) AddSubIterator(sub Iterator) {
or.internalIterators = append(or.internalIterators, sub) it.internalIterators = append(it.internalIterators, sub)
or.itCount++ it.itCount++
} }
// Returns the Next value from the Or iterator. Because the Or is the // Returns the Next value from the Or iterator. Because the Or is the
// union of its subiterators, it must produce from all subiterators -- unless // 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. // it's shortcircuiting, in which case, it's the first one that returns anything.
func (or *OrIterator) Next() (TSVal, bool) { func (it *OrIterator) Next() (TSVal, bool) {
NextLogIn(or) NextLogIn(it)
var curr TSVal var curr TSVal
var exists bool var exists bool
firstTime := false firstTime := false
for { for {
if or.currentIterator == -1 { if it.currentIterator == -1 {
or.currentIterator = 0 it.currentIterator = 0
firstTime = true firstTime = true
} }
curIt := or.internalIterators[or.currentIterator] curIt := it.internalIterators[it.currentIterator]
curr, exists = curIt.Next() curr, exists = curIt.Next()
if !exists { if !exists {
if or.isShortCircuiting && !firstTime { if it.isShortCircuiting && !firstTime {
return NextLogOut(or, nil, false) return NextLogOut(it, nil, false)
} }
or.currentIterator++ it.currentIterator++
if or.currentIterator == or.itCount { if it.currentIterator == it.itCount {
return NextLogOut(or, nil, false) return NextLogOut(it, nil, false)
} }
} else { } else {
or.Last = curr it.Last = curr
return NextLogOut(or, curr, true) return NextLogOut(it, curr, true)
} }
} }
panic("Somehow broke out of Next() loop in OrIterator") panic("Somehow broke out of Next() loop in OrIterator")
} }
// Checks a value against the iterators, in order. // Checks a value against the iterators, in order.
func (or *OrIterator) checkSubIts(val TSVal) bool { func (it *OrIterator) checkSubIts(val TSVal) bool {
var subIsGood = false var subIsGood = false
for i, it := range or.internalIterators { for i, sub := range it.internalIterators {
subIsGood = it.Check(val) subIsGood = sub.Check(val)
if subIsGood { if subIsGood {
or.currentIterator = i it.currentIterator = i
break break
} }
} }
@ -173,27 +173,27 @@ func (or *OrIterator) checkSubIts(val TSVal) bool {
} }
// Check a value against the entire iterator, in order. // Check a value against the entire iterator, in order.
func (or *OrIterator) Check(val TSVal) bool { func (it *OrIterator) Check(val TSVal) bool {
CheckLogIn(or, val) CheckLogIn(it, val)
anyGood := or.checkSubIts(val) anyGood := it.checkSubIts(val)
if !anyGood { if !anyGood {
return CheckLogOut(or, val, false) return CheckLogOut(it, val, false)
} }
or.Last = val it.Last = val
return CheckLogOut(or, val, true) return CheckLogOut(it, val, true)
} }
// Returns the approximate size of the Or iterator. Because we're dealing // Returns the approximate size of the Or iterator. Because we're dealing
// with a union, we know that the largest we can be is the sum of all the iterators, // with a union, we know that the largest we can be is the sum of all the iterators,
// or in the case of short-circuiting, the longest. // or in the case of short-circuiting, the longest.
func (or *OrIterator) Size() (int64, bool) { func (it *OrIterator) Size() (int64, bool) {
var val int64 var val int64
var b bool var b bool
if or.isShortCircuiting { if it.isShortCircuiting {
val = 0 val = 0
b = true b = true
for _, it := range or.internalIterators { for _, sub := range it.internalIterators {
newval, newb := it.Size() newval, newb := sub.Size()
if val < newval { if val < newval {
val = newval val = newval
} }
@ -202,8 +202,8 @@ func (or *OrIterator) Size() (int64, bool) {
} else { } else {
val = 0 val = 0
b = true b = true
for _, it := range or.internalIterators { for _, sub := range it.internalIterators {
newval, newb := it.Size() newval, newb := sub.Size()
val += newval val += newval
b = newb && b b = newb && b
} }
@ -215,34 +215,34 @@ func (or *OrIterator) Size() (int64, bool) {
// which satisfy our previous result that are not the result itself. Our // which satisfy our previous result that are not the result itself. Our
// subiterators might, however, so just pass the call recursively. In the case of // subiterators might, however, so just pass the call recursively. In the case of
// shortcircuiting, only allow new results from the currently checked iterator // shortcircuiting, only allow new results from the currently checked iterator
func (or *OrIterator) NextResult() bool { func (it *OrIterator) NextResult() bool {
if or.currentIterator != -1 { if it.currentIterator != -1 {
return or.internalIterators[or.currentIterator].NextResult() return it.internalIterators[it.currentIterator].NextResult()
} }
return false return false
} }
// Perform or-specific cleanup, of which there currently is none. // Perform or-specific cleanup, of which there currently is none.
func (or *OrIterator) cleanUp() {} func (it *OrIterator) cleanUp() {}
// Close this iterator, and, by extension, close the subiterators. // Close this iterator, and, by extension, close the subiterators.
// Close should be idempotent, and it follows that if it's subiterators // Close should be idempotent, and it follows that if it's subiterators
// follow this contract, the And follows the contract. // follow this contract, the And follows the contract.
func (or *OrIterator) Close() { func (it *OrIterator) Close() {
or.cleanUp() it.cleanUp()
for _, it := range or.internalIterators { for _, sub := range it.internalIterators {
it.Close() sub.Close()
} }
} }
func (or *OrIterator) Optimize() (Iterator, bool) { func (it *OrIterator) Optimize() (Iterator, bool) {
oldItList := or.GetSubIterators() oldItList := it.GetSubIterators()
itList := optimizeSubIterators(oldItList) itList := optimizeSubIterators(oldItList)
// Close the replaced iterators (they ought to close themselves, but Close() // Close the replaced iterators (they ought to close themselves, but Close()
// is idempotent, so this just protects against any machinations). // is idempotent, so this just protects against any machinations).
closeIteratorList(oldItList, nil) closeIteratorList(oldItList, nil)
newOr := NewOrIterator() newOr := NewOrIterator()
newOr.isShortCircuiting = or.isShortCircuiting newOr.isShortCircuiting = it.isShortCircuiting
// Add the subiterators in order. // Add the subiterators in order.
for e := itList.Front(); e != nil; e = e.Next() { for e := itList.Front(); e != nil; e = e.Next() {
@ -250,24 +250,24 @@ func (or *OrIterator) Optimize() (Iterator, bool) {
} }
// Move the tags hanging on us (like any good replacement). // Move the tags hanging on us (like any good replacement).
newOr.CopyTagsFrom(or) newOr.CopyTagsFrom(it)
// And close ourselves but not our subiterators -- some may still be alive in // And close ourselves but not our subiterators -- some may still be alive in
// the new And (they were unchanged upon calling Optimize() on them, at the // the new And (they were unchanged upon calling Optimize() on them, at the
// start). // start).
or.cleanUp() it.cleanUp()
return newOr, true return newOr, true
} }
func (or *OrIterator) GetStats() *IteratorStats { func (it *OrIterator) GetStats() *IteratorStats {
CheckCost := int64(0) CheckCost := int64(0)
NextCost := int64(0) NextCost := int64(0)
Size := int64(0) Size := int64(0)
for _, it := range or.internalIterators { for _, sub := range it.internalIterators {
stats := it.GetStats() stats := sub.GetStats()
NextCost += stats.NextCost NextCost += stats.NextCost
CheckCost += stats.CheckCost CheckCost += stats.CheckCost
if or.isShortCircuiting { if it.isShortCircuiting {
if Size < stats.Size { if Size < stats.Size {
Size = stats.Size Size = stats.Size
} }
@ -284,4 +284,4 @@ func (or *OrIterator) GetStats() *IteratorStats {
} }
// Register this as an "or" iterator. // Register this as an "or" iterator.
func (or *OrIterator) Type() string { return "or" } func (it *OrIterator) Type() string { return "or" }

View file

@ -25,16 +25,16 @@ type ResultTree struct {
} }
func NewResultTree(result TSVal) *ResultTree { func NewResultTree(result TSVal) *ResultTree {
var tree ResultTree var t ResultTree
tree.subtrees = list.New() t.subtrees = list.New()
tree.result = result t.result = result
return &tree return &t
} }
func (tree *ResultTree) ToString() string { func (t *ResultTree) ToString() string {
base := fmt.Sprintf("(%d", tree.result) base := fmt.Sprintf("(%d", t.result)
if tree.subtrees.Len() != 0 { if t.subtrees.Len() != 0 {
for e := tree.subtrees.Front(); e != nil; e = e.Next() { for e := t.subtrees.Front(); e != nil; e = e.Next() {
base += fmt.Sprintf(" %s", (e.Value.(*ResultTree)).ToString()) base += fmt.Sprintf(" %s", (e.Value.(*ResultTree)).ToString())
} }
} }
@ -42,8 +42,8 @@ func (tree *ResultTree) ToString() string {
return base return base
} }
func (tree *ResultTree) AddSubtree(sub *ResultTree) { func (t *ResultTree) AddSubtree(sub *ResultTree) {
tree.subtrees.PushBack(sub) t.subtrees.PushBack(sub)
} }
func StringResultTreeEvaluator(it Iterator) string { func StringResultTreeEvaluator(it Iterator) string {

View file

@ -68,30 +68,30 @@ func NewValueComparisonIterator(
// Here's the non-boilerplate part of the ValueComparison iterator. Given a value // Here's the non-boilerplate part of the ValueComparison iterator. Given a value
// and our operator, determine whether or not we meet the requirement. // and our operator, determine whether or not we meet the requirement.
func (vc *ValueComparisonIterator) doComparison(val TSVal) bool { func (it *ValueComparisonIterator) doComparison(val TSVal) bool {
//TODO(barakmich): Implement string comparison. //TODO(barakmich): Implement string comparison.
nodeStr := vc.ts.GetNameFor(val) nodeStr := it.ts.GetNameFor(val)
switch cVal := vc.comparisonValue.(type) { switch cVal := it.comparisonValue.(type) {
case int: case int:
cInt := int64(cVal) cInt := int64(cVal)
intVal, err := strconv.ParseInt(nodeStr, 10, 64) intVal, err := strconv.ParseInt(nodeStr, 10, 64)
if err != nil { if err != nil {
return false return false
} }
return RunIntOp(intVal, vc.op, cInt) return RunIntOp(intVal, it.op, cInt)
case int64: case int64:
intVal, err := strconv.ParseInt(nodeStr, 10, 64) intVal, err := strconv.ParseInt(nodeStr, 10, 64)
if err != nil { if err != nil {
return false return false
} }
return RunIntOp(intVal, vc.op, cVal) return RunIntOp(intVal, it.op, cVal)
default: default:
return true return true
} }
} }
func (vc *ValueComparisonIterator) Close() { func (it *ValueComparisonIterator) Close() {
vc.subIt.Close() it.subIt.Close()
} }
func RunIntOp(a int64, op ComparisonOperator, b int64) bool { func RunIntOp(a int64, op ComparisonOperator, b int64) bool {
@ -110,84 +110,84 @@ func RunIntOp(a int64, op ComparisonOperator, b int64) bool {
} }
} }
func (vc *ValueComparisonIterator) Reset() { func (it *ValueComparisonIterator) Reset() {
vc.subIt.Reset() it.subIt.Reset()
} }
func (vc *ValueComparisonIterator) Clone() Iterator { func (it *ValueComparisonIterator) Clone() Iterator {
out := NewValueComparisonIterator(vc.subIt.Clone(), vc.op, vc.comparisonValue, vc.ts) out := NewValueComparisonIterator(it.subIt.Clone(), it.op, it.comparisonValue, it.ts)
out.CopyTagsFrom(vc) out.CopyTagsFrom(it)
return out return out
} }
func (vc *ValueComparisonIterator) Next() (TSVal, bool) { func (it *ValueComparisonIterator) Next() (TSVal, bool) {
var val TSVal var val TSVal
var ok bool var ok bool
for { for {
val, ok = vc.subIt.Next() val, ok = it.subIt.Next()
if !ok { if !ok {
return nil, false return nil, false
} }
if vc.doComparison(val) { if it.doComparison(val) {
break break
} }
} }
vc.Last = val it.Last = val
return val, ok return val, ok
} }
func (vc *ValueComparisonIterator) NextResult() bool { func (it *ValueComparisonIterator) NextResult() bool {
for { for {
hasNext := vc.subIt.NextResult() hasNext := it.subIt.NextResult()
if !hasNext { if !hasNext {
return false return false
} }
if vc.doComparison(vc.subIt.LastResult()) { if it.doComparison(it.subIt.LastResult()) {
return true return true
} }
} }
vc.Last = vc.subIt.LastResult() it.Last = it.subIt.LastResult()
return true return true
} }
func (vc *ValueComparisonIterator) Check(val TSVal) bool { func (it *ValueComparisonIterator) Check(val TSVal) bool {
if !vc.doComparison(val) { if !it.doComparison(val) {
return false return false
} }
return vc.subIt.Check(val) return it.subIt.Check(val)
} }
// If we failed the check, then the subiterator should not contribute to the result // If we failed the check, then the subiterator should not contribute to the result
// set. Otherwise, go ahead and tag it. // set. Otherwise, go ahead and tag it.
func (vc *ValueComparisonIterator) TagResults(out *map[string]TSVal) { func (it *ValueComparisonIterator) TagResults(out *map[string]TSVal) {
vc.BaseIterator.TagResults(out) it.BaseIterator.TagResults(out)
vc.subIt.TagResults(out) it.subIt.TagResults(out)
} }
// Registers the value-comparison iterator. // Registers the value-comparison iterator.
func (vc *ValueComparisonIterator) Type() string { return "value-comparison" } func (it *ValueComparisonIterator) Type() string { return "value-comparison" }
// Prints the value-comparison and its subiterator. // Prints the value-comparison and its subiterator.
func (vc *ValueComparisonIterator) DebugString(indent int) string { func (it *ValueComparisonIterator) DebugString(indent int) string {
return fmt.Sprintf("%s(%s\n%s)", return fmt.Sprintf("%s(%s\n%s)",
strings.Repeat(" ", indent), strings.Repeat(" ", indent),
vc.Type(), vc.subIt.DebugString(indent+4)) it.Type(), it.subIt.DebugString(indent+4))
} }
// There's nothing to optimize, locally, for a value-comparison iterator. // There's nothing to optimize, locally, for a value-comparison iterator.
// Replace the underlying iterator if need be. // Replace the underlying iterator if need be.
// potentially replace it. // potentially replace it.
func (vc *ValueComparisonIterator) Optimize() (Iterator, bool) { func (it *ValueComparisonIterator) Optimize() (Iterator, bool) {
newSub, changed := vc.subIt.Optimize() newSub, changed := it.subIt.Optimize()
if changed { if changed {
vc.subIt.Close() it.subIt.Close()
vc.subIt = newSub it.subIt = newSub
} }
return vc, false return it, false
} }
// We're only as expensive as our subiterator. // We're only as expensive as our subiterator.
// Again, optimized value comparison iterators should do better. // Again, optimized value comparison iterators should do better.
func (vc *ValueComparisonIterator) GetStats() *IteratorStats { func (it *ValueComparisonIterator) GetStats() *IteratorStats {
return vc.subIt.GetStats() return it.subIt.GetStats()
} }