github.com/cayleygraph/cayley@v0.7.7/graph/memstore/iterator.go (about)

     1  // Copyright 2014 The Cayley Authors. All rights reserved.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package memstore
    16  
    17  import (
    18  	"context"
    19  	"fmt"
    20  	"io"
    21  	"math"
    22  
    23  	"github.com/cayleygraph/cayley/graph"
    24  	"github.com/cayleygraph/quad"
    25  )
    26  
    27  var _ graph.Iterator = &Iterator{}
    28  
    29  type Iterator struct {
    30  	it *iterator2
    31  	graph.Iterator
    32  }
    33  
    34  func NewIterator(tree *Tree, qs *QuadStore, d quad.Direction, value int64) *Iterator {
    35  	it := &Iterator{
    36  		it: newIterator(tree, qs, d, value),
    37  	}
    38  	it.Iterator = graph.NewLegacy(it.it, it)
    39  	return it
    40  }
    41  
    42  func (it *Iterator) AsShape() graph.IteratorShape {
    43  	it.Close()
    44  	return it.it
    45  }
    46  
    47  func (it *Iterator) Sorted() bool { return true }
    48  
    49  var _ graph.IteratorShapeCompat = &iterator2{}
    50  
    51  type iterator2 struct {
    52  	qs    *QuadStore
    53  	tree  *Tree
    54  	d     quad.Direction
    55  	value int64
    56  }
    57  
    58  func newIterator(tree *Tree, qs *QuadStore, d quad.Direction, value int64) *iterator2 {
    59  	return &iterator2{
    60  		qs:    qs,
    61  		tree:  tree,
    62  		d:     d,
    63  		value: value,
    64  	}
    65  }
    66  
    67  func (it *iterator2) Iterate() graph.Scanner {
    68  	// TODO(dennwc): it doesn't check the direction and value, while Contains does; is it expected?
    69  	return newIteratorNext(it.tree, it.qs, it.d)
    70  }
    71  
    72  func (it *iterator2) Lookup() graph.Index {
    73  	return newIteratorContains(it.tree, it.qs, it.d, it.value)
    74  }
    75  
    76  func (it *iterator2) AsLegacy() graph.Iterator {
    77  	it2 := &Iterator{it: it}
    78  	it2.Iterator = graph.NewLegacy(it, it2)
    79  	return it2
    80  }
    81  
    82  func (it *iterator2) SubIterators() []graph.IteratorShape {
    83  	return nil
    84  }
    85  
    86  func (it *iterator2) String() string {
    87  	return fmt.Sprintf("MemStore(%v)", it.d)
    88  }
    89  
    90  func (it *iterator2) Sorted() bool { return true }
    91  
    92  func (it *iterator2) Optimize(ctx context.Context) (graph.IteratorShape, bool) {
    93  	return it, false
    94  }
    95  
    96  func (it *iterator2) Stats(ctx context.Context) (graph.IteratorCosts, error) {
    97  	return graph.IteratorCosts{
    98  		ContainsCost: int64(math.Log(float64(it.tree.Len()))) + 1,
    99  		NextCost:     1,
   100  		Size: graph.Size{
   101  			Size:  int64(it.tree.Len()),
   102  			Exact: true,
   103  		},
   104  	}, nil
   105  }
   106  
   107  type iteratorNext struct {
   108  	nodes bool
   109  	qs    *QuadStore
   110  	tree  *Tree
   111  	d     quad.Direction
   112  
   113  	iter *Enumerator
   114  	cur  *primitive
   115  	err  error
   116  }
   117  
   118  func newIteratorNext(tree *Tree, qs *QuadStore, d quad.Direction) *iteratorNext {
   119  	return &iteratorNext{
   120  		nodes: d == 0,
   121  		d:     d,
   122  		qs:    qs,
   123  		tree:  tree,
   124  	}
   125  }
   126  
   127  func (it *iteratorNext) TagResults(dst map[string]graph.Ref) {}
   128  
   129  func (it *iteratorNext) Close() error {
   130  	return nil
   131  }
   132  
   133  func (it *iteratorNext) Next(ctx context.Context) bool {
   134  	if it.iter == nil {
   135  		it.iter, it.err = it.tree.SeekFirst()
   136  		if it.err == io.EOF || it.iter == nil {
   137  			it.err = nil
   138  			return false
   139  		} else if it.err != nil {
   140  			return false
   141  		}
   142  	}
   143  	for {
   144  		_, p, err := it.iter.Next()
   145  		if err != nil {
   146  			if err != io.EOF {
   147  				it.err = err
   148  			}
   149  			return false
   150  		}
   151  		it.cur = p
   152  		return true
   153  	}
   154  }
   155  
   156  func (it *iteratorNext) Err() error {
   157  	return it.err
   158  }
   159  
   160  func (it *iteratorNext) Result() graph.Ref {
   161  	if it.cur == nil {
   162  		return nil
   163  	}
   164  	return qprim{p: it.cur}
   165  }
   166  
   167  func (it *iteratorNext) NextPath(ctx context.Context) bool {
   168  	return false
   169  }
   170  
   171  func (it *iteratorNext) String() string {
   172  	return fmt.Sprintf("MemStoreNext(%v)", it.d)
   173  }
   174  
   175  func (it *iteratorNext) Sorted() bool { return true }
   176  
   177  type iteratorContains struct {
   178  	nodes bool
   179  	qs    *QuadStore
   180  	tree  *Tree
   181  
   182  	cur *primitive
   183  
   184  	d     quad.Direction
   185  	value int64
   186  }
   187  
   188  func newIteratorContains(tree *Tree, qs *QuadStore, d quad.Direction, value int64) *iteratorContains {
   189  	return &iteratorContains{
   190  		nodes: d == 0,
   191  		qs:    qs,
   192  		tree:  tree,
   193  		d:     d,
   194  		value: value,
   195  	}
   196  }
   197  
   198  func (it *iteratorContains) TagResults(dst map[string]graph.Ref) {}
   199  
   200  func (it *iteratorContains) Close() error {
   201  	return nil
   202  }
   203  
   204  func (it *iteratorContains) Err() error {
   205  	return nil
   206  }
   207  
   208  func (it *iteratorContains) Result() graph.Ref {
   209  	if it.cur == nil {
   210  		return nil
   211  	}
   212  	return qprim{p: it.cur}
   213  }
   214  
   215  func (it *iteratorContains) NextPath(ctx context.Context) bool {
   216  	return false
   217  }
   218  
   219  func (it *iteratorContains) Contains(ctx context.Context, v graph.Ref) bool {
   220  	if v == nil {
   221  		return false
   222  	}
   223  	switch v := v.(type) {
   224  	case bnode:
   225  		if p, ok := it.tree.Get(int64(v)); ok {
   226  			it.cur = p
   227  			return true
   228  		}
   229  	case qprim:
   230  		if v.p.Quad.Dir(it.d) == it.value {
   231  			it.cur = v.p
   232  			return true
   233  		}
   234  	}
   235  	return false
   236  }
   237  
   238  func (it *iteratorContains) String() string {
   239  	return fmt.Sprintf("MemStoreContains(%v)", it.d)
   240  }
   241  
   242  func (it *iteratorContains) Sorted() bool { return true }