Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(88)

Side by Side Diff: sdk/lib/core/iterable.dart

Issue 1992713002: Make Iterable.generate use ListIterable as base implementation. (Closed) Base URL: https://github.com/dart-lang/sdk.git@master
Patch Set: Created 4 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « sdk/lib/async/future.dart ('k') | tests/corelib/iterable_generate_test.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
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
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 }
OLDNEW
« no previous file with comments | « sdk/lib/async/future.dart ('k') | tests/corelib/iterable_generate_test.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698