github.com/cayleygraph/cayley@v0.7.7/graph/iterator/unique.go (about) 1 package iterator 2 3 import ( 4 "context" 5 6 "github.com/cayleygraph/cayley/graph" 7 ) 8 9 var _ graph.IteratorFuture = &Unique{} 10 11 // Unique iterator removes duplicate values from it's subiterator. 12 type Unique struct { 13 it *unique 14 graph.Iterator 15 } 16 17 func NewUnique(subIt graph.Iterator) *Unique { 18 it := &Unique{ 19 it: newUnique(graph.AsShape(subIt)), 20 } 21 it.Iterator = graph.NewLegacy(it.it, it) 22 return it 23 } 24 25 func (it *Unique) AsShape() graph.IteratorShape { 26 it.Close() 27 return it.it 28 } 29 30 var _ graph.IteratorShapeCompat = (*unique)(nil) 31 32 // Unique iterator removes duplicate values from it's subiterator. 33 type unique struct { 34 subIt graph.IteratorShape 35 } 36 37 func newUnique(subIt graph.IteratorShape) *unique { 38 return &unique{ 39 subIt: subIt, 40 } 41 } 42 43 func (it *unique) Iterate() graph.Scanner { 44 return newUniqueNext(it.subIt.Iterate()) 45 } 46 47 func (it *unique) Lookup() graph.Index { 48 return newUniqueContains(it.subIt.Lookup()) 49 } 50 51 func (it *unique) AsLegacy() graph.Iterator { 52 it2 := &Unique{it: it} 53 it2.Iterator = graph.NewLegacy(it, it2) 54 return it2 55 } 56 57 // SubIterators returns a slice of the sub iterators. The first iterator is the 58 // primary iterator, for which the complement is generated. 59 func (it *unique) SubIterators() []graph.IteratorShape { 60 return []graph.IteratorShape{it.subIt} 61 } 62 63 func (it *unique) Optimize(ctx context.Context) (graph.IteratorShape, bool) { 64 newIt, optimized := it.subIt.Optimize(ctx) 65 if optimized { 66 it.subIt = newIt 67 } 68 return it, false 69 } 70 71 const uniquenessFactor = 2 72 73 func (it *unique) Stats(ctx context.Context) (graph.IteratorCosts, error) { 74 subStats, err := it.subIt.Stats(ctx) 75 return graph.IteratorCosts{ 76 NextCost: subStats.NextCost * uniquenessFactor, 77 ContainsCost: subStats.ContainsCost, 78 Size: graph.Size{ 79 Size: subStats.Size.Size / uniquenessFactor, 80 Exact: false, 81 }, 82 }, err 83 } 84 85 func (it *unique) String() string { 86 return "Unique" 87 } 88 89 // Unique iterator removes duplicate values from it's subiterator. 90 type uniqueNext struct { 91 subIt graph.Scanner 92 result graph.Ref 93 err error 94 seen map[interface{}]bool 95 } 96 97 func newUniqueNext(subIt graph.Scanner) *uniqueNext { 98 return &uniqueNext{ 99 subIt: subIt, 100 seen: make(map[interface{}]bool), 101 } 102 } 103 104 func (it *uniqueNext) TagResults(dst map[string]graph.Ref) { 105 if it.subIt != nil { 106 it.subIt.TagResults(dst) 107 } 108 } 109 110 // Next advances the subiterator, continuing until it returns a value which it 111 // has not previously seen. 112 func (it *uniqueNext) Next(ctx context.Context) bool { 113 for it.subIt.Next(ctx) { 114 curr := it.subIt.Result() 115 key := graph.ToKey(curr) 116 if ok := it.seen[key]; !ok { 117 it.result = curr 118 it.seen[key] = true 119 return true 120 } 121 } 122 it.err = it.subIt.Err() 123 return false 124 } 125 126 func (it *uniqueNext) Err() error { 127 return it.err 128 } 129 130 func (it *uniqueNext) Result() graph.Ref { 131 return it.result 132 } 133 134 // NextPath for unique always returns false. If we were to return multiple 135 // paths, we'd no longer be a unique result, so we have to choose only the first 136 // path that got us here. Unique is serious on this point. 137 func (it *uniqueNext) NextPath(ctx context.Context) bool { 138 return false 139 } 140 141 // Close closes the primary iterators. 142 func (it *uniqueNext) Close() error { 143 it.seen = nil 144 return it.subIt.Close() 145 } 146 147 func (it *uniqueNext) String() string { 148 return "UniqueNext" 149 } 150 151 // Unique iterator removes duplicate values from it's subiterator. 152 type uniqueContains struct { 153 subIt graph.Index 154 } 155 156 func newUniqueContains(subIt graph.Index) *uniqueContains { 157 return &uniqueContains{ 158 subIt: subIt, 159 } 160 } 161 162 func (it *uniqueContains) TagResults(dst map[string]graph.Ref) { 163 if it.subIt != nil { 164 it.subIt.TagResults(dst) 165 } 166 } 167 168 func (it *uniqueContains) Err() error { 169 return it.subIt.Err() 170 } 171 172 func (it *uniqueContains) Result() graph.Ref { 173 return it.subIt.Result() 174 } 175 176 // Contains checks whether the passed value is part of the primary iterator, 177 // which is irrelevant for uniqueness. 178 func (it *uniqueContains) Contains(ctx context.Context, val graph.Ref) bool { 179 return it.subIt.Contains(ctx, val) 180 } 181 182 // NextPath for unique always returns false. If we were to return multiple 183 // paths, we'd no longer be a unique result, so we have to choose only the first 184 // path that got us here. Unique is serious on this point. 185 func (it *uniqueContains) NextPath(ctx context.Context) bool { 186 return false 187 } 188 189 // Close closes the primary iterators. 190 func (it *uniqueContains) Close() error { 191 return it.subIt.Close() 192 } 193 194 func (it *uniqueContains) String() string { 195 return "UniqueContains" 196 }