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 }