Chromium Code Reviews| 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._collection.dev; | 5 part of dart._collection.dev; |
| 6 | 6 |
| 7 | |
| 8 /** | 7 /** |
| 9 * An [Iterable] for classes that have efficient [length] and [elementAt]. | 8 * An [Iterable] for classes that have efficient [length] and [elementAt]. |
| 10 * | 9 * |
| 11 * All other methods are implemented in terms of [length] and [elementAt], | 10 * All other methods are implemented in terms of [length] and [elementAt], |
| 12 * including [iterator]. | 11 * including [iterator]. |
| 13 */ | 12 */ |
| 14 abstract class ListIterable<E> extends Iterable<E> { | 13 abstract class ListIterable<E> extends Iterable<E> { |
| 15 int get length; | 14 int get length; |
| 16 E elementAt(int i); | 15 E elementAt(int i); |
| 17 | 16 |
| 18 Iterator<E> get iterator => new ListIterableIterator<E>(this); | 17 Iterator<E> get iterator => new ListIterator<E>(this); |
| 19 | 18 |
| 20 void forEach(void action(E element)) { | 19 void forEach(void action(E element)) { |
| 21 int length = this.length; | 20 int length = this.length; |
| 22 for (int i = 0; i < length; i++) { | 21 for (int i = 0; i < length; i++) { |
| 23 action(elementAt(i)); | 22 action(elementAt(i)); |
| 24 if (length != this.length) { | 23 if (length != this.length) { |
| 25 throw new ConcurrentModificationError(this); | 24 throw new ConcurrentModificationError(this); |
| 26 } | 25 } |
| 27 } | 26 } |
| 28 } | 27 } |
| (...skipping 201 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 230 | 229 |
| 231 Set<E> toSet() { | 230 Set<E> toSet() { |
| 232 Set<E> result = new Set<E>(); | 231 Set<E> result = new Set<E>(); |
| 233 for (int i = 0; i < length; i++) { | 232 for (int i = 0; i < length; i++) { |
| 234 result.add(elementAt(i)); | 233 result.add(elementAt(i)); |
| 235 } | 234 } |
| 236 return result; | 235 return result; |
| 237 } | 236 } |
| 238 } | 237 } |
| 239 | 238 |
| 240 abstract class SubListIterable<E> extends ListIterable<E> { | 239 class SubListIterable<E> extends ListIterable<E> { |
| 241 final Iterable<E> _iterable; | 240 final Iterable<E> _iterable; |
| 242 final int _start; | 241 final int _start; |
| 243 /** If null, represents the length of the iterable. */ | 242 /** If null, represents the length of the iterable. */ |
| 244 final int _endOrLength; | 243 final int _endOrLength; |
| 245 | 244 |
| 246 SubListIterable(this._iterable, this._start, this._endOrLength); | 245 SubListIterable(this._iterable, this._start, this._endOrLength); |
| 247 | 246 |
| 248 int get _endIndex { | 247 int get _endIndex { |
| 249 int length = _iterable.length; | 248 int length = _iterable.length; |
| 250 if (_endOrLength == null || _endOrLength > length) return length; | 249 if (_endOrLength == null || _endOrLength > length) return length; |
| 251 return _endOrLength; | 250 return _endOrLength; |
| 252 } | 251 } |
| 253 | 252 |
| 254 int get _startIndex { | 253 int get _startIndex { |
| 255 int length = _iterable.length; | 254 int length = _iterable.length; |
| 256 if (_start > length) return length; | 255 if (_start > length) return length; |
| 257 return _start; | 256 return _start; |
| 258 } | 257 } |
| 259 | 258 |
| 260 int get length { | 259 int get length { |
| 261 int length = _iterable.length; | 260 int length = _iterable.length; |
| 262 if (_start >= length) return 0; | 261 if (_start >= length) return 0; |
| 263 if (_endOrLength == null || _endOrLength >= length) { | 262 if (_endOrLength == null || _endOrLength >= length) { |
| 264 return length - _start; | 263 return length - _start; |
| 265 } | 264 } |
| 266 return _endOrLength - _start | 265 return _endOrLength - _start; |
| 267 } | 266 } |
| 268 | 267 |
| 269 E elementAt(int index) { | 268 E elementAt(int index) { |
| 270 int realIndex = _startIndex + index; | 269 int realIndex = _startIndex + index; |
| 271 if (index < 0 || realIndex >= _endIndex) { | 270 if (index < 0 || realIndex >= _endIndex) { |
| 272 throw new RangeError.range(index, 0, length); | 271 throw new RangeError.range(index, 0, length); |
| 273 } | 272 } |
| 274 return _iterable.elementAt(realIndex); | 273 return _iterable.elementAt(realIndex); |
| 275 } | 274 } |
| 276 | 275 |
| 277 iterable<E> skip(int count) { | 276 Iterable<E> skip(int count) { |
| 278 if (count < 0) throw new ArgumentError(count); | 277 if (count < 0) throw new ArgumentError(count); |
| 279 return new SubListIterable(_iterable, _start + count, _endOrLength); | 278 return new SubListIterable(_iterable, _start + count, _endOrLength); |
| 280 } | 279 } |
| 281 | 280 |
| 282 iterable<E> take(int count) { | 281 Iterable<E> take(int count) { |
| 283 if (count < 0) throw new ArgumentError(count); | 282 if (count < 0) throw new ArgumentError(count); |
| 284 if (_endOrLength == null) { | 283 if (_endOrLength == null) { |
| 285 return new SubListIterable(_iterable, _start, _start + count); | 284 return new SubListIterable(_iterable, _start, _start + count); |
| 286 } else { | 285 } else { |
| 287 newEnd = _start + count; | 286 int newEnd = _start + count; |
| 288 if (_endOrLength < newEnd) return this; | 287 if (_endOrLength < newEnd) return this; |
|
floitsch
2013/02/14 15:33:07
Usually we return new objects. But I can understan
| |
| 289 return new SubListIterable(_iterable, _start, newEnd); | 288 return new SubListIterable(_iterable, _start, newEnd); |
| 290 } | 289 } |
| 291 } | 290 } |
| 292 } | 291 } |
| 293 | 292 |
| 294 class ListIterableIterator<E> implements Iterator<E> { | 293 /** |
| 294 * An [Iterator] that iterates a list-like [Iterable]. | |
| 295 * | |
| 296 * All iterations is done in terms of [Iterable.length] and | |
| 297 * [Iterable.elementAt]. These operations are fast for list-like | |
| 298 * iterables. | |
| 299 */ | |
| 300 class ListIterator<E> implements Iterator<E> { | |
| 295 final Iterable<E> _iterable; | 301 final Iterable<E> _iterable; |
| 296 final int _length; | 302 final int _length; |
| 297 int _index; | 303 int _index; |
| 298 E _current; | 304 E _current; |
| 299 ListIterableIterator(Iterable<E> iterable) | 305 |
| 306 ListIterator(Iterable<E> iterable) | |
| 300 : _iterable = iterable, _length = iterable.length, _index = 0; | 307 : _iterable = iterable, _length = iterable.length, _index = 0; |
| 301 | 308 |
| 302 E get current => _current; | 309 E get current => _current; |
| 303 | 310 |
| 304 bool moveNext() { | 311 bool moveNext() { |
| 305 if (_length != _iterable.length) { | 312 if (_length != _iterable.length) { |
| 306 throw new ConcurrentModificationError(_iterable); | 313 throw new ConcurrentModificationError(_iterable); |
| 307 } | 314 } |
| 308 if (_index == _length) { | 315 if (_index == _length) { |
| 309 _current = null; | 316 _current = null; |
| (...skipping 13 matching lines...) Expand all Loading... | |
| 323 // checked mode. http://dartbug.com/7733 | 330 // checked mode. http://dartbug.com/7733 |
| 324 final /* _Transformation<S, T> */ _f; | 331 final /* _Transformation<S, T> */ _f; |
| 325 | 332 |
| 326 MappedIterable(this._iterable, T this._f(S element)); | 333 MappedIterable(this._iterable, T this._f(S element)); |
| 327 | 334 |
| 328 Iterator<T> get iterator => new MappedIterator<S, T>(_iterable.iterator, _f); | 335 Iterator<T> get iterator => new MappedIterator<S, T>(_iterable.iterator, _f); |
| 329 | 336 |
| 330 // Length related functions are independent of the mapping. | 337 // Length related functions are independent of the mapping. |
| 331 int get length => _iterable.length; | 338 int get length => _iterable.length; |
| 332 bool get isEmpty => _iterable.isEmpty; | 339 bool get isEmpty => _iterable.isEmpty; |
| 340 | |
| 341 // Index based lookup can be done before transforming. | |
| 342 T get first => _f(_iterable.first); | |
| 343 T get last => _f(_iterable.last); | |
| 344 T get single => _f(_iterable.single); | |
| 345 T elementAt(int index) => _f(_iterable.elementAt(index)); | |
| 333 } | 346 } |
| 334 | 347 |
| 335 | |
| 336 class MappedIterator<S, T> extends Iterator<T> { | 348 class MappedIterator<S, T> extends Iterator<T> { |
| 337 T _current; | 349 T _current; |
| 338 final Iterator<S> _iterator; | 350 final Iterator<S> _iterator; |
| 339 // TODO(ahe): Restore type when feature is implemented in dart2js | 351 // TODO(ahe): Restore type when feature is implemented in dart2js |
| 340 // checked mode. http://dartbug.com/7733 | 352 // checked mode. http://dartbug.com/7733 |
| 341 final /* _Transformation<S, T> */ _f; | 353 final /* _Transformation<S, T> */ _f; |
| 342 | 354 |
| 343 MappedIterator(this._iterator, T this._f(S element)); | 355 MappedIterator(this._iterator, T this._f(S element)); |
| 344 | 356 |
| 345 bool moveNext() { | 357 bool moveNext() { |
| 346 if (_iterator.moveNext()) { | 358 if (_iterator.moveNext()) { |
| 347 _current = _f(_iterator.current); | 359 _current = _f(_iterator.current); |
| 348 return true; | 360 return true; |
| 349 } else { | |
| 350 _current = null; | |
| 351 return false; | |
| 352 } | 361 } |
| 362 _current = null; | |
| 363 return false; | |
| 353 } | 364 } |
| 354 | 365 |
| 355 T get current => _current; | 366 T get current => _current; |
| 356 } | 367 } |
| 357 | 368 |
| 358 /** Specialized alternative to [MappedIterable] for mapped [List]s. */ | 369 /** Specialized alternative to [MappedIterable] for mapped [List]s. */ |
| 359 class MappedListIterable<S, T> extends Iterable<T> { | 370 class MappedListIterable<S, T> extends ListIterable<T> { |
| 360 final List<S> _list; | 371 final Iterable<S> _source; |
| 361 /** | |
| 362 * Start index of the part of the list to map. | |
| 363 * | |
| 364 * Allows mapping only a sub-list of an existing list. | |
| 365 * | |
| 366 * Used to implement lazy skip/take on a [MappedListIterable]. | |
| 367 */ | |
| 368 final int _start; | |
| 369 | |
| 370 /** | |
| 371 * End index of the part of the list to map. | |
| 372 * | |
| 373 * If null, always use the length of the list. | |
| 374 */ | |
| 375 final int _end; | |
| 376 | |
| 377 // TODO(ahe): Restore type when feature is implemented in dart2js | 372 // TODO(ahe): Restore type when feature is implemented in dart2js |
| 378 // checked mode. http://dartbug.com/7733 | 373 // checked mode. http://dartbug.com/7733 |
| 379 final /* _Transformation<S, T> */ _f; | 374 final /* _Transformation<S, T> */ _f; |
| 380 | 375 |
| 381 MappedListIterable(this._list, T this._f(S element), this._start, this._end) { | 376 MappedListIterable(this._source, T this._f(S value)); |
| 382 if (_end != null && _end < _start) { | |
| 383 throw new ArgumentError("End ($_end) before start ($_start)"); | |
| 384 } | |
| 385 } | |
| 386 | 377 |
| 387 /** The start index, limited to the current length of the list. */ | 378 int get length => _source.length; |
| 388 int get _startIndex { | 379 T elementAt(int index) => _f(_source.elementAt(index)); |
| 389 if (_start <= _list.length) return _start; | |
| 390 return _list.length; | |
| 391 } | |
| 392 | |
| 393 /** The end index, if given, limited to the current length of the list. */ | |
| 394 int get _endIndex { | |
| 395 if (_end == null || _end > _list.length) return _list.length; | |
| 396 return _end; | |
| 397 } | |
| 398 | |
| 399 Iterator<T> get iterator => | |
| 400 new MappedListIterator<S, T>(_list, _f, _startIndex, _endIndex); | |
| 401 | |
| 402 void forEach(void action(T element)) { | |
| 403 int length = _list.length; | |
| 404 for (int i = _startIndex, n = _endIndex; i < n; i++) { | |
| 405 action(_f(_list[i])); | |
| 406 if (_list.length != length) { | |
| 407 throw new ConcurrentModificationError(_list); | |
| 408 } | |
| 409 } | |
| 410 } | |
| 411 | |
| 412 bool get isEmpty => _startIndex == _endIndex; | |
| 413 | |
| 414 int get length => _endIndex - _startIndex; | |
| 415 | |
| 416 T get first { | |
| 417 int start = _startIndex; | |
| 418 if (start == _endIndex) { | |
| 419 throw new StateError("No elements"); | |
| 420 } | |
| 421 return _f(_list.elementAt(start)); | |
| 422 } | |
| 423 | |
| 424 T get last { | |
| 425 int end = _endIndex; | |
| 426 if (end == _startIndex) { | |
| 427 throw new StateError("No elements"); | |
| 428 } | |
| 429 return _f(_list.elementAt(end - 1)); | |
| 430 } | |
| 431 | |
| 432 T get single { | |
| 433 int start = _startIndex; | |
| 434 int end = _endIndex; | |
| 435 if (start != end - 1) { | |
| 436 if (start == end) { | |
| 437 throw new StateError("No elements"); | |
| 438 } | |
| 439 throw new StateError("Too many elements"); | |
| 440 } | |
| 441 return _f(_list[start]); | |
| 442 } | |
| 443 | |
| 444 T elementAt(int index) { | |
| 445 index += _startIndex; | |
| 446 if (index >= _endIndex) { | |
| 447 throw new StateError("No matching element"); | |
| 448 } | |
| 449 return _f(_list.elementAt(index)); | |
| 450 } | |
| 451 | |
| 452 bool contains(T element) { | |
| 453 int length = _list.length; | |
| 454 for (int i = _startIndex, n = _endIndex; i < n; i++) { | |
| 455 if (_f(_list[i]) == element) { | |
| 456 return true; | |
| 457 } | |
| 458 if (_list.length != length) { | |
| 459 throw new ConcurrentModificationError(_list); | |
| 460 } | |
| 461 } | |
| 462 return false; | |
| 463 } | |
| 464 | |
| 465 bool every(bool test(T element)) { | |
| 466 int length = _list.length; | |
| 467 for (int i = _startIndex, n = _endIndex; i < n; i++) { | |
| 468 if (!test(_f(_list[i]))) return false; | |
| 469 if (_list.length != length) { | |
| 470 throw new ConcurrentModificationError(_list); | |
| 471 } | |
| 472 } | |
| 473 return true; | |
| 474 } | |
| 475 | |
| 476 bool any(bool test(T element)) { | |
| 477 int length = _list.length; | |
| 478 for (int i = _startIndex, n = _endIndex; i < n; i++) { | |
| 479 if (test(_f(_list[i]))) return true; | |
| 480 if (_list.length != length) { | |
| 481 throw new ConcurrentModificationError(_list); | |
| 482 } | |
| 483 } | |
| 484 return false; | |
| 485 } | |
| 486 | |
| 487 T firstMatching(bool test(T element), { T orElse() }) { | |
| 488 int length = _list.length; | |
| 489 for (int i = _startIndex, n = _endIndex; i < n; i++) { | |
| 490 T value = _f(_list[i]); | |
| 491 if (test(value)) return value; | |
| 492 if (_list.length != length) { | |
| 493 throw new ConcurrentModificationError(_list); | |
| 494 } | |
| 495 } | |
| 496 if (orElse != null) return orElse(); | |
| 497 throw new StateError("No matching element"); | |
| 498 } | |
| 499 | |
| 500 T lastMatching(bool test(T element), { T orElse() }) { | |
| 501 int length = _list.length; | |
| 502 for (int i = _endIndex - 1, start = _startIndex; i >= start; i++) { | |
| 503 T value = _f(_list[i]); | |
| 504 if (test(value)) return value; | |
| 505 if (_list.length != length) { | |
| 506 throw new ConcurrentModificationError(_list); | |
| 507 } | |
| 508 } | |
| 509 if (orElse != null) return orElse(); | |
| 510 throw new StateError("No matching element"); | |
| 511 } | |
| 512 | |
| 513 T singleMatching(bool test(T element)) { | |
| 514 int length = _list.length; | |
| 515 T match; | |
| 516 bool matchFound = false; | |
| 517 for (int i = _startIndex, n = _endIndex; i < n; i++) { | |
| 518 T value = _f(_list[i]); | |
| 519 if (test(value)) { | |
| 520 if (matchFound) { | |
| 521 throw new StateError("More than one matching element"); | |
| 522 } | |
| 523 matchFound = true; | |
| 524 match = value; | |
| 525 } | |
| 526 if (_list.length != length) { | |
| 527 throw new ConcurrentModificationError(_list); | |
| 528 } | |
| 529 } | |
| 530 if (matchFound) return match; | |
| 531 throw new StateError("No matching element"); | |
| 532 } | |
| 533 | |
| 534 T min([int compare(T a, T b)]) { | |
| 535 if (compare == null) { | |
| 536 var defaultCompare = Comparable.compare; | |
| 537 compare = defaultCompare; | |
| 538 } | |
| 539 int length = _list.length; | |
| 540 int start = _startIndex; | |
| 541 int end = _endIndex; | |
| 542 if (start == end) return null; | |
| 543 T value = _f(_list[start]); | |
| 544 if (_list.length != length) { | |
| 545 throw new ConcurrentModificationError(_list); | |
| 546 } | |
| 547 for (int i = start + 1; i < end; i++) { | |
| 548 T nextValue = _f(_list[i]); | |
| 549 if (compare(value, nextValue) > 0) { | |
| 550 value = nextValue; | |
| 551 } | |
| 552 if (_list.length != length) { | |
| 553 throw new ConcurrentModificationError(_list); | |
| 554 } | |
| 555 } | |
| 556 return value; | |
| 557 } | |
| 558 | |
| 559 T max([int compare(T a, T b)]) { | |
| 560 if (compare == null) { | |
| 561 var defaultCompare = Comparable.compare; | |
| 562 compare = defaultCompare; | |
| 563 } | |
| 564 int length = _list.length; | |
| 565 int start = _startIndex; | |
| 566 int end = _endIndex; | |
| 567 if (start == end) return null; | |
| 568 T value = _f(_list[start]); | |
| 569 if (_list.length != length) { | |
| 570 throw new ConcurrentModificationError(_list); | |
| 571 } | |
| 572 for (int i = start + 1; i < end; i++) { | |
| 573 T nextValue = _f(_list[i]); | |
| 574 if (compare(value, nextValue) < 0) { | |
| 575 value = nextValue; | |
| 576 } | |
| 577 if (_list.length != length) { | |
| 578 throw new ConcurrentModificationError(_list); | |
| 579 } | |
| 580 } | |
| 581 return value; | |
| 582 } | |
| 583 | |
| 584 String join([String separator]) { | |
| 585 int start = _startIndex; | |
| 586 int end = _endIndex; | |
| 587 if (start == end) return ""; | |
| 588 StringBuffer buffer = new StringBuffer("${_f(_list[start])}"); | |
| 589 if (_list.length != length) { | |
| 590 throw new ConcurrentModificationError(_list); | |
| 591 } | |
| 592 for (int i = start + 1; i < end; i++) { | |
| 593 if (separator != null && separator != "") { | |
| 594 buffer.add(separator); | |
| 595 } | |
| 596 buffer.add("${_f(_list[i])}"); | |
| 597 if (_list.length != length) { | |
| 598 throw new ConcurrentModificationError(_list); | |
| 599 } | |
| 600 } | |
| 601 return buffer.toString(); | |
| 602 } | |
| 603 | |
| 604 Iterable<T> where(bool test(T element)) => super.where(test); | |
| 605 | |
| 606 Iterable map(f(T element)) { | |
| 607 return new MappedListIterable(_list, (S v) => f(_f(v)), _start, _end); | |
| 608 } | |
| 609 | |
| 610 Iterable mappedBy(f(T element)) => map(f); | |
| 611 | |
| 612 reduce(var initialValue, combine(var previousValue, T element)) { | |
| 613 return _list.reduce(initialValue, (v, S e) => combine(v, _f(e))); | |
| 614 } | |
| 615 | |
| 616 Iterable<T> skip(int count) { | |
| 617 int start = _startIndex + count; | |
| 618 if (_end != null && start >= _end) { | |
| 619 return new EmptyIterable<T>(); | |
| 620 } | |
| 621 return new MappedListIterable(_list, _f, start, _end); | |
| 622 } | |
| 623 | |
| 624 Iterable<T> skipWhile(bool test(T element)) => super.skipWhile(test); | |
| 625 | |
| 626 Iterable<T> take(int count) { | |
| 627 int newEnd = _start + count; | |
| 628 if (_end == null || newEnd < _end) { | |
| 629 return new MappedListIterable(_list, _f, _start, newEnd); | |
| 630 } | |
| 631 // Equivalent to "this". | |
| 632 return new MappedListIterable(_list, _f, _start, _end); | |
| 633 } | |
| 634 | |
| 635 Iterable<T> takeWhile(bool test(T element)) => super.takeWhile(test); | |
| 636 | |
| 637 List<T> toList() { | |
| 638 List<T> result = new List<T>(); | |
| 639 forEach(result.add); | |
| 640 return result; | |
| 641 } | |
| 642 | |
| 643 Set<T> toSet() { | |
| 644 Set<T> result = new Set<T>(); | |
| 645 forEach(result.add); | |
| 646 return result; | |
| 647 } | |
| 648 } | |
| 649 | |
| 650 /** | |
| 651 * Iterator for [MappedListIterable]. | |
| 652 * | |
| 653 * A list iterator that iterates over (a sublist of) a list and | |
| 654 * returns the values transformed by a function. | |
| 655 * | |
| 656 * As a list iterator, it throws if the length of the list has | |
| 657 * changed during iteration. | |
| 658 */ | |
| 659 class MappedListIterator<S, T> implements Iterator<T> { | |
| 660 List<S> _list; | |
| 661 // TODO(ahe): Restore type when feature is implemented in dart2js | |
| 662 // checked mode. http://dartbug.com/7733 | |
| 663 final /* _Transformation<S, T> */ _f; | |
| 664 final int _endIndex; | |
| 665 final int _length; | |
| 666 int _index; | |
| 667 T _current; | |
| 668 | |
| 669 MappedListIterator(List<S> list, this._f, int start, this._endIndex) | |
| 670 : _list = list, _length = list.length, _index = start; | |
| 671 | |
| 672 T get current => _current; | |
| 673 | |
| 674 bool moveNext() { | |
| 675 if (_list.length != _length) { | |
| 676 throw new ConcurrentModificationError(_list); | |
| 677 } | |
| 678 if (_index >= _endIndex) { | |
| 679 _current = null; | |
| 680 return false; | |
| 681 } | |
| 682 _current = _f(_list[_index]); | |
| 683 _index++; | |
| 684 return true; | |
| 685 } | |
| 686 } | 380 } |
| 687 | 381 |
| 688 typedef bool _ElementPredicate<E>(E element); | 382 typedef bool _ElementPredicate<E>(E element); |
| 689 | 383 |
| 690 class WhereIterable<E> extends Iterable<E> { | 384 class WhereIterable<E> extends Iterable<E> { |
| 691 final Iterable<E> _iterable; | 385 final Iterable<E> _iterable; |
| 692 // TODO(ahe): Restore type when feature is implemented in dart2js | 386 // TODO(ahe): Restore type when feature is implemented in dart2js |
| 693 // checked mode. http://dartbug.com/7733 | 387 // checked mode. http://dartbug.com/7733 |
| 694 final /* _ElementPredicate */ _f; | 388 final /* _ElementPredicate */ _f; |
| 695 | 389 |
| (...skipping 296 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 992 class EmptyIterator<E> implements Iterator<E> { | 686 class EmptyIterator<E> implements Iterator<E> { |
| 993 const EmptyIterator(); | 687 const EmptyIterator(); |
| 994 bool moveNext() => false; | 688 bool moveNext() => false; |
| 995 E get current => null; | 689 E get current => null; |
| 996 } | 690 } |
| 997 | 691 |
| 998 /** An [Iterator] that can move in both directions. */ | 692 /** An [Iterator] that can move in both directions. */ |
| 999 abstract class BiDirectionalIterator<T> implements Iterator<T> { | 693 abstract class BiDirectionalIterator<T> implements Iterator<T> { |
| 1000 bool movePrevious(); | 694 bool movePrevious(); |
| 1001 } | 695 } |
| OLD | NEW |