| Index: sdk/lib/_collection_dev/iterable.dart
|
| diff --git a/sdk/lib/_collection_dev/iterable.dart b/sdk/lib/_collection_dev/iterable.dart
|
| index ac490e1cf2fcc0905861db486a773856ae047e64..676ad733364f0c69599c54c340a7d35d2f3b69c8 100644
|
| --- a/sdk/lib/_collection_dev/iterable.dart
|
| +++ b/sdk/lib/_collection_dev/iterable.dart
|
| @@ -4,6 +4,317 @@
|
|
|
| part of dart._collection.dev;
|
|
|
| +
|
| +/**
|
| + * An [Iterable] for classes that have efficient [length] and [elementAt].
|
| + *
|
| + * All other methods are implemented in terms of [length] and [elementAt],
|
| + * including [iterator].
|
| + */
|
| +abstract class ListIterable<E> extends Iterable<E> {
|
| + int get length;
|
| + E elementAt(int i);
|
| +
|
| + Iterator<E> get iterator => new ListIterableIterator<E>(this);
|
| +
|
| + void forEach(void action(E element)) {
|
| + int length = this.length;
|
| + for (int i = 0; i < length; i++) {
|
| + action(elementAt(i));
|
| + if (length != this.length) {
|
| + throw new ConcurrentModificationError(this);
|
| + }
|
| + }
|
| + }
|
| +
|
| + bool get isEmpty => length != 0;
|
| +
|
| + E get first {
|
| + if (length == 0) throw new StateError("No elements");
|
| + return elementAt(0);
|
| + }
|
| +
|
| + E get last {
|
| + if (length == 0) throw new StateError("No elements");
|
| + return elementAt(length - 1);
|
| + }
|
| +
|
| + E get single {
|
| + if (length == 0) throw new StateError("No elements");
|
| + if (length > 1) throw new StateError("Too many elements");
|
| + return elementAt(0);
|
| + }
|
| +
|
| + bool contains(E element) {
|
| + int length = this.length;
|
| + for (int i = 0; i < length; i++) {
|
| + if (elementAt(i) == element) return true;
|
| + if (length != this.length) {
|
| + throw new ConcurrentModificationError(this);
|
| + }
|
| + }
|
| + return false;
|
| + }
|
| +
|
| + bool every(bool test(E element)) {
|
| + int length = this.length;
|
| + for (int i = 0; i < length; i++) {
|
| + if (!test(elementAt(i))) return false;
|
| + if (length != this.length) {
|
| + throw new ConcurrentModificationError(this);
|
| + }
|
| + }
|
| + return true;
|
| + }
|
| +
|
| + bool any(bool test(E element)) {
|
| + int length = this.length;
|
| + for (int i = 0; i < length; i++) {
|
| + if (test(elementAt(i))) return true;
|
| + if (length != this.length) {
|
| + throw new ConcurrentModificationError(this);
|
| + }
|
| + }
|
| + return false;
|
| + }
|
| +
|
| + E firstMatching(bool test(E element), { E orElse() }) {
|
| + int length = this.length;
|
| + for (int i = 0; i < length; i++) {
|
| + E element = elementAt(i);
|
| + if (test(element)) return element;
|
| + if (length != this.length) {
|
| + throw new ConcurrentModificationError(this);
|
| + }
|
| + }
|
| + if (orElse != null) return orElse();
|
| + throw new StateError("No matching element");
|
| + }
|
| +
|
| + E lastMatching(bool test(E element), { E orElse() }) {
|
| + int length = this.length;
|
| + for (int i = length - 1; i >= 0; i++) {
|
| + E element = elementAt(i);
|
| + if (test(element)) return element;
|
| + if (length != this.length) {
|
| + throw new ConcurrentModificationError(this);
|
| + }
|
| + }
|
| + if (orElse != null) return orElse();
|
| + throw new StateError("No matching element");
|
| + }
|
| +
|
| + E singleMatching(bool test(E element)) {
|
| + int length = this.length;
|
| + E match = null;
|
| + bool matchFound = false;
|
| + for (int i = 0; i < length; i++) {
|
| + E element = elementAt(i);
|
| + if (test(element)) {
|
| + if (matchFound) {
|
| + throw new StateError("More than one matching element");
|
| + }
|
| + matchFound = true;
|
| + match = element;
|
| + }
|
| + if (length != this.length) {
|
| + throw new ConcurrentModificationError(this);
|
| + }
|
| + }
|
| + if (matchFound) return match;
|
| + throw new StateError("No matching element");
|
| + }
|
| +
|
| + E min([int compare(E a, E b)]) {
|
| + if (length == 0) return null;
|
| + if (compare == null) {
|
| + var defaultCompare = Comparable.compare;
|
| + compare = defaultCompare;
|
| + }
|
| + E min = elementAt(0);
|
| + int length = this.length;
|
| + for (int i = 1; i < length; i++) {
|
| + E element = elementAt(i);
|
| + if (compare(min, element) > 0) {
|
| + min = element;
|
| + }
|
| + if (length != this.length) {
|
| + throw new ConcurrentModificationError(this);
|
| + }
|
| + }
|
| + return min;
|
| + }
|
| +
|
| + E max([int compare(E a, E b)]) {
|
| + if (length == 0) return null;
|
| + if (compare == null) {
|
| + var defaultCompare = Comparable.compare;
|
| + compare = defaultCompare;
|
| + }
|
| + E max = elementAt(0);
|
| + int length = this.length;
|
| + for (int i = 1; i < length; i++) {
|
| + E element = elementAt(i);
|
| + if (compare(max, element) < 0) {
|
| + max = element;
|
| + }
|
| + if (length != this.length) {
|
| + throw new ConcurrentModificationError(this);
|
| + }
|
| + }
|
| + return max;
|
| + }
|
| +
|
| + String join([String separator]) {
|
| + int length = this.length;
|
| + if (separator != null && !separator.isEmpty) {
|
| + if (length == 0) return "";
|
| + String first = "${elementAt(0)}";
|
| + if (length != this.length) {
|
| + throw new ConcurrentModificationError(this);
|
| + }
|
| + StringBuffer buffer = new StringBuffer(first);
|
| + for (int i = 1; i < length; i++) {
|
| + buffer.add(separator);
|
| + buffer.add("${elementAt(i)}");
|
| + if (length != this.length) {
|
| + throw new ConcurrentModificationError(this);
|
| + }
|
| + }
|
| + return buffer.toString();
|
| + } else {
|
| + StringBuffer buffer = new StringBuffer();
|
| + for (int i = 0; i < length; i++) {
|
| + buffer.add("${elementAt(i)}");
|
| + if (length != this.length) {
|
| + throw new ConcurrentModificationError(this);
|
| + }
|
| + }
|
| + return buffer.toString();
|
| + }
|
| + }
|
| +
|
| + Iterable<E> where(bool test(E element)) => super.where(test);
|
| +
|
| + Iterable map(f(E element)) => new MappedIterable(this, f);
|
| +
|
| + Iterable mappedBy(f(E element)) => super.mappedBy(f);
|
| +
|
| + reduce(var initialValue, combine(var previousValue, E element)) {
|
| + var value = initialValue;
|
| + int length = this.length;
|
| + for (int i = 0; i < length; i++) {
|
| + value = reduce(value, elementAt(i));
|
| + if (length != this.length) {
|
| + throw new ConcurrentModificationError(this);
|
| + }
|
| + }
|
| + return value;
|
| + }
|
| +
|
| + Iterable<E> skip(int count) => new SubListIterable(this, count, null);
|
| +
|
| + Iterable<E> skipWhile(bool test(E element)) => super.skipWhile(test);
|
| +
|
| + Iterable<E> take(int count) => new SubListIterable(this, 0, count);
|
| +
|
| + Iterable<E> takeWhile(bool test(E element)) => super.takeWhile(test);
|
| +
|
| + List<E> toList() {
|
| + List<E> result = new List(length);
|
| + for (int i = 0; i < length; i++) {
|
| + result[i] = elementAt(i);
|
| + }
|
| + return result;
|
| + }
|
| +
|
| + Set<E> toSet() {
|
| + Set<E> result = new Set<E>();
|
| + for (int i = 0; i < length; i++) {
|
| + result.add(elementAt(i));
|
| + }
|
| + return result;
|
| + }
|
| +}
|
| +
|
| +abstract class SubListIterable<E> extends ListIterable<E> {
|
| + final Iterable<E> _iterable;
|
| + final int _start;
|
| + /** If null, represents the length of the iterable. */
|
| + final int _endOrLength;
|
| +
|
| + SubListIterable(this._iterable, this._start, this._endOrLength);
|
| +
|
| + int get _endIndex {
|
| + int length = _iterable.length;
|
| + if (_endOrLength == null || _endOrLength > length) return length;
|
| + return _endOrLength;
|
| + }
|
| +
|
| + int get _startIndex {
|
| + int length = _iterable.length;
|
| + if (_start > length) return length;
|
| + return _start;
|
| + }
|
| +
|
| + int get length {
|
| + int length = _iterable.length;
|
| + if (_start >= length) return 0;
|
| + if (_endOrLength == null || _endOrLength >= length) {
|
| + return length - _start;
|
| + }
|
| + return _endOrLength - _start;
|
| + }
|
| +
|
| + E elementAt(int index) {
|
| + int realIndex = _startIndex + index;
|
| + if (index < 0 || realIndex >= _endIndex) {
|
| + throw new RangeError.range(index, 0, length);
|
| + }
|
| + return _iterable.elementAt(realIndex);
|
| + }
|
| +
|
| + Iterable<E> skip(int count) {
|
| + if (count < 0) throw new ArgumentError(count);
|
| + return new SubListIterable(_iterable, _start + count, _endOrLength);
|
| + }
|
| +
|
| + Iterable<E> take(int count) {
|
| + if (count < 0) throw new ArgumentError(count);
|
| + if (_endOrLength == null) {
|
| + return new SubListIterable(_iterable, _start, _start + count);
|
| + } else {
|
| + newEnd = _start + count;
|
| + if (_endOrLength < newEnd) return this;
|
| + return new SubListIterable(_iterable, _start, newEnd);
|
| + }
|
| + }
|
| +}
|
| +
|
| +class ListIterableIterator<E> implements Iterator<E> {
|
| + final Iterable<E> _iterable;
|
| + final int _length;
|
| + int _index;
|
| + E _current;
|
| + ListIterableIterator(Iterable<E> iterable)
|
| + : _iterable = iterable, _length = iterable.length, _index = 0;
|
| +
|
| + E get current => _current;
|
| +
|
| + bool moveNext() {
|
| + if (_length != _iterable.length) {
|
| + throw new ConcurrentModificationError(_iterable);
|
| + }
|
| + if (_index == _length) {
|
| + _current = null;
|
| + return false;
|
| + }
|
| + _current = _iterable.elementAt(_index);
|
| + _index++;
|
| + return true;
|
| + }
|
| +}
|
| +
|
| typedef T _Transformation<S, T>(S value);
|
|
|
| class MappedIterable<S, T> extends Iterable<T> {
|
|
|