OLD | NEW |
| (Empty) |
1 // Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file | |
2 // for details. All rights reserved. Use of this source code is governed by a | |
3 // BSD-style license that can be found in the LICENSE file. | |
4 | |
5 part of dart.core; | |
6 | |
7 /** | |
8 * A collection of values, or "elements", that can be accessed sequentially. | |
9 * | |
10 * The elements of the iterable are accessed by getting an [Iterator] | |
11 * using the [iterator] getter, and using it to step through the values. | |
12 * Stepping with the iterator is done by calling [Iterator.moveNext], | |
13 * and if the call returns `true`, | |
14 * the iterator has now moved to the next element, | |
15 * which is then available as [Iterator.current]. | |
16 * If the call returns `false`, there are no more elements, | |
17 * and `iterator.currrent` returns `null`. | |
18 * | |
19 * You can create more than one iterator from the same `Iterable`. | |
20 * Each time `iterator` is read, it returns a new iterator, | |
21 * and different iterators can be stepped through independently, | |
22 * each giving access to all the elements of the iterable. | |
23 * The iterators of the same iterable *should* provide the same values | |
24 * in the same order (unless the underlying collection is modified between | |
25 * the iterations, which some collections allow). | |
26 * | |
27 * You can also iterate over the elements of an `Iterable` | |
28 * using the for-in loop construct, which uses the `iterator` getter behind the | |
29 * scenes. | |
30 * For example, you can iterate over all of the keys of a [Map], | |
31 * because `Map` keys are iterable. | |
32 * | |
33 * Map kidsBooks = {'Matilda': 'Roald Dahl', | |
34 * 'Green Eggs and Ham': 'Dr Seuss', | |
35 * 'Where the Wild Things Are': 'Maurice Sendak'}; | |
36 * for (var book in kidsBooks.keys) { | |
37 * print('$book was written by ${kidsBooks[book]}'); | |
38 * } | |
39 * | |
40 * The [List] and [Set] classes are both `Iterable`, | |
41 * as are most classes in the [dart:collection](#dart-collection) library. | |
42 * | |
43 * Some [Iterable] collections can be modified. | |
44 * Adding an element to a `List` or `Set` will change which elements it | |
45 * contains, and adding a new key to a `Map` changes the elements of [Map.keys]. | |
46 * Iterators created after the change will provide the new elements, and may | |
47 * or may not preserve the order of existing elements | |
48 * (for example, a [HashSet] may completely change its order when a single | |
49 * element is added). | |
50 * | |
51 * Changing a collection *while* it is being iterated | |
52 * is generally *not* allowed. | |
53 * Doing so will break the iteration, which is typically signalled | |
54 * by throwing a [ConcurrentModificationError] | |
55 * the next time [Iterator.moveNext] is called. | |
56 * The current value of [Iterator.current] getter | |
57 * should not be affected by the change in the collection, | |
58 * the `current` value was set by the previous call to [Iterator.moveNext]. | |
59 * | |
60 * Some iterables compute their elements dynamically every time they are | |
61 * iterated, like the one returned by [Iterable.generate] or the iterable | |
62 * returned by a `sync*` generator function. If the computation doesn't depend | |
63 * on other objects that may change, then the generated sequence should be | |
64 * the same one every time it's iterated. | |
65 * | |
66 * The members of `Iterable`, other than `iterator` itself, | |
67 * work by looking at the elements of the iterable. | |
68 * This can be implemented by running through the [iterator], but some classes | |
69 * may have more efficient ways of finding the result | |
70 * (like [last] or [length] on a [List], or [contains] on a [Set]). | |
71 * | |
72 * The methods that return another `Iterable` (like [map] and [where]) | |
73 * are all *lazy* - they will iterate the original (as necessary) | |
74 * every time the returned iterable is iterated, and not before. | |
75 * | |
76 * Since an iterable may be iterated more than once, it's not recommended to | |
77 * have detectable side-effects in the iterator. | |
78 * For methods like [map] and [while], the returned iterable will execute the | |
79 * argument function on every iteration, so those functions should also not | |
80 * have side effects. | |
81 */ | |
82 abstract class Iterable<E> { | |
83 const Iterable(); | |
84 | |
85 /** | |
86 * Creates an `Iterable` that generates its elements dynamically. | |
87 * | |
88 * An `Iterator` created by [iterator] will count from | |
89 * zero to [:count - 1:], and call [generator] | |
90 * with each index in turn to create the next value. | |
91 * | |
92 * If [generator] is omitted, it defaults to an identity function | |
93 * on integers `(int x) => x`, so it should only be omitted if the type | |
94 * parameter allows integer values. | |
95 * | |
96 * As an `Iterable`, `new Iterable.generate(n, generator))` is equivalent to | |
97 * `const [0, ..., n - 1].map(generator)`. | |
98 */ | |
99 factory Iterable.generate(int count, [E generator(int index)]) { | |
100 if (count <= 0) return new EmptyIterable<E>(); | |
101 return new _GeneratorIterable<E>(count, generator); | |
102 } | |
103 | |
104 /** | |
105 * Creates an empty iterable. | |
106 * | |
107 * The empty iterable has no elements, and iterating it always stops | |
108 * immediately. | |
109 */ | |
110 const factory Iterable.empty() = EmptyIterable<E>; | |
111 | |
112 /** | |
113 * Returns a new `Iterator` that allows iterating the elements of this | |
114 * `Iterable`. | |
115 * | |
116 * Iterable classes may specify the iteration order of their elements | |
117 * (for example [List] always iterate in index order), | |
118 * or they may leave it unspecified (for example a hash-based [Set] | |
119 * may iterate in any order). | |
120 * | |
121 * Each time `iterator` is read, it returns a new iterator, | |
122 * which can be used to iterate through all the elements again. | |
123 * The iterators of the same iterable can be stepped through independently, | |
124 * but should return the same elements in the same order, | |
125 * as long as the underlying collection isn't changed. | |
126 * | |
127 * Modifying the collection may cause new iterators to produce | |
128 * different elements, and may change the order of existing elements. | |
129 * A [List] specifies its iteration order precisely, | |
130 * so modifying the list changes the iteration order predictably. | |
131 * A hash-based [Set] may change its iteration order completely | |
132 * when adding a new element to the set. | |
133 * | |
134 * Modifying the underlying collection after creating the new iterator | |
135 * may cause an error the next time [Iterator.moveNext] is called | |
136 * on that iterator. | |
137 * Any *modifiable* iterable class should specify which operations will | |
138 * break iteration. | |
139 */ | |
140 Iterator<E> get iterator; | |
141 | |
142 /** | |
143 * Returns a new lazy [Iterable] with elements that are created by | |
144 * calling `f` on each element of this `Iterable` in iteration order. | |
145 * | |
146 * This method returns a view of the mapped elements. As long as the | |
147 * returned [Iterable] is not iterated over, the supplied function [f] will | |
148 * not be invoked. The transformed elements will not be cached. Iterating | |
149 * multiple times over the returned [Iterable] will invoke the supplied | |
150 * function [f] multiple times on the same element. | |
151 * | |
152 * Methods on the returned iterable are allowed to omit calling `f` | |
153 * on any element where the result isn't needed. | |
154 * For example, [elementAt] may call `f` only once. | |
155 */ | |
156 Iterable/*<T>*/ map/*<T>*/(/*=T*/ f(E e)) => | |
157 new MappedIterable<E, dynamic/*=T*/>(this, f); | |
158 | |
159 /** | |
160 * Returns a new lazy [Iterable] with all elements that satisfy the | |
161 * predicate [test]. | |
162 * | |
163 * The matching elements have the same order in the returned iterable | |
164 * as they have in [iterator]. | |
165 * | |
166 * This method returns a view of the mapped elements. As long as the | |
167 * returned [Iterable] is not iterated over, the supplied function [test] will | |
168 * not be invoked. Iterating will not cache results, and thus iterating | |
169 * multiple times over the returned [Iterable] will invoke the supplied | |
170 * function [test] multiple times on the same element. | |
171 */ | |
172 Iterable<E> where(bool test(E element)) => | |
173 new WhereIterable<E>(this, test); | |
174 | |
175 /** | |
176 * Expands each element of this [Iterable] into zero or more elements. | |
177 * | |
178 * The resulting Iterable runs through the elements returned | |
179 * by [f] for each element of this, in iteration order. | |
180 * | |
181 * The returned [Iterable] is lazy, and calls [f] for each element | |
182 * of this every time it's iterated. | |
183 */ | |
184 Iterable/*<T>*/ expand/*<T>*/(Iterable/*<T>*/ f(E element)) => | |
185 new ExpandIterable<E, dynamic/*=T*/>(this, f); | |
186 | |
187 /** | |
188 * Returns true if the collection contains an element equal to [element]. | |
189 * | |
190 * This operation will check each element in order for being equal to | |
191 * [element], unless it has a more efficient way to find an element | |
192 * equal to [element]. | |
193 * | |
194 * The equality used to determine whether [element] is equal to an element of | |
195 * the iterable defaults to the [Object.operator==] of the element. | |
196 * | |
197 * Some types of iterable may have a different equality used for its elements. | |
198 * For example, a [Set] may have a custom equality | |
199 * (see [Set.identical]) that its `contains` uses. | |
200 * Likewise the `Iterable` returned by a [Map.keys] call | |
201 * should use the same equality that the `Map` uses for keys. | |
202 */ | |
203 bool contains(Object element) { | |
204 for (E e in this) { | |
205 if (e == element) return true; | |
206 } | |
207 return false; | |
208 } | |
209 | |
210 | |
211 /** | |
212 * Applies the function [f] to each element of this collection in iteration | |
213 * order. | |
214 */ | |
215 void forEach(void f(E element)) { | |
216 for (E element in this) f(element); | |
217 } | |
218 | |
219 /** | |
220 * Reduces a collection to a single value by iteratively combining elements | |
221 * of the collection using the provided function. | |
222 * | |
223 * The iterable must have at least one element. | |
224 * If it has only one element, that element is returned. | |
225 * | |
226 * Otherwise this method starts with the first element from the iterator, | |
227 * and then combines it with the remaining elements in iteration order, | |
228 * as if by: | |
229 * | |
230 * E value = iterable.first; | |
231 * iterable.skip(1).forEach((element) { | |
232 * value = combine(value, element); | |
233 * }); | |
234 * return value; | |
235 * | |
236 * Example of calculating the sum of an iterable: | |
237 * | |
238 * iterable.reduce((value, element) => value + element); | |
239 * | |
240 */ | |
241 E reduce(E combine(E value, E element)) { | |
242 Iterator<E> iterator = this.iterator; | |
243 if (!iterator.moveNext()) { | |
244 throw IterableElementError.noElement(); | |
245 } | |
246 E value = iterator.current; | |
247 while (iterator.moveNext()) { | |
248 value = combine(value, iterator.current); | |
249 } | |
250 return value; | |
251 } | |
252 | |
253 /** | |
254 * Reduces a collection to a single value by iteratively combining each | |
255 * element of the collection with an existing value | |
256 * | |
257 * Uses [initialValue] as the initial value, | |
258 * then iterates through the elements and updates the value with | |
259 * each element using the [combine] function, as if by: | |
260 * | |
261 * var value = initialValue; | |
262 * for (E element in this) { | |
263 * value = combine(value, element); | |
264 * } | |
265 * return value; | |
266 * | |
267 * Example of calculating the sum of an iterable: | |
268 * | |
269 * iterable.fold(0, (prev, element) => prev + element); | |
270 * | |
271 */ | |
272 dynamic/*=T*/ fold/*<T>*/(var/*=T*/ initialValue, | |
273 dynamic/*=T*/ combine(var/*=T*/ previousValue, E element)) { | |
274 var value = initialValue; | |
275 for (E element in this) value = combine(value, element); | |
276 return value; | |
277 } | |
278 | |
279 /** | |
280 * Checks whether every element of this iterable satisfies [test]. | |
281 * | |
282 * Checks every element in iteration order, and returns `false` if | |
283 * any of them make [test] return `false`, otherwise returns `true`. | |
284 */ | |
285 bool every(bool f(E element)) { | |
286 for (E element in this) { | |
287 if (!f(element)) return false; | |
288 } | |
289 return true; | |
290 } | |
291 | |
292 /** | |
293 * Converts each element to a [String] and concatenates the strings. | |
294 * | |
295 * Iterates through elements of this iterable, | |
296 * converts each one to a [String] by calling [Object.toString], | |
297 * and then concatenates the strings, with the | |
298 * [separator] string interleaved between the elements. | |
299 */ | |
300 String join([String separator = ""]) { | |
301 Iterator<E> iterator = this.iterator; | |
302 if (!iterator.moveNext()) return ""; | |
303 StringBuffer buffer = new StringBuffer(); | |
304 if (separator == null || separator == "") { | |
305 do { | |
306 buffer.write("${iterator.current}"); | |
307 } while (iterator.moveNext()); | |
308 } else { | |
309 buffer.write("${iterator.current}"); | |
310 while (iterator.moveNext()) { | |
311 buffer.write(separator); | |
312 buffer.write("${iterator.current}"); | |
313 } | |
314 } | |
315 return buffer.toString(); | |
316 } | |
317 | |
318 | |
319 /** | |
320 * Checks whether any element of this iterable satisfies [test]. | |
321 * | |
322 * Checks every element in iteration order, and returns `true` if | |
323 * any of them make [test] return `true`, otherwise returns false. | |
324 */ | |
325 bool any(bool f(E element)) { | |
326 for (E element in this) { | |
327 if (f(element)) return true; | |
328 } | |
329 return false; | |
330 } | |
331 | |
332 /** | |
333 * Creates a [List] containing the elements of this [Iterable]. | |
334 * | |
335 * The elements are in iteration order. | |
336 * The list is fixed-length if [growable] is false. | |
337 */ | |
338 List<E> toList({ bool growable: true }) => | |
339 new List<E>.from(this, growable: growable); | |
340 | |
341 /** | |
342 * Creates a [Set] containing the same elements as this iterable. | |
343 * | |
344 * The set may contain fewer elements than the iterable, | |
345 * if the iterable contains an element more than once, | |
346 * or it contains one or more elements that are equal. | |
347 * The order of the elements in the set is not guaranteed to be the same | |
348 * as for the iterable. | |
349 */ | |
350 Set<E> toSet() => new Set<E>.from(this); | |
351 | |
352 /** | |
353 * Returns the number of elements in [this]. | |
354 * | |
355 * Counting all elements may involve iterating through all elements and can | |
356 * therefore be slow. | |
357 * Some iterables have a more efficient way to find the number of elements. | |
358 */ | |
359 int get length { | |
360 assert(this is! EfficientLength); | |
361 int count = 0; | |
362 Iterator it = iterator; | |
363 while (it.moveNext()) { | |
364 count++; | |
365 } | |
366 return count; | |
367 } | |
368 | |
369 /** | |
370 * Returns `true` if there are no elements in this collection. | |
371 * | |
372 * May be computed by checking if `iterator.moveNext()` returns `false`. | |
373 */ | |
374 bool get isEmpty => !iterator.moveNext(); | |
375 | |
376 /** | |
377 * Returns true if there is at least one element in this collection. | |
378 * | |
379 * May be computed by checking if `iterator.moveNext()` returns `true`. | |
380 */ | |
381 bool get isNotEmpty => !isEmpty; | |
382 | |
383 /** | |
384 * Returns a lazy iterable of the [count] first elements of this iterable. | |
385 * | |
386 * The returned `Iterable` may contain fewer than `count` elements, if `this` | |
387 * contains fewer than `count` elements. | |
388 * | |
389 * The elements can be computed by stepping through [iterator] until [count] | |
390 * elements have been seen. | |
391 * | |
392 * The `count` must not be negative. | |
393 */ | |
394 Iterable<E> take(int count) { | |
395 return new TakeIterable<E>(this, count); | |
396 } | |
397 | |
398 /** | |
399 * Returns a lazy iterable of the leading elements satisfying [test]. | |
400 * | |
401 * The filtering happens lazily. Every new iterator of the returned | |
402 * iterable starts iterating over the elements of `this`. | |
403 * | |
404 * The elements can be computed by stepping through [iterator] until an | |
405 * element is found where `test(element)` is false. At that point, | |
406 * the returned iterable stops (its `moveNext()` returns false). | |
407 */ | |
408 Iterable<E> takeWhile(bool test(E value)) { | |
409 return new TakeWhileIterable<E>(this, test); | |
410 } | |
411 | |
412 /** | |
413 * Returns an Iterable that provides all but the first [count] elements. | |
414 * | |
415 * When the returned iterable is iterated, it starts iterating over `this`, | |
416 * first skipping past the initial [count] elements. | |
417 * If `this` has fewer than `count` elements, then the resulting Iterable is | |
418 * empty. | |
419 * After that, the remaining elements are iterated in the same order as | |
420 * in this iterable. | |
421 * | |
422 * The `count` must not be negative. | |
423 */ | |
424 Iterable<E> skip(int count) { | |
425 return new SkipIterable<E>(this, count); | |
426 } | |
427 | |
428 /** | |
429 * Returns an Iterable that skips leading elements while [test] is satisfied. | |
430 * | |
431 * The filtering happens lazily. Every new Iterator of the returned | |
432 * Iterable iterates over all elements of `this`. | |
433 * | |
434 * The returned iterable provides elements by iterating this iterable, | |
435 * but skipping over all initial elements where `test(element)` returns | |
436 * true. If all elements satisfy `test` the resulting iterable is empty, | |
437 * otherwise it iterates the remaining elements in their original order, | |
438 * starting with the first element for which `test(element)` returns false. | |
439 */ | |
440 Iterable<E> skipWhile(bool test(E value)) { | |
441 return new SkipWhileIterable<E>(this, test); | |
442 } | |
443 | |
444 /** | |
445 * Returns the first element. | |
446 * | |
447 * Throws a [StateError] if `this` is empty. | |
448 * Otherwise returns the first element in the iteration order, | |
449 * equivalent to `this.elementAt(0)`. | |
450 */ | |
451 E get first { | |
452 Iterator<E> it = iterator; | |
453 if (!it.moveNext()) { | |
454 throw IterableElementError.noElement(); | |
455 } | |
456 return it.current; | |
457 } | |
458 | |
459 /** | |
460 * Returns the last element. | |
461 * | |
462 * Throws a [StateError] if `this` is empty. | |
463 * Otherwise may iterate through the elements and returns the last one | |
464 * seen. | |
465 * Some iterables may have more efficient ways to find the last element | |
466 * (for example a list can directly access the last element, | |
467 * without iterating through the previous ones). | |
468 */ | |
469 E get last { | |
470 Iterator<E> it = iterator; | |
471 if (!it.moveNext()) { | |
472 throw IterableElementError.noElement(); | |
473 } | |
474 E result; | |
475 do { | |
476 result = it.current; | |
477 } while(it.moveNext()); | |
478 return result; | |
479 } | |
480 | |
481 /** | |
482 * Checks that this iterable has only one element, and returns that element. | |
483 * | |
484 * Throws a [StateError] if `this` is empty or has more than one element. | |
485 */ | |
486 E get single { | |
487 Iterator<E> it = iterator; | |
488 if (!it.moveNext()) throw IterableElementError.noElement(); | |
489 E result = it.current; | |
490 if (it.moveNext()) throw IterableElementError.tooMany(); | |
491 return result; | |
492 } | |
493 | |
494 /** | |
495 * Returns the first element that satisfies the given predicate [test]. | |
496 * | |
497 * Iterates through elements and returns the first to satsify [test]. | |
498 * | |
499 * If no element satisfies [test], the result of invoking the [orElse] | |
500 * function is returned. | |
501 * If [orElse] is omitted, it defaults to throwing a [StateError]. | |
502 */ | |
503 E firstWhere(bool test(E element), { E orElse() }) { | |
504 for (E element in this) { | |
505 if (test(element)) return element; | |
506 } | |
507 if (orElse != null) return orElse(); | |
508 throw IterableElementError.noElement(); | |
509 } | |
510 | |
511 /** | |
512 * Returns the last element that satisfies the given predicate [test]. | |
513 * | |
514 * An iterable that can access its elements directly may check its | |
515 * elements in any order (for example a list starts by checking the | |
516 * last element and then moves towards the start of the list). | |
517 * The default implementation iterates elements in iteration order, | |
518 * checks `test(element)` for each, | |
519 * and finally returns that last one that matched. | |
520 * | |
521 * If no element satsfies [test], the result of invoking the [orElse] | |
522 * function is returned. | |
523 * If [orElse] is omitted, it defaults to throwing a [StateError]. | |
524 */ | |
525 E lastWhere(bool test(E element), {E orElse()}) { | |
526 E result = null; | |
527 bool foundMatching = false; | |
528 for (E element in this) { | |
529 if (test(element)) { | |
530 result = element; | |
531 foundMatching = true; | |
532 } | |
533 } | |
534 if (foundMatching) return result; | |
535 if (orElse != null) return orElse(); | |
536 throw IterableElementError.noElement(); | |
537 } | |
538 | |
539 /** | |
540 * Returns the single element that satisfies [test]. | |
541 * | |
542 * Checks all elements to see if `test(element)` returns true. | |
543 * If exactly one element satisfies [test], that element is returned. | |
544 * Otherwise, if there are no matching elements, or if there is more than | |
545 * one matching element, a [StateError] is thrown. | |
546 */ | |
547 E singleWhere(bool test(E element)) { | |
548 E result = null; | |
549 bool foundMatching = false; | |
550 for (E element in this) { | |
551 if (test(element)) { | |
552 if (foundMatching) { | |
553 throw IterableElementError.tooMany(); | |
554 } | |
555 result = element; | |
556 foundMatching = true; | |
557 } | |
558 } | |
559 if (foundMatching) return result; | |
560 throw IterableElementError.noElement(); | |
561 } | |
562 | |
563 /** | |
564 * Returns the [index]th element. | |
565 * | |
566 * The [index] must be non-negative and less than [length]. | |
567 * Index zero represents the first element (so `iterable.elementAt(0)` is | |
568 * equivalent to `iterable.first`). | |
569 * | |
570 * May iterate through the elements in iteration order, skipping the | |
571 * first `index` elements and returning the next. | |
572 * Some iterable may have more efficient ways to find the element. | |
573 */ | |
574 E elementAt(int index) { | |
575 if (index is! int) throw new ArgumentError.notNull("index"); | |
576 RangeError.checkNotNegative(index, "index"); | |
577 int elementIndex = 0; | |
578 for (E element in this) { | |
579 if (index == elementIndex) return element; | |
580 elementIndex++; | |
581 } | |
582 throw new RangeError.index(index, this, "index", null, elementIndex); | |
583 } | |
584 | |
585 /** | |
586 * Returns a string representation of (some of) the elements of `this`. | |
587 * | |
588 * Elements are represented by their own `toString` results. | |
589 * | |
590 * The default representation always contains the first three elements. | |
591 * If there are less than a hundred elements in the iterable, it also | |
592 * contains the last two elements. | |
593 * | |
594 * If the resulting string isn't above 80 characters, more elements are | |
595 * included from the start of the iterable. | |
596 * | |
597 * The conversion may omit calling `toString` on some elements if they | |
598 * are known to not occur in the output, and it may stop iterating after | |
599 * a hundred elements. | |
600 */ | |
601 String toString() => IterableBase.iterableToShortString(this, '(', ')'); | |
602 } | |
603 | |
604 typedef E _Generator<E>(int index); | |
605 | |
606 class _GeneratorIterable<E> extends Iterable<E> | |
607 implements EfficientLength { | |
608 final int _start; | |
609 final int _end; | |
610 final _Generator<E> _generator; | |
611 | |
612 /// Creates an iterable that builds the elements from a generator function. | |
613 /// | |
614 /// The [generator] may be null, in which case the default generator | |
615 /// enumerating the integer positions is used. This means that [int] must | |
616 /// be assignable to [E] when no generator is provided. In practice this means | |
617 /// that the generator can only be emitted when [E] is equal to `dynamic`, | |
618 /// `int`, or `num`. The constructor will check that the types match. | |
619 _GeneratorIterable(this._end, E generator(int n)) | |
620 : _start = 0, | |
621 // The `as` below is used as check to make sure that `int` is assignable | |
622 // to [E]. | |
623 _generator = (generator != null) ? generator : _id as _Generator<E>; | |
624 | |
625 _GeneratorIterable.slice(this._start, this._end, this._generator); | |
626 | |
627 Iterator<E> get iterator => | |
628 new _GeneratorIterator<E>(_start, _end, _generator); | |
629 int get length => _end - _start; | |
630 | |
631 Iterable<E> skip(int count) { | |
632 RangeError.checkNotNegative(count, "count"); | |
633 if (count == 0) return this; | |
634 int newStart = _start + count; | |
635 if (newStart >= _end) return new EmptyIterable<E>(); | |
636 return new _GeneratorIterable<E>.slice(newStart, _end, _generator); | |
637 } | |
638 | |
639 Iterable<E> take(int count) { | |
640 RangeError.checkNotNegative(count, "count"); | |
641 if (count == 0) return new EmptyIterable<E>(); | |
642 int newEnd = _start + count; | |
643 if (newEnd >= _end) return this; | |
644 return new _GeneratorIterable<E>.slice(_start, newEnd, _generator); | |
645 } | |
646 | |
647 static int _id(int n) => n; | |
648 } | |
649 | |
650 class _GeneratorIterator<E> implements Iterator<E> { | |
651 final int _end; | |
652 final _Generator<E> _generator; | |
653 int _index; | |
654 E _current; | |
655 | |
656 _GeneratorIterator(this._index, this._end, this._generator); | |
657 | |
658 bool moveNext() { | |
659 if (_index < _end) { | |
660 _current = _generator(_index); | |
661 _index++; | |
662 return true; | |
663 } else { | |
664 _current = null; | |
665 return false; | |
666 } | |
667 } | |
668 | |
669 E get current => _current; | |
670 } | |
671 | |
672 /** | |
673 * An Iterator that allows moving backwards as well as forwards. | |
674 */ | |
675 abstract class BidirectionalIterator<E> implements Iterator<E> { | |
676 /** | |
677 * Move back to the previous element. | |
678 * | |
679 * Returns true and updates [current] if successful. Returns false | |
680 * and sets [current] to null if there is no previous element. | |
681 */ | |
682 bool movePrevious(); | |
683 } | |
OLD | NEW |