github.com/cayleygraph/cayley@v0.7.7/graph/iterator/fixed.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 iterator 16 17 // Defines one of the base iterators, the Fixed iterator. A fixed iterator is quite simple; it 18 // contains an explicit fixed array of values. 19 // 20 // A fixed iterator requires an Equality function to be passed to it, by reason that graph.Ref, the 21 // opaque Quad store value, may not answer to ==. 22 23 import ( 24 "context" 25 "fmt" 26 27 "github.com/cayleygraph/cayley/graph" 28 ) 29 30 var _ graph.IteratorFuture = &Fixed{} 31 32 // A Fixed iterator consists of it's values, an index (where it is in the process of Next()ing) and 33 // an equality function. 34 type Fixed struct { 35 it *fixed 36 graph.Iterator 37 } 38 39 // Creates a new Fixed iterator with a custom comparator. 40 func NewFixed(vals ...graph.Ref) *Fixed { 41 it := &Fixed{ 42 it: newFixed(vals...), 43 } 44 it.Iterator = graph.AsLegacy(it.it) 45 return it 46 } 47 48 // Add a value to the iterator. The array now contains this value. 49 // TODO(barakmich): This ought to be a set someday, disallowing repeated values. 50 func (it *Fixed) Add(v graph.Ref) { 51 it.it.Add(v) 52 } 53 54 // Values returns a list of values stored in iterator. Slice should not be modified. 55 func (it *Fixed) Values() []graph.Ref { 56 return it.it.Values() 57 } 58 59 func (it *Fixed) AsShape() graph.IteratorShape { 60 it.Close() 61 return it.it 62 } 63 64 var _ graph.IteratorShape = &fixed{} 65 66 // A Fixed iterator consists of it's values, an index (where it is in the process of Next()ing) and 67 // an equality function. 68 type fixed struct { 69 values []graph.Ref 70 } 71 72 // Creates a new Fixed iterator with a custom comparator. 73 func newFixed(vals ...graph.Ref) *fixed { 74 return &fixed{ 75 values: append([]graph.Ref{}, vals...), 76 } 77 } 78 79 func (it *fixed) Iterate() graph.Scanner { 80 return newFixedNext(it.values) 81 } 82 83 func (it *fixed) Lookup() graph.Index { 84 return newFixedContains(it.values) 85 } 86 87 func (it *fixed) AsLegacy() graph.Iterator { 88 it2 := &Fixed{it: it} 89 it2.Iterator = graph.NewLegacy(it, it2) 90 return it2 91 } 92 93 // Add a value to the iterator. The array now contains this value. 94 // TODO(barakmich): This ought to be a set someday, disallowing repeated values. 95 func (it *fixed) Add(v graph.Ref) { 96 it.values = append(it.values, v) 97 } 98 99 // Values returns a list of values stored in iterator. Slice must not be modified. 100 func (it *fixed) Values() []graph.Ref { 101 return it.values 102 } 103 104 func (it *fixed) String() string { 105 return fmt.Sprintf("Fixed(%v)", it.values) 106 } 107 108 // No sub-iterators. 109 func (it *fixed) SubIterators() []graph.IteratorShape { 110 return nil 111 } 112 113 // Optimize() for a Fixed iterator is simple. Returns a Null iterator if it's empty 114 // (so that other iterators upstream can treat this as null) or there is no 115 // optimization. 116 func (it *fixed) Optimize(ctx context.Context) (graph.IteratorShape, bool) { 117 if len(it.values) == 1 && it.values[0] == nil { 118 return newNull(), true 119 } 120 121 return it, false 122 } 123 124 // As we right now have to scan the entire list, Next and Contains are linear with the 125 // size. However, a better data structure could remove these limits. 126 func (it *fixed) Stats(ctx context.Context) (graph.IteratorCosts, error) { 127 return graph.IteratorCosts{ 128 ContainsCost: 1, 129 NextCost: 1, 130 Size: graph.Size{ 131 Size: int64(len(it.values)), 132 Exact: true, 133 }, 134 }, nil 135 } 136 137 // A Fixed iterator consists of it's values, an index (where it is in the process of Next()ing) and 138 // an equality function. 139 type fixedNext struct { 140 values []graph.Ref 141 ind int 142 result graph.Ref 143 } 144 145 // Creates a new Fixed iterator with a custom comparator. 146 func newFixedNext(vals []graph.Ref) *fixedNext { 147 return &fixedNext{ 148 values: vals, 149 } 150 } 151 152 func (it *fixedNext) Close() error { 153 return nil 154 } 155 156 func (it *fixedNext) TagResults(dst map[string]graph.Ref) {} 157 158 func (it *fixedNext) String() string { 159 return fmt.Sprintf("Fixed(%v)", it.values) 160 } 161 162 // Next advances the iterator. 163 func (it *fixedNext) Next(ctx context.Context) bool { 164 if it.ind >= len(it.values) { 165 return false 166 } 167 out := it.values[it.ind] 168 it.result = out 169 it.ind++ 170 return true 171 } 172 173 func (it *fixedNext) Err() error { 174 return nil 175 } 176 177 func (it *fixedNext) Result() graph.Ref { 178 return it.result 179 } 180 181 func (it *fixedNext) NextPath(ctx context.Context) bool { 182 return false 183 } 184 185 // A Fixed iterator consists of it's values, an index (where it is in the process of Next()ing) and 186 // an equality function. 187 type fixedContains struct { 188 values []graph.Ref 189 keys []interface{} 190 result graph.Ref 191 } 192 193 // Creates a new Fixed iterator with a custom comparator. 194 func newFixedContains(vals []graph.Ref) *fixedContains { 195 keys := make([]interface{}, 0, len(vals)) 196 for _, v := range vals { 197 keys = append(keys, graph.ToKey(v)) 198 } 199 return &fixedContains{ 200 values: vals, 201 keys: keys, 202 } 203 } 204 205 func (it *fixedContains) Close() error { 206 return nil 207 } 208 209 func (it *fixedContains) TagResults(dst map[string]graph.Ref) {} 210 211 func (it *fixedContains) String() string { 212 return fmt.Sprintf("Fixed(%v)", it.values) 213 } 214 215 // Check if the passed value is equal to one of the values stored in the iterator. 216 func (it *fixedContains) Contains(ctx context.Context, v graph.Ref) bool { 217 // Could be optimized by keeping it sorted or using a better datastructure. 218 // However, for fixed iterators, which are by definition kind of tiny, this 219 // isn't a big issue. 220 vk := graph.ToKey(v) 221 for i, x := range it.keys { 222 if x == vk { 223 it.result = it.values[i] 224 return true 225 } 226 } 227 return false 228 } 229 230 func (it *fixedContains) Err() error { 231 return nil 232 } 233 234 func (it *fixedContains) Result() graph.Ref { 235 return it.result 236 } 237 238 func (it *fixedContains) NextPath(ctx context.Context) bool { 239 return false 240 }