-
Notifications
You must be signed in to change notification settings - Fork 12
/
Copy patharray_iterator.go
326 lines (261 loc) · 8.22 KB
/
array_iterator.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
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
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
/*
* Atree - Scalable Arrays and Ordered Maps
*
* Copyright Flow Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package atree
import (
"fmt"
)
type ArrayIterator interface {
CanMutate() bool
Next() (Value, error)
}
// Empty array iterator
type emptyArrayIterator struct {
readOnly bool
}
var _ ArrayIterator = &emptyArrayIterator{}
var emptyMutableArrayIterator = &emptyArrayIterator{readOnly: false}
var emptyReadOnlyArrayIterator = &emptyArrayIterator{readOnly: true}
func (i *emptyArrayIterator) CanMutate() bool {
return !i.readOnly
}
func (*emptyArrayIterator) Next() (Value, error) {
return nil, nil
}
// Mutable array iterator
type mutableArrayIterator struct {
array *Array
nextIndex uint64
lastIndex uint64 // noninclusive index
}
var _ ArrayIterator = &mutableArrayIterator{}
func (i *mutableArrayIterator) CanMutate() bool {
return true
}
func (i *mutableArrayIterator) Next() (Value, error) {
if i.nextIndex == i.lastIndex {
// No more elements.
return nil, nil
}
// Don't need to set up notification callback for v because
// Get() returns value with notification already.
v, err := i.array.Get(i.nextIndex)
if err != nil {
return nil, err
}
i.nextIndex++
return v, nil
}
// Readonly array iterator
type ReadOnlyArrayIteratorMutationCallback func(mutatedValue Value)
type readOnlyArrayIterator struct {
array *Array
dataSlab *ArrayDataSlab
indexInDataSlab uint64
remainingCount uint64 // needed for range iteration
valueMutationCallback ReadOnlyArrayIteratorMutationCallback
}
// defaultReadOnlyArrayIteratorMutatinCallback is no-op.
var defaultReadOnlyArrayIteratorMutatinCallback ReadOnlyArrayIteratorMutationCallback = func(Value) {}
var _ ArrayIterator = &readOnlyArrayIterator{}
func (i *readOnlyArrayIterator) setMutationCallback(value Value) {
unwrappedChild, _ := unwrapValue(value)
if v, ok := unwrappedChild.(mutableValueNotifier); ok {
v.setParentUpdater(func() (found bool, err error) {
i.valueMutationCallback(value)
return true, NewReadOnlyIteratorElementMutationError(i.array.ValueID(), v.ValueID())
})
}
}
func (i *readOnlyArrayIterator) CanMutate() bool {
return false
}
func (i *readOnlyArrayIterator) Next() (Value, error) {
if i.remainingCount == 0 {
return nil, nil
}
if i.indexInDataSlab >= uint64(len(i.dataSlab.elements)) {
// No more elements in current data slab.
nextDataSlabID := i.dataSlab.next
if nextDataSlabID == SlabIDUndefined {
// No more elements in array.
return nil, nil
}
// Load next data slab.
slab, found, err := i.array.Storage.Retrieve(nextDataSlabID)
if err != nil {
// Wrap err as external error (if needed) because err is returned by SlabStorage interface.
return nil, wrapErrorfAsExternalErrorIfNeeded(err, fmt.Sprintf("failed to retrieve slab %s", nextDataSlabID))
}
if !found {
return nil, NewSlabNotFoundErrorf(nextDataSlabID, "slab not found during array iteration")
}
i.dataSlab = slab.(*ArrayDataSlab)
i.indexInDataSlab = 0
// Check current data slab isn't empty because i.remainingCount > 0.
if len(i.dataSlab.elements) == 0 {
return nil, NewSlabDataErrorf("data slab contains 0 elements, expect more")
}
}
// At this point:
// - There are elements to iterate in array (i.remainingCount > 0), and
// - There are elements to iterate in i.dataSlab (i.indexInDataSlab < len(i.dataSlab.elements))
element, err := i.dataSlab.elements[i.indexInDataSlab].StoredValue(i.array.Storage)
if err != nil {
// Wrap err as external error (if needed) because err is returned by Storable interface.
return nil, wrapErrorfAsExternalErrorIfNeeded(err, "failed to get storable's stored value")
}
i.indexInDataSlab++
i.remainingCount--
i.setMutationCallback(element)
return element, nil
}
// Array loaded value iterator
type arrayLoadedElementIterator struct {
storage SlabStorage
slab *ArrayDataSlab
index int
}
func (i *arrayLoadedElementIterator) next() (Value, error) {
// Iterate loaded elements in data slab.
for i.index < len(i.slab.elements) {
element := i.slab.elements[i.index]
i.index++
v, err := getLoadedValue(i.storage, element)
if err != nil {
// Don't need to wrap error as external error because err is already categorized by getLoadedValue.
return nil, err
}
if v == nil {
// Skip this element because it references unloaded slab.
// Try next element.
continue
}
return v, nil
}
// Reach end of elements
return nil, nil
}
type arrayLoadedSlabIterator struct {
storage SlabStorage
slab *ArrayMetaDataSlab
index int
}
func (i *arrayLoadedSlabIterator) next() Slab {
// Iterate loaded slabs in meta data slab.
for i.index < len(i.slab.childrenHeaders) {
header := i.slab.childrenHeaders[i.index]
i.index++
childSlab := i.storage.RetrieveIfLoaded(header.slabID)
if childSlab == nil {
// Skip this child because it references unloaded slab.
// Try next child.
continue
}
return childSlab
}
// Reach end of children.
return nil
}
// ArrayLoadedValueIterator is used to iterate over loaded array elements.
type ArrayLoadedValueIterator struct {
storage SlabStorage
parents []*arrayLoadedSlabIterator // LIFO stack for parents of dataIterator
dataIterator *arrayLoadedElementIterator
}
func (i *ArrayLoadedValueIterator) nextDataIterator() (*arrayLoadedElementIterator, error) {
// Iterate parents (LIFO) to find next loaded array data slab.
for len(i.parents) > 0 {
lastParent := i.parents[len(i.parents)-1]
nextChildSlab := lastParent.next()
switch slab := nextChildSlab.(type) {
case *ArrayDataSlab:
// Create data iterator
return &arrayLoadedElementIterator{
storage: i.storage,
slab: slab,
}, nil
case *ArrayMetaDataSlab:
// Push new parent to parents queue
newParent := &arrayLoadedSlabIterator{
storage: i.storage,
slab: slab,
}
i.parents = append(i.parents, newParent)
case nil:
// Reach end of last parent.
// Reset last parent to nil and pop last parent from parents stack.
lastParentIndex := len(i.parents) - 1
i.parents[lastParentIndex] = nil
i.parents = i.parents[:lastParentIndex]
default:
return nil, NewSlabDataErrorf("slab %s isn't ArraySlab", nextChildSlab.SlabID())
}
}
// Reach end of parents stack.
return nil, nil
}
// Next iterates and returns next loaded element.
// It returns nil Value at end of loaded elements.
func (i *ArrayLoadedValueIterator) Next() (Value, error) {
if i.dataIterator != nil {
element, err := i.dataIterator.next()
if err != nil {
// Don't need to wrap error as external error because err is already categorized by arrayLoadedElementIterator.next().
return nil, err
}
if element != nil {
return element, nil
}
// Reach end of element in current data slab.
i.dataIterator = nil
}
// Get next data iterator.
var err error
i.dataIterator, err = i.nextDataIterator()
if err != nil {
// Don't need to wrap error as external error because err is already categorized by arrayLoadedValueIterator.nextDataIterator().
return nil, err
}
if i.dataIterator != nil {
return i.Next()
}
// Reach end of loaded value iterator
return nil, nil
}
// Iterate functions
type ArrayIterationFunc func(element Value) (resume bool, err error)
func iterateArray(iterator ArrayIterator, fn ArrayIterationFunc) error {
for {
value, err := iterator.Next()
if err != nil {
// Don't need to wrap error as external error because err is already categorized by ArrayIterator.Next().
return err
}
if value == nil {
return nil
}
resume, err := fn(value)
if err != nil {
// Wrap err as external error (if needed) because err is returned by ArrayIterationFunc callback.
return wrapErrorAsExternalErrorIfNeeded(err)
}
if !resume {
return nil
}
}
}