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

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: Reword skip docs 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 *
422 * The `count` must not be negative. 423 * Some iterables may be able to find later elements without first iterating
424 * through earlier elements, for example when iterating a [List].
425 * Such iterables are allowed to ignore the initial skipped elements.
426 *
427 * The [count] must not be negative.
423 */ 428 */
424 Iterable<E> skip(int count) { 429 Iterable<E> skip(int count) {
425 return new SkipIterable<E>(this, count); 430 return new SkipIterable<E>(this, count);
426 } 431 }
427 432
428 /** 433 /**
429 * Returns an Iterable that skips leading elements while [test] is satisfied. 434 * Returns an `Iterable` that skips leading elements while [test] is satisfied .
430 * 435 *
431 * The filtering happens lazily. Every new Iterator of the returned 436 * The filtering happens lazily. Every new [Iterator] of the returned
432 * Iterable iterates over all elements of `this`. 437 * iterable iterates over all elements of `this`.
433 * 438 *
434 * The returned iterable provides elements by iterating this iterable, 439 * The returned iterable provides elements by iterating this iterable,
435 * but skipping over all initial elements where `test(element)` returns 440 * but skipping over all initial elements where `test(element)` returns
436 * true. If all elements satisfy `test` the resulting iterable is empty, 441 * true. If all elements satisfy `test` the resulting iterable is empty,
437 * otherwise it iterates the remaining elements in their original order, 442 * otherwise it iterates the remaining elements in their original order,
438 * starting with the first element for which `test(element)` returns false. 443 * starting with the first element for which `test(element)` returns `false`.
439 */ 444 */
440 Iterable<E> skipWhile(bool test(E value)) { 445 Iterable<E> skipWhile(bool test(E value)) {
441 return new SkipWhileIterable<E>(this, test); 446 return new SkipWhileIterable<E>(this, test);
442 } 447 }
443 448
444 /** 449 /**
445 * Returns the first element. 450 * Returns the first element.
446 * 451 *
447 * Throws a [StateError] if `this` is empty. 452 * Throws a [StateError] if `this` is empty.
448 * Otherwise returns the first element in the iteration order, 453 * 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; 492 Iterator<E> it = iterator;
488 if (!it.moveNext()) throw IterableElementError.noElement(); 493 if (!it.moveNext()) throw IterableElementError.noElement();
489 E result = it.current; 494 E result = it.current;
490 if (it.moveNext()) throw IterableElementError.tooMany(); 495 if (it.moveNext()) throw IterableElementError.tooMany();
491 return result; 496 return result;
492 } 497 }
493 498
494 /** 499 /**
495 * Returns the first element that satisfies the given predicate [test]. 500 * Returns the first element that satisfies the given predicate [test].
496 * 501 *
497 * Iterates through elements and returns the first to satsify [test]. 502 * Iterates through elements and returns the first to satisfy [test].
498 * 503 *
499 * If no element satisfies [test], the result of invoking the [orElse] 504 * If no element satisfies [test], the result of invoking the [orElse]
500 * function is returned. 505 * function is returned.
501 * If [orElse] is omitted, it defaults to throwing a [StateError]. 506 * If [orElse] is omitted, it defaults to throwing a [StateError].
502 */ 507 */
503 E firstWhere(bool test(E element), { E orElse() }) { 508 E firstWhere(bool test(E element), { E orElse() }) {
504 for (E element in this) { 509 for (E element in this) {
505 if (test(element)) return element; 510 if (test(element)) return element;
506 } 511 }
507 if (orElse != null) return orElse(); 512 if (orElse != null) return orElse();
508 throw IterableElementError.noElement(); 513 throw IterableElementError.noElement();
509 } 514 }
510 515
511 /** 516 /**
512 * Returns the last element that satisfies the given predicate [test]. 517 * Returns the last element that satisfies the given predicate [test].
513 * 518 *
514 * An iterable that can access its elements directly may check its 519 * An iterable that can access its elements directly may check its
515 * elements in any order (for example a list starts by checking the 520 * elements in any order (for example a list starts by checking the
516 * last element and then moves towards the start of the list). 521 * last element and then moves towards the start of the list).
517 * The default implementation iterates elements in iteration order, 522 * The default implementation iterates elements in iteration order,
518 * checks `test(element)` for each, 523 * checks `test(element)` for each,
519 * and finally returns that last one that matched. 524 * and finally returns that last one that matched.
520 * 525 *
521 * If no element satsfies [test], the result of invoking the [orElse] 526 * If no element satisfies [test], the result of invoking the [orElse]
522 * function is returned. 527 * function is returned.
523 * If [orElse] is omitted, it defaults to throwing a [StateError]. 528 * If [orElse] is omitted, it defaults to throwing a [StateError].
524 */ 529 */
525 E lastWhere(bool test(E element), {E orElse()}) { 530 E lastWhere(bool test(E element), {E orElse()}) {
526 E result = null; 531 E result = null;
527 bool foundMatching = false; 532 bool foundMatching = false;
528 for (E element in this) { 533 for (E element in this) {
529 if (test(element)) { 534 if (test(element)) {
530 result = element; 535 result = element;
531 foundMatching = true; 536 foundMatching = true;
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after
596 * 601 *
597 * The conversion may omit calling `toString` on some elements if they 602 * 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 603 * are known to not occur in the output, and it may stop iterating after
599 * a hundred elements. 604 * a hundred elements.
600 */ 605 */
601 String toString() => IterableBase.iterableToShortString(this, '(', ')'); 606 String toString() => IterableBase.iterableToShortString(this, '(', ')');
602 } 607 }
603 608
604 typedef E _Generator<E>(int index); 609 typedef E _Generator<E>(int index);
605 610
606 class _GeneratorIterable<E> extends Iterable<E> 611 class _GeneratorIterable<E> extends ListIterable<E> {
607 implements EfficientLength { 612 /// The length of the generated iterable.
608 final int _start; 613 final int length;
609 final int _end; 614
615 /// The function mapping indices to values.
610 final _Generator<E> _generator; 616 final _Generator<E> _generator;
611 617
612 /// Creates an iterable that builds the elements from a generator function. 618 /// Creates the generated iterable.
613 /// 619 ///
614 /// The [generator] may be null, in which case the default generator 620 /// 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 621 _GeneratorIterable(this.length, E generator(int index))
616 /// be assignable to [E] when no generator is provided. In practice this means 622 : // 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]. 623 // to [E].
623 _generator = (generator != null) ? generator : _id as _Generator<E>; 624 _generator = (generator != null) ? generator : _id as _Generator<E>;
624 625
625 _GeneratorIterable.slice(this._start, this._end, this._generator); 626 E elementAt(int index) {
626 627 RangeError.checkValidIndex(index, this);
627 Iterator<E> get iterator => 628 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 } 629 }
638 630
639 Iterable<E> take(int count) { 631 /// 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; 632 static int _id(int n) => n;
648 } 633 }
649 634
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 /** 635 /**
673 * An Iterator that allows moving backwards as well as forwards. 636 * An Iterator that allows moving backwards as well as forwards.
674 */ 637 */
675 abstract class BidirectionalIterator<E> implements Iterator<E> { 638 abstract class BidirectionalIterator<E> implements Iterator<E> {
676 /** 639 /**
677 * Move back to the previous element. 640 * Move back to the previous element.
678 * 641 *
679 * Returns true and updates [current] if successful. Returns false 642 * Returns true and updates [current] if successful. Returns false
680 * and sets [current] to null if there is no previous element. 643 * and sets [current] to null if there is no previous element.
681 */ 644 */
682 bool movePrevious(); 645 bool movePrevious();
683 } 646 }
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