This repository was archived by the owner on Jan 30, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathiterator.go
More file actions
161 lines (152 loc) · 4.96 KB
/
iterator.go
File metadata and controls
161 lines (152 loc) · 4.96 KB
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
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
package skiptake
import (
"math"
)
// Iterator holds the state for iterating and seeking through the
// original input values.
type Iterator struct {
Decoder *Decoder
skipSum uint64 // How many integers before n were not part of the subsequeunce
take uint64 // Remaining take count in the current interval
n uint64 // Current sub-sequence value
}
// Reset resets the iterator to it's inital state at the beginning of the list.
func (t *Iterator) Reset() {
t.Decoder.Reset()
t.skipSum = 0
t.take = 0
t.n = 0
}
// EOS returns true if the stream is at end-of-stream. Because Iterator can
// iterate by either individual sequence values or intervals, EOS will not
// return true until AFTER a call of either Next() or NextSkipTake() causes EOS
// to be reached. Use of EOS should therefor occur after calls to Next() or
// NextSkipTake(). Eg:
//
// for skip, take := iter.Next(); !iter.EOS(); skip, take = iter.Next() {
// ...
// }
//
func (t Iterator) EOS() bool {
return t.n == math.MaxUint64 && t.take == math.MaxUint64
}
// NextSkipTake advances the iterator to the next skip-take interval, returning
// the skip and take values. A following call to Next() returns the expanded
// sequence value at the beginning of the interval. Returns (0, 0)
// if-and-only-if the iterator is at the end-of-sequence.
//
// NextSkipTake will coalesce any zero skip or zero take values that occur
// within the underlying list. Callers are safe to assume that while not at the
// end-of-sequence, all returned intervals will have a discontinuity (non-zero
// skip), and have a greater than zero size (non-zero take.)
//
// This means that Iterator.NextSkipTake() may not always return the same values
// as would be returned by Decoder.Next(), which can return zero skip and take
// values if they are present in the source list.
func (t *Iterator) NextSkipTake() (skip, take uint64) {
// Coalesce zero takes
for take == 0 {
if t.Decoder.EOS() {
t.n = math.MaxUint64
t.take = math.MaxUint64
return 0, 0
}
nskip, ntake := t.Decoder.Next()
skip += nskip
take = ntake
}
// Coalesce zero skips
for !t.Decoder.EOS() {
nskip := t.Decoder.PeekSkip()
if nskip != 0 {
break
}
_, ntake := t.Decoder.Next()
take += ntake
}
t.skipSum += skip
t.n += t.take + skip
t.take = take
return
}
// NextInterval fetches the next interval range in the expanded sequence. The
// values returned are inclusive, that is both first and last are members of
// the subsequence. In the case of a single-element interval, first and last
// will be equal.
//
// Values returned between two calls never abut, that is the value of first is
// always at least two more than the previous value of last.
//
// Returns (math.MaxUint64, 0) in the case of end of stream.
//
// first is always less than or equal to last, except for EOS.
func (t *Iterator) NextInterval() (first uint64, last uint64) {
if s, k := t.NextSkipTake(); s == 0 && k == 0 {
return math.MaxUint64, 0
}
return t.n, t.n + t.take - 1
}
// Next returns the next value in the subsequence. Returns math.MaxUint64 at
// end-of-sequence, althougth this is a legitimate subsequence value. Use EOS()
// to differentiate in this case.
//
// If following a call to NextSkipTake() or Seek(), returns the first
// subsequence value of the new take interval.
//
// Calling Next shrinks the current interval by one, as returned by Interval().
func (t *Iterator) Next() uint64 {
if t.take == 0 {
if s, k := t.NextSkipTake(); s == 0 && k == 0 {
return math.MaxUint64
}
}
result := t.n
t.take--
t.n++
return result
}
// Seek seeks to the i'th position in the subsequence. Returns the subsequence
// value at position i as skip, and the count of how many following sequential
// values as take. These values are identical to what would be the first
// skip-take pair of a subsequence that was truncated to start at the
// i'th position.
//
// A following call to Next() start returns the same i'th sequence value, and
// subsequent calls to Next() continue as normal within the expanded sequence.
//
// A following call to NextSkipTake() returns next skip take pair, not the skip
// take pair that was seeked to.
func (t *Iterator) Seek(pos uint64) (uint64, uint64) {
takeSum := t.n + t.take - t.skipSum
if pos < takeSum {
t.Reset()
takeSum = 0
}
for takeSum <= pos {
if t.Decoder.EOS() {
t.n = math.MaxUint64
t.take = math.MaxUint64
return 0, 0
}
_, take := t.NextSkipTake()
takeSum += take
}
t.take = takeSum - pos
t.n = t.skipSum + pos
return t.n, t.take
}
// Interval returns the contigious interval from the subsequence that
// correlates to the current skip-take pair. Returns the first and last values
// inclusive of this contigious interval.
//
// Returns (math.MaxUint64, 0) in the case of EOS or iterator that has never
// had Next() or NextSkipTake() called.
func (t *Iterator) Interval() (first uint64, last uint64) {
if t.n == 0 && t.take == 0 {
t.NextSkipTake()
}
if t.EOS() {
return math.MaxUint64, 0
}
return t.n, t.n + t.take - 1
}