/
skip.go
132 lines (110 loc) · 2.92 KB
/
skip.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
package iterator
import (
"context"
"fmt"
"github.com/cayleygraph/cayley/graph"
)
var _ graph.Iterator = &Skip{}
// Skip iterator will skip certain number of values from primary iterator.
type Skip struct {
uid uint64
skip int64
skipped int64
primaryIt graph.Iterator
}
func NewSkip(primaryIt graph.Iterator, skip int64) *Skip {
return &Skip{
uid: NextUID(),
skip: skip,
primaryIt: primaryIt,
}
}
func (it *Skip) UID() uint64 {
return it.uid
}
// Reset resets the internal iterators and the iterator itself.
func (it *Skip) Reset() {
it.skipped = 0
it.primaryIt.Reset()
}
func (it *Skip) Tagger() *graph.Tagger {
return it.primaryIt.Tagger()
}
func (it *Skip) TagResults(dst map[string]graph.Value) {
it.primaryIt.TagResults(dst)
}
func (it *Skip) Clone() graph.Iterator {
return NewSkip(it.primaryIt.Clone(), it.skip)
}
// SubIterators returns a slice of the sub iterators.
func (it *Skip) SubIterators() []graph.Iterator {
return []graph.Iterator{it.primaryIt}
}
// Next advances the Skip iterator. It will skip all initial values
// before returning actual result.
func (it *Skip) Next(ctx context.Context) bool {
graph.NextLogIn(it)
for ; it.skipped < it.skip; it.skipped++ {
if !it.primaryIt.Next(ctx) {
return graph.NextLogOut(it, false)
}
}
if it.primaryIt.Next(ctx) {
return graph.NextLogOut(it, true)
}
return graph.NextLogOut(it, false)
}
func (it *Skip) Err() error {
return it.primaryIt.Err()
}
func (it *Skip) Result() graph.Value {
return it.primaryIt.Result()
}
func (it *Skip) Contains(ctx context.Context, val graph.Value) bool {
return it.primaryIt.Contains(ctx, val) // FIXME(dennwc): will not skip anything in this case
}
// NextPath checks whether there is another path. It will skip first paths
// according to iterator parameter.
func (it *Skip) NextPath(ctx context.Context) bool {
for ; it.skipped < it.skip; it.skipped++ {
if !it.primaryIt.NextPath(ctx) {
return false
}
}
return it.primaryIt.NextPath(ctx)
}
// Close closes the primary and all iterators. It closes all subiterators
// it can, but returns the first error it encounters.
func (it *Skip) Close() error {
return it.primaryIt.Close()
}
func (it *Skip) Type() graph.Type { return graph.Skip }
func (it *Skip) Optimize() (graph.Iterator, bool) {
optimizedPrimaryIt, optimized := it.primaryIt.Optimize()
if it.skip == 0 { // nothing to skip
return optimizedPrimaryIt, true
}
it.primaryIt = optimizedPrimaryIt
return it, optimized
}
func (it *Skip) Stats() graph.IteratorStats {
primaryStats := it.primaryIt.Stats()
primaryStats.Size -= it.skip
if primaryStats.Size < 0 {
primaryStats.Size = 0
}
return primaryStats
}
func (it *Skip) Size() (int64, bool) {
primarySize, exact := it.primaryIt.Size()
if exact {
primarySize -= it.skip
if primarySize < 0 {
primarySize = 0
}
}
return primarySize, exact
}
func (it *Skip) String() string {
return fmt.Sprintf("Skip(%d)", it.skip)
}