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

Side by Side Diff: tool/input_sdk/lib/core/iterable.dart

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

Powered by Google App Engine
This is Rietveld 408576698