OLD | NEW |
1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, 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; | 5 part of dart.collection; |
6 | 6 |
| 7 /** A reusable set used to identify cyclic lists during toString() calls. */ |
| 8 Set _toStringVisiting = new HashSet.identity(); |
| 9 |
7 /** | 10 /** |
8 * Abstract implementation of a list. | 11 * Abstract implementation of a list. |
9 * | 12 * |
10 * All operations are defined in terms of `length`, `operator[]`, | 13 * All operations are defined in terms of `length`, `operator[]`, |
11 * `operator[]=` and `length=`, which need to be implemented. | 14 * `operator[]=` and `length=`, which need to be implemented. |
12 */ | 15 */ |
13 typedef ListBase<E> = Object with ListMixin<E>; | 16 typedef ListBase<E> = Object with ListMixin<E>; |
14 | 17 |
15 /** | 18 /** |
16 * Base implementation of a [List] class. | 19 * Base implementation of a [List] class. |
17 * | 20 * |
18 * This class can be used as a mixin. | 21 * This class can be used as a mixin. |
19 * | 22 * |
20 * This implements all read operations using only the `length` and | 23 * This implements all read operations using only the `length` and |
21 * `operator[]` members. It implements write operations using those and | 24 * `operator[]` members. It implements write operations using those and |
22 * `length=` and `operator[]=` | 25 * `length=` and `operator[]=` |
23 */ | 26 */ |
24 abstract class ListMixin<E> implements List<E> { | 27 abstract class ListMixin<E> implements List<E> { |
25 // A list to identify cyclic lists during toString() calls. | |
26 static List _toStringList = new List(); | |
27 | 28 |
28 // Iterable interface. | 29 // Iterable interface. |
29 Iterator<E> get iterator => new ListIterator<E>(this); | 30 Iterator<E> get iterator => new ListIterator<E>(this); |
30 | 31 |
31 E elementAt(int index) => this[index]; | 32 E elementAt(int index) => this[index]; |
32 | 33 |
33 void forEach(void action(E element)) { | 34 void forEach(void action(E element)) { |
34 int length = this.length; | 35 int length = this.length; |
35 for (int i = 0; i < length; i++) { | 36 for (int i = 0; i < length; i++) { |
36 action(this[i]); | 37 action(this[i]); |
(...skipping 443 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
480 } else { | 481 } else { |
481 for (E element in iterable) { | 482 for (E element in iterable) { |
482 this[index++] = element; | 483 this[index++] = element; |
483 } | 484 } |
484 } | 485 } |
485 } | 486 } |
486 | 487 |
487 Iterable<E> get reversed => new ReversedListIterable(this); | 488 Iterable<E> get reversed => new ReversedListIterable(this); |
488 | 489 |
489 String toString() { | 490 String toString() { |
490 for (int i = 0; i < _toStringList.length; i++) { | 491 if (_toStringVisiting.contains(this)) { |
491 if (identical(_toStringList[i], this)) { return '[...]'; } | 492 return '[...]'; |
492 } | 493 } |
493 | 494 |
494 var result = new StringBuffer(); | 495 var result = new StringBuffer(); |
495 try { | 496 try { |
496 _toStringList.add(this); | 497 _toStringVisiting.add(this); |
497 result.write('['); | 498 result.write('['); |
498 result.writeAll(this, ', '); | 499 result.writeAll(this, ', '); |
499 result.write(']'); | 500 result.write(']'); |
500 } finally { | 501 } finally { |
501 assert(identical(_toStringList.last, this)); | 502 _toStringVisiting.remove(this); |
502 _toStringList.removeLast(); | |
503 } | 503 } |
504 | 504 |
505 return result.toString(); | 505 return result.toString(); |
506 } | 506 } |
507 } | 507 } |
OLD | NEW |