OLD | NEW |
---|---|
1 // Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file | 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 | 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. | 3 // BSD-style license that can be found in the LICENSE file. |
4 | 4 |
5 part of dart.core; | 5 part of dart.core; |
6 | 6 |
7 /** | 7 /** |
8 * A collection of values, or "elements", that can be accessed sequentially. | 8 * A collection of values, or "elements", that can be accessed sequentially. |
9 * | 9 * |
10 * The elements of the iterable are accessed by getting an [Iterator] | 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. | 11 * using the [iterator] getter, and using it to step through the values. |
12 * Stepping with the iterator is done by calling [Iterator.moveNext], | 12 * Stepping with the iterator is done by calling [Iterator.moveNext], |
13 * and if the call returns `true`, | 13 * and if the call returns `true`, |
14 * the iterator has now moved to the next element, | 14 * the iterator has now moved to the next element, |
15 * which is then available as [Iterator.current]. | 15 * which is then available as [Iterator.current]. |
16 * If the call returns `false`, there are no more elements, | 16 * If the call returns `false`, there are no more elements, |
17 * and `iterator.currrent` returns `null`. | 17 * and `iterator.current` returns `null`. |
18 * | 18 * |
19 * You can create more than one iterator from the same `Iterable`. | 19 * You can create more than one iterator from the same `Iterable`. |
20 * Each time `iterator` is read, it returns a new iterator, | 20 * Each time `iterator` is read, it returns a new iterator, |
21 * and different iterators can be stepped through independently, | 21 * and different iterators can be stepped through independently, |
22 * each giving access to all the elements of the iterable. | 22 * each giving access to all the elements of the iterable. |
23 * The iterators of the same iterable *should* provide the same values | 23 * The iterators of the same iterable *should* provide the same values |
24 * in the same order (unless the underlying collection is modified between | 24 * in the same order (unless the underlying collection is modified between |
25 * the iterations, which some collections allow). | 25 * the iterations, which some collections allow). |
26 * | 26 * |
27 * You can also iterate over the elements of an `Iterable` | 27 * You can also iterate over the elements of an `Iterable` |
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
76 * Since an iterable may be iterated more than once, it's not recommended to | 76 * Since an iterable may be iterated more than once, it's not recommended to |
77 * have detectable side-effects in the iterator. | 77 * have detectable side-effects in the iterator. |
78 * For methods like [map] and [while], the returned iterable will execute the | 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 | 79 * argument function on every iteration, so those functions should also not |
80 * have side effects. | 80 * have side effects. |
81 */ | 81 */ |
82 abstract class Iterable<E> { | 82 abstract class Iterable<E> { |
83 const Iterable(); | 83 const Iterable(); |
84 | 84 |
85 /** | 85 /** |
86 * Creates an `Iterable` that generates its elements dynamically. | 86 * Creates an `Iterable` which generates its elements dynamically. |
87 * | 87 * |
88 * An `Iterator` created by [iterator] will count from | 88 * The generated iterable has [count] elements, |
89 * zero to [:count - 1:], and call [generator] | 89 * and the element at index `n` is computed by calling `generator(n)`. |
90 * with each index in turn to create the next value. | 90 * Values are not cached, so each iteration computes the values again. |
91 * | 91 * |
92 * If [generator] is omitted, it defaults to an identity function | 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 | 93 * on integers `(int x) => x`, so it may only be omitted if the type |
94 * parameter allows integer values. | 94 * parameter allows integer values. That is, if [E] is one of |
95 * `int`, `num`, `Object` or `dynamic`. | |
95 * | 96 * |
96 * As an `Iterable`, `new Iterable.generate(n, generator))` is equivalent to | 97 * As an `Iterable`, `new Iterable.generate(n, generator))` is equivalent to |
97 * `const [0, ..., n - 1].map(generator)`. | 98 * `const [0, ..., n - 1].map(generator)`. |
98 */ | 99 */ |
99 factory Iterable.generate(int count, [E generator(int index)]) { | 100 factory Iterable.generate(int count, [E generator(int index)]) { |
100 if (count <= 0) return new EmptyIterable<E>(); | 101 if (count <= 0) return new EmptyIterable<E>(); |
101 return new _GeneratorIterable<E>(count, generator); | 102 return new _GeneratorIterable<E>(count, generator); |
102 } | 103 } |
103 | 104 |
104 /** | 105 /** |
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
156 Iterable/*<T>*/ map/*<T>*/(/*=T*/ f(E e)) => | 157 Iterable/*<T>*/ map/*<T>*/(/*=T*/ f(E e)) => |
157 new MappedIterable<E, dynamic/*=T*/>(this, f); | 158 new MappedIterable<E, dynamic/*=T*/>(this, f); |
158 | 159 |
159 /** | 160 /** |
160 * Returns a new lazy [Iterable] with all elements that satisfy the | 161 * Returns a new lazy [Iterable] with all elements that satisfy the |
161 * predicate [test]. | 162 * predicate [test]. |
162 * | 163 * |
163 * The matching elements have the same order in the returned iterable | 164 * The matching elements have the same order in the returned iterable |
164 * as they have in [iterator]. | 165 * as they have in [iterator]. |
165 * | 166 * |
166 * This method returns a view of the mapped elements. As long as the | 167 * This method returns a view of the mapped elements. |
167 * returned [Iterable] is not iterated over, the supplied function [test] will | 168 * As long as the returned [Iterable] is not iterated over, |
168 * not be invoked. Iterating will not cache results, and thus iterating | 169 * the supplied function [test] will not be invoked. |
169 * multiple times over the returned [Iterable] will invoke the supplied | 170 * Iterating will not cache results, and thus iterating multiple times over |
171 * the returned [Iterable] may invoke the supplied | |
170 * function [test] multiple times on the same element. | 172 * function [test] multiple times on the same element. |
171 */ | 173 */ |
172 Iterable<E> where(bool test(E element)) => | 174 Iterable<E> where(bool test(E element)) => new WhereIterable<E>(this, test); |
173 new WhereIterable<E>(this, test); | |
174 | 175 |
175 /** | 176 /** |
176 * Expands each element of this [Iterable] into zero or more elements. | 177 * Expands each element of this [Iterable] into zero or more elements. |
177 * | 178 * |
178 * The resulting Iterable runs through the elements returned | 179 * The resulting Iterable runs through the elements returned |
179 * by [f] for each element of this, in iteration order. | 180 * by [f] for each element of this, in iteration order. |
180 * | 181 * |
181 * The returned [Iterable] is lazy, and calls [f] for each element | 182 * The returned [Iterable] is lazy, and calls [f] for each element |
182 * of this every time it's iterated. | 183 * of this every time it's iterated. |
183 */ | 184 */ |
(...skipping 219 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
403 * | 404 * |
404 * The elements can be computed by stepping through [iterator] until an | 405 * The elements can be computed by stepping through [iterator] until an |
405 * element is found where `test(element)` is false. At that point, | 406 * element is found where `test(element)` is false. At that point, |
406 * the returned iterable stops (its `moveNext()` returns false). | 407 * the returned iterable stops (its `moveNext()` returns false). |
407 */ | 408 */ |
408 Iterable<E> takeWhile(bool test(E value)) { | 409 Iterable<E> takeWhile(bool test(E value)) { |
409 return new TakeWhileIterable<E>(this, test); | 410 return new TakeWhileIterable<E>(this, test); |
410 } | 411 } |
411 | 412 |
412 /** | 413 /** |
413 * Returns an Iterable that provides all but the first [count] elements. | 414 * Returns an `Iterable` that provides all but the first [count] elements. |
414 * | 415 * |
415 * When the returned iterable is iterated, it starts iterating over `this`, | 416 * When the returned iterable is iterated, it starts iterating over `this`, |
416 * first skipping past the initial [count] elements. | 417 * first skipping past the initial [count] elements. |
417 * If `this` has fewer than `count` elements, then the resulting Iterable is | 418 * If `this` has fewer than `count` elements, then the resulting Iterable is |
418 * empty. | 419 * empty. |
419 * After that, the remaining elements are iterated in the same order as | 420 * After that, the remaining elements are iterated in the same order as |
420 * in this iterable. | 421 * in this iterable. |
421 * | 422 * |
423 * Some iterables may provide ways to skip initial elements without actively | |
424 * iterating through them (for example when iterating a [List]). | |
425 * Such iterables are allowed to completely ignore the inital skipped elements | |
floitsch
2016/05/18 09:44:27
ignore the initial skipped elements.
(I would dro
Lasse Reichstein Nielsen
2016/05/18 09:54:15
Reworded entire paragraph, PTAL.
| |
426 * and not, for example, compute their value. | |
427 * | |
422 * The `count` must not be negative. | 428 * The `count` must not be negative. |
423 */ | 429 */ |
424 Iterable<E> skip(int count) { | 430 Iterable<E> skip(int count) { |
425 return new SkipIterable<E>(this, count); | 431 return new SkipIterable<E>(this, count); |
426 } | 432 } |
427 | 433 |
428 /** | 434 /** |
429 * Returns an Iterable that skips leading elements while [test] is satisfied. | 435 * Returns an `Iterable` that skips leading elements while [test] is satisfied . |
430 * | 436 * |
431 * The filtering happens lazily. Every new Iterator of the returned | 437 * The filtering happens lazily. Every new [Iterator] of the returned |
432 * Iterable iterates over all elements of `this`. | 438 * iterable iterates over all elements of `this`. |
433 * | 439 * |
434 * The returned iterable provides elements by iterating this iterable, | 440 * The returned iterable provides elements by iterating this iterable, |
435 * but skipping over all initial elements where `test(element)` returns | 441 * but skipping over all initial elements where `test(element)` returns |
436 * true. If all elements satisfy `test` the resulting iterable is empty, | 442 * true. If all elements satisfy `test` the resulting iterable is empty, |
437 * otherwise it iterates the remaining elements in their original order, | 443 * otherwise it iterates the remaining elements in their original order, |
438 * starting with the first element for which `test(element)` returns false. | 444 * starting with the first element for which `test(element)` returns `false`. |
439 */ | 445 */ |
440 Iterable<E> skipWhile(bool test(E value)) { | 446 Iterable<E> skipWhile(bool test(E value)) { |
441 return new SkipWhileIterable<E>(this, test); | 447 return new SkipWhileIterable<E>(this, test); |
442 } | 448 } |
443 | 449 |
444 /** | 450 /** |
445 * Returns the first element. | 451 * Returns the first element. |
446 * | 452 * |
447 * Throws a [StateError] if `this` is empty. | 453 * Throws a [StateError] if `this` is empty. |
448 * Otherwise returns the first element in the iteration order, | 454 * Otherwise returns the first element in the iteration order, |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
487 Iterator<E> it = iterator; | 493 Iterator<E> it = iterator; |
488 if (!it.moveNext()) throw IterableElementError.noElement(); | 494 if (!it.moveNext()) throw IterableElementError.noElement(); |
489 E result = it.current; | 495 E result = it.current; |
490 if (it.moveNext()) throw IterableElementError.tooMany(); | 496 if (it.moveNext()) throw IterableElementError.tooMany(); |
491 return result; | 497 return result; |
492 } | 498 } |
493 | 499 |
494 /** | 500 /** |
495 * Returns the first element that satisfies the given predicate [test]. | 501 * Returns the first element that satisfies the given predicate [test]. |
496 * | 502 * |
497 * Iterates through elements and returns the first to satsify [test]. | 503 * Iterates through elements and returns the first to satisfy [test]. |
498 * | 504 * |
499 * If no element satisfies [test], the result of invoking the [orElse] | 505 * If no element satisfies [test], the result of invoking the [orElse] |
500 * function is returned. | 506 * function is returned. |
501 * If [orElse] is omitted, it defaults to throwing a [StateError]. | 507 * If [orElse] is omitted, it defaults to throwing a [StateError]. |
502 */ | 508 */ |
503 E firstWhere(bool test(E element), { E orElse() }) { | 509 E firstWhere(bool test(E element), { E orElse() }) { |
504 for (E element in this) { | 510 for (E element in this) { |
505 if (test(element)) return element; | 511 if (test(element)) return element; |
506 } | 512 } |
507 if (orElse != null) return orElse(); | 513 if (orElse != null) return orElse(); |
508 throw IterableElementError.noElement(); | 514 throw IterableElementError.noElement(); |
509 } | 515 } |
510 | 516 |
511 /** | 517 /** |
512 * Returns the last element that satisfies the given predicate [test]. | 518 * Returns the last element that satisfies the given predicate [test]. |
513 * | 519 * |
514 * An iterable that can access its elements directly may check its | 520 * An iterable that can access its elements directly may check its |
515 * elements in any order (for example a list starts by checking the | 521 * elements in any order (for example a list starts by checking the |
516 * last element and then moves towards the start of the list). | 522 * last element and then moves towards the start of the list). |
517 * The default implementation iterates elements in iteration order, | 523 * The default implementation iterates elements in iteration order, |
518 * checks `test(element)` for each, | 524 * checks `test(element)` for each, |
519 * and finally returns that last one that matched. | 525 * and finally returns that last one that matched. |
520 * | 526 * |
521 * If no element satsfies [test], the result of invoking the [orElse] | 527 * If no element satisfies [test], the result of invoking the [orElse] |
522 * function is returned. | 528 * function is returned. |
523 * If [orElse] is omitted, it defaults to throwing a [StateError]. | 529 * If [orElse] is omitted, it defaults to throwing a [StateError]. |
524 */ | 530 */ |
525 E lastWhere(bool test(E element), {E orElse()}) { | 531 E lastWhere(bool test(E element), {E orElse()}) { |
526 E result = null; | 532 E result = null; |
527 bool foundMatching = false; | 533 bool foundMatching = false; |
528 for (E element in this) { | 534 for (E element in this) { |
529 if (test(element)) { | 535 if (test(element)) { |
530 result = element; | 536 result = element; |
531 foundMatching = true; | 537 foundMatching = true; |
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
596 * | 602 * |
597 * The conversion may omit calling `toString` on some elements if they | 603 * 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 | 604 * are known to not occur in the output, and it may stop iterating after |
599 * a hundred elements. | 605 * a hundred elements. |
600 */ | 606 */ |
601 String toString() => IterableBase.iterableToShortString(this, '(', ')'); | 607 String toString() => IterableBase.iterableToShortString(this, '(', ')'); |
602 } | 608 } |
603 | 609 |
604 typedef E _Generator<E>(int index); | 610 typedef E _Generator<E>(int index); |
605 | 611 |
606 class _GeneratorIterable<E> extends Iterable<E> | 612 class _GeneratorIterable<E> extends ListIterable<E> { |
607 implements EfficientLength { | 613 /// The length of the generated iterable. |
608 final int _start; | 614 final int length; |
609 final int _end; | 615 |
616 /// The function mapping indices to values. | |
610 final _Generator<E> _generator; | 617 final _Generator<E> _generator; |
611 | 618 |
612 /// Creates an iterable that builds the elements from a generator function. | 619 /// Creates the generated iterable. |
613 /// | 620 /// |
614 /// The [generator] may be null, in which case the default generator | 621 /// If [generator] is `null`, it is checked that `int` is assignable to [E]. |
615 /// enumerating the integer positions is used. This means that [int] must | 622 _GeneratorIterable(this.length, E generator(int index)) |
616 /// be assignable to [E] when no generator is provided. In practice this means | 623 : // The `as` below is used as check to make sure that `int` is assignable |
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]. | 624 // to [E]. |
623 _generator = (generator != null) ? generator : _id as _Generator<E>; | 625 _generator = (generator != null) ? generator : _id as _Generator<E>; |
624 | 626 |
625 _GeneratorIterable.slice(this._start, this._end, this._generator); | 627 E elementAt(int index) { |
626 | 628 RangeError.checkValidIndex(index, this); |
627 Iterator<E> get iterator => | 629 return _generator(index); |
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 } | 630 } |
638 | 631 |
639 Iterable<E> take(int count) { | 632 /// Helper function used as default _generator function. |
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; | 633 static int _id(int n) => n; |
648 } | 634 } |
649 | 635 |
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 /** | 636 /** |
673 * An Iterator that allows moving backwards as well as forwards. | 637 * An Iterator that allows moving backwards as well as forwards. |
674 */ | 638 */ |
675 abstract class BidirectionalIterator<E> implements Iterator<E> { | 639 abstract class BidirectionalIterator<E> implements Iterator<E> { |
676 /** | 640 /** |
677 * Move back to the previous element. | 641 * Move back to the previous element. |
678 * | 642 * |
679 * Returns true and updates [current] if successful. Returns false | 643 * Returns true and updates [current] if successful. Returns false |
680 * and sets [current] to null if there is no previous element. | 644 * and sets [current] to null if there is no previous element. |
681 */ | 645 */ |
682 bool movePrevious(); | 646 bool movePrevious(); |
683 } | 647 } |
OLD | NEW |