diff --git a/runtime/vm/debugger_api_impl_test.cc b/runtime/vm/debugger_api_impl_test.cc index e8df0880082..4bbc7e8f496 100644 --- a/runtime/vm/debugger_api_impl_test.cc +++ b/runtime/vm/debugger_api_impl_test.cc @@ -2147,7 +2147,7 @@ TEST_CASE(Debug_GetSupertype) { Dart_Handle object_name = Dart_NewStringFromCString("Object"); Dart_Handle int_name = Dart_NewStringFromCString("int"); Dart_Handle set_name = Dart_NewStringFromCString("Set"); - Dart_Handle iterable_name = Dart_NewStringFromCString("IterableBase"); + Dart_Handle iterable_name = Dart_NewStringFromCString("Iterable"); Dart_Handle list_name = Dart_NewStringFromCString("List"); Dart_Handle object_type = Dart_GetType(core_lib, object_name, 0, NULL); diff --git a/sdk/lib/_internal/compiler/js_lib/collection_patch.dart b/sdk/lib/_internal/compiler/js_lib/collection_patch.dart index 67e54bc0978..9242d392644 100644 --- a/sdk/lib/_internal/compiler/js_lib/collection_patch.dart +++ b/sdk/lib/_internal/compiler/js_lib/collection_patch.dart @@ -427,7 +427,7 @@ class _CustomHashMap extends _HashMap { String toString() => Maps.mapToString(this); } -class HashMapKeyIterable extends IterableBase +class HashMapKeyIterable extends Iterable implements EfficientLength { final _map; HashMapKeyIterable(this._map); diff --git a/sdk/lib/_internal/compiler/js_lib/constant_map.dart b/sdk/lib/_internal/compiler/js_lib/constant_map.dart index ae3e3799f33..e716cf14bf9 100644 --- a/sdk/lib/_internal/compiler/js_lib/constant_map.dart +++ b/sdk/lib/_internal/compiler/js_lib/constant_map.dart @@ -92,7 +92,7 @@ class ConstantProtoMap extends ConstantStringMap { '__proto__' == key ? _protoValue : jsPropertyAccess(_jsObject, key); } -class _ConstantMapKeyIterable extends IterableBase { +class _ConstantMapKeyIterable extends Iterable { ConstantStringMap _map; _ConstantMapKeyIterable(this._map); diff --git a/sdk/lib/_internal/compiler/js_lib/js_helper.dart b/sdk/lib/_internal/compiler/js_lib/js_helper.dart index c2d26ff6029..bb22a2fdce1 100644 --- a/sdk/lib/_internal/compiler/js_lib/js_helper.dart +++ b/sdk/lib/_internal/compiler/js_lib/js_helper.dart @@ -3972,7 +3972,7 @@ class SyncStarIterator implements Iterator { /// An Iterable corresponding to a sync* method. /// /// Each invocation of a sync* method will return a new instance of this class. -class SyncStarIterable extends IterableBase { +class SyncStarIterable extends Iterable { // This is a function that will return a helper function that does the // iteration of the sync*. // diff --git a/sdk/lib/_internal/compiler/js_lib/linked_hash_map.dart b/sdk/lib/_internal/compiler/js_lib/linked_hash_map.dart index f543e74d706..f99e067c69c 100644 --- a/sdk/lib/_internal/compiler/js_lib/linked_hash_map.dart +++ b/sdk/lib/_internal/compiler/js_lib/linked_hash_map.dart @@ -324,7 +324,7 @@ class LinkedHashMapCell { LinkedHashMapCell(this.hashMapCellKey, this.hashMapCellValue); } -class LinkedHashMapKeyIterable extends IterableBase +class LinkedHashMapKeyIterable extends Iterable implements EfficientLength { final _map; LinkedHashMapKeyIterable(this._map); diff --git a/sdk/lib/collection/iterable.dart b/sdk/lib/collection/iterable.dart index 154d19c2dde..32906824459 100644 --- a/sdk/lib/collection/iterable.dart +++ b/sdk/lib/collection/iterable.dart @@ -206,210 +206,9 @@ abstract class IterableMixin implements Iterable { * This class implements all methods of [Iterable] except [Iterable.iterator] * in terms of `iterator`. */ -abstract class IterableBase implements Iterable { - // TODO(lrn): Base this on IterableMixin if there ever becomes a way - // to combine const constructors and mixins. +abstract class IterableBase extends Iterable { const IterableBase(); - Iterable map(f(E element)) => new MappedIterable(this, f); - - Iterable where(bool f(E element)) => new WhereIterable(this, f); - - Iterable expand(Iterable f(E element)) => - new ExpandIterable(this, f); - - bool contains(Object element) { - for (E e in this) { - if (e == element) return true; - } - return false; - } - - void forEach(void f(E element)) { - for (E element in this) f(element); - } - - E reduce(E combine(E value, E element)) { - Iterator iterator = this.iterator; - if (!iterator.moveNext()) { - throw IterableElementError.noElement(); - } - E value = iterator.current; - while (iterator.moveNext()) { - value = combine(value, iterator.current); - } - return value; - } - - dynamic fold(var initialValue, - dynamic combine(var previousValue, E element)) { - var value = initialValue; - for (E element in this) value = combine(value, element); - return value; - } - - bool every(bool f(E element)) { - for (E element in this) { - if (!f(element)) return false; - } - return true; - } - - String join([String separator = ""]) { - Iterator iterator = this.iterator; - if (!iterator.moveNext()) return ""; - StringBuffer buffer = new StringBuffer(); - if (separator == null || separator == "") { - do { - buffer.write("${iterator.current}"); - } while (iterator.moveNext()); - } else { - buffer.write("${iterator.current}"); - while (iterator.moveNext()) { - buffer.write(separator); - buffer.write("${iterator.current}"); - } - } - return buffer.toString(); - } - - bool any(bool f(E element)) { - for (E element in this) { - if (f(element)) return true; - } - return false; - } - - List toList({ bool growable: true }) => - new List.from(this, growable: growable); - - Set toSet() => new Set.from(this); - - int get length { - assert(this is! EfficientLength); - int count = 0; - Iterator it = iterator; - while (it.moveNext()) { - count++; - } - return count; - } - - bool get isEmpty => !iterator.moveNext(); - - bool get isNotEmpty => !isEmpty; - - Iterable take(int n) { - return new TakeIterable(this, n); - } - - Iterable takeWhile(bool test(E value)) { - return new TakeWhileIterable(this, test); - } - - Iterable skip(int n) { - return new SkipIterable(this, n); - } - - Iterable skipWhile(bool test(E value)) { - return new SkipWhileIterable(this, test); - } - - E get first { - Iterator it = iterator; - if (!it.moveNext()) { - throw IterableElementError.noElement(); - } - return it.current; - } - - E get last { - Iterator it = iterator; - if (!it.moveNext()) { - throw IterableElementError.noElement(); - } - E result; - do { - result = it.current; - } while(it.moveNext()); - return result; - } - - E get single { - Iterator it = iterator; - if (!it.moveNext()) throw IterableElementError.noElement(); - E result = it.current; - if (it.moveNext()) throw IterableElementError.tooMany(); - return result; - } - - E firstWhere(bool test(E value), { E orElse() }) { - for (E element in this) { - if (test(element)) return element; - } - if (orElse != null) return orElse(); - throw IterableElementError.noElement(); - } - - E lastWhere(bool test(E value), { E orElse() }) { - E result = null; - bool foundMatching = false; - for (E element in this) { - if (test(element)) { - result = element; - foundMatching = true; - } - } - if (foundMatching) return result; - if (orElse != null) return orElse(); - throw IterableElementError.noElement(); - } - - E singleWhere(bool test(E value)) { - E result = null; - bool foundMatching = false; - for (E element in this) { - if (test(element)) { - if (foundMatching) { - throw IterableElementError.tooMany(); - } - result = element; - foundMatching = true; - } - } - if (foundMatching) return result; - throw IterableElementError.noElement(); - } - - E elementAt(int index) { - if (index is! int) throw new ArgumentError.notNull("index"); - RangeError.checkNotNegative(index, "index"); - int elementIndex = 0; - for (E element in this) { - if (index == elementIndex) return element; - elementIndex++; - } - throw new RangeError.index(index, this, "index", null, elementIndex); - } - - /** - * Returns a string representation of (some of) the elements of `this`. - * - * Elements are represented by their own `toString` results. - * - * The representation always contains the first three elements. - * If there are less than a hundred elements in the iterable, it also - * contains the last two elements. - * - * If the resulting string isn't above 80 characters, more elements are - * included from the start of the iterable. - * - * The conversion may omit calling `toString` on some elements if they - * are known to not occur in the output, and it may stop iterating after - * a hundred elements. - */ - String toString() => iterableToShortString(this, '(', ')'); - /** * Convert an `Iterable` to a string like [IterableBase.toString]. * @@ -470,131 +269,131 @@ abstract class IterableBase implements Iterable { buffer.write(rightDelimiter); return buffer.toString(); } +} - /** A set used to identify cyclic lists during toString() calls. */ - static final List _toStringVisiting = []; +/** A set used to identify cyclic lists during toString() calls. */ +final List _toStringVisiting = []; - /** Check if we are currently visiting `o` in a toString call. */ - static bool _isToStringVisiting(Object o) { - for (int i = 0; i < _toStringVisiting.length; i++) { - if (identical(o, _toStringVisiting[i])) return true; - } - return false; +/** Check if we are currently visiting `o` in a toString call. */ +bool _isToStringVisiting(Object o) { + for (int i = 0; i < _toStringVisiting.length; i++) { + if (identical(o, _toStringVisiting[i])) return true; + } + return false; +} + +/** + * Convert elments of [iterable] to strings and store them in [parts]. + */ +void _iterablePartsToStrings(Iterable iterable, List parts) { + /* + * This is the complicated part of [iterableToShortString]. + * It is extracted as a separate function to avoid having too much code + * inside the try/finally. + */ + /// Try to stay below this many characters. + const int LENGTH_LIMIT = 80; + /// Always at least this many elements at the start. + const int HEAD_COUNT = 3; + /// Always at least this many elements at the end. + const int TAIL_COUNT = 2; + /// Stop iterating after this many elements. Iterables can be infinite. + const int MAX_COUNT = 100; + // Per entry length overhead. It's for ", " for all after the first entry, + // and for "(" and ")" for the initial entry. By pure luck, that's the same + // number. + const int OVERHEAD = 2; + const int ELLIPSIS_SIZE = 3; // "...".length. + + int length = 0; + int count = 0; + Iterator it = iterable.iterator; + // Initial run of elements, at least HEAD_COUNT, and then continue until + // passing at most LENGTH_LIMIT characters. + while (length < LENGTH_LIMIT || count < HEAD_COUNT) { + if (!it.moveNext()) return; + String next = "${it.current}"; + parts.add(next); + length += next.length + OVERHEAD; + count++; } - /** - * Convert elments of [iterable] to strings and store them in [parts]. - */ - static void _iterablePartsToStrings(Iterable iterable, List parts) { - /* - * This is the complicated part of [iterableToShortString]. - * It is extracted as a separate function to avoid having too much code - * inside the try/finally. - */ - /// Try to stay below this many characters. - const int LENGTH_LIMIT = 80; - /// Always at least this many elements at the start. - const int HEAD_COUNT = 3; - /// Always at least this many elements at the end. - const int TAIL_COUNT = 2; - /// Stop iterating after this many elements. Iterables can be infinite. - const int MAX_COUNT = 100; - // Per entry length overhead. It's for ", " for all after the first entry, - // and for "(" and ")" for the initial entry. By pure luck, that's the same - // number. - const int OVERHEAD = 2; - const int ELLIPSIS_SIZE = 3; // "...".length. + String penultimateString; + String ultimateString; - int length = 0; - int count = 0; - Iterator it = iterable.iterator; - // Initial run of elements, at least HEAD_COUNT, and then continue until - // passing at most LENGTH_LIMIT characters. - while (length < LENGTH_LIMIT || count < HEAD_COUNT) { - if (!it.moveNext()) return; - String next = "${it.current}"; - parts.add(next); - length += next.length + OVERHEAD; - count++; - } - - String penultimateString; - String ultimateString; - - // Find last two elements. One or more of them may already be in the - // parts array. Include their length in `length`. - var penultimate = null; - var ultimate = null; + // Find last two elements. One or more of them may already be in the + // parts array. Include their length in `length`. + var penultimate = null; + var ultimate = null; + if (!it.moveNext()) { + if (count <= HEAD_COUNT + TAIL_COUNT) return; + ultimateString = parts.removeLast(); + penultimateString = parts.removeLast(); + } else { + penultimate = it.current; + count++; if (!it.moveNext()) { - if (count <= HEAD_COUNT + TAIL_COUNT) return; - ultimateString = parts.removeLast(); + if (count <= HEAD_COUNT + 1) { + parts.add("$penultimate"); + return; + } + ultimateString = "$penultimate"; penultimateString = parts.removeLast(); + length += ultimateString.length + OVERHEAD; } else { - penultimate = it.current; + ultimate = it.current; count++; - if (!it.moveNext()) { - if (count <= HEAD_COUNT + 1) { - parts.add("$penultimate"); - return; - } - ultimateString = "$penultimate"; - penultimateString = parts.removeLast(); - length += ultimateString.length + OVERHEAD; - } else { + // Then keep looping, keeping the last two elements in variables. + assert(count < MAX_COUNT); + while (it.moveNext()) { + penultimate = ultimate; ultimate = it.current; count++; - // Then keep looping, keeping the last two elements in variables. - assert(count < MAX_COUNT); - while (it.moveNext()) { - penultimate = ultimate; - ultimate = it.current; - count++; - if (count > MAX_COUNT) { - // If we haven't found the end before MAX_COUNT, give up. - // This cannot happen in the code above because each entry - // increases length by at least two, so there is no way to - // visit more than ~40 elements before this loop. + if (count > MAX_COUNT) { + // If we haven't found the end before MAX_COUNT, give up. + // This cannot happen in the code above because each entry + // increases length by at least two, so there is no way to + // visit more than ~40 elements before this loop. - // Remove any surplus elements until length, including ", ...)", - // is at most LENGTH_LIMIT. - while (length > LENGTH_LIMIT - ELLIPSIS_SIZE - OVERHEAD && - count > HEAD_COUNT) { - length -= parts.removeLast().length + OVERHEAD; - count--; - } - parts.add("..."); - return; + // Remove any surplus elements until length, including ", ...)", + // is at most LENGTH_LIMIT. + while (length > LENGTH_LIMIT - ELLIPSIS_SIZE - OVERHEAD && + count > HEAD_COUNT) { + length -= parts.removeLast().length + OVERHEAD; + count--; } + parts.add("..."); + return; } - penultimateString = "$penultimate"; - ultimateString = "$ultimate"; - length += - ultimateString.length + penultimateString.length + 2 * OVERHEAD; } + penultimateString = "$penultimate"; + ultimateString = "$ultimate"; + length += + ultimateString.length + penultimateString.length + 2 * OVERHEAD; } + } - // If there is a gap between the initial run and the last two, - // prepare to add an ellipsis. - String elision = null; - if (count > parts.length + TAIL_COUNT) { + // If there is a gap between the initial run and the last two, + // prepare to add an ellipsis. + String elision = null; + if (count > parts.length + TAIL_COUNT) { + elision = "..."; + length += ELLIPSIS_SIZE + OVERHEAD; + } + + // If the last two elements were very long, and we have more than + // HEAD_COUNT elements in the initial run, drop some to make room for + // the last two. + while (length > LENGTH_LIMIT && parts.length > HEAD_COUNT) { + length -= parts.removeLast().length + OVERHEAD; + if (elision == null) { elision = "..."; length += ELLIPSIS_SIZE + OVERHEAD; } - - // If the last two elements were very long, and we have more than - // HEAD_COUNT elements in the initial run, drop some to make room for - // the last two. - while (length > LENGTH_LIMIT && parts.length > HEAD_COUNT) { - length -= parts.removeLast().length + OVERHEAD; - if (elision == null) { - elision = "..."; - length += ELLIPSIS_SIZE + OVERHEAD; - } - } - if (elision != null) { - parts.add(elision); - } - parts.add(penultimateString); - parts.add(ultimateString); } + if (elision != null) { + parts.add(elision); + } + parts.add(penultimateString); + parts.add(ultimateString); } diff --git a/sdk/lib/collection/linked_list.dart b/sdk/lib/collection/linked_list.dart index 5bff429b98b..e2139c012d2 100644 --- a/sdk/lib/collection/linked_list.dart +++ b/sdk/lib/collection/linked_list.dart @@ -29,7 +29,7 @@ part of dart.collection; * and a constant time length getter. */ class LinkedList> - extends IterableBase + extends Iterable implements _LinkedListLink { int _modificationCount = 0; diff --git a/sdk/lib/collection/maps.dart b/sdk/lib/collection/maps.dart index c0a411d4c89..7945e7ea643 100644 --- a/sdk/lib/collection/maps.dart +++ b/sdk/lib/collection/maps.dart @@ -111,7 +111,7 @@ abstract class UnmodifiableMapBase = * It accesses the values by iterating over the keys of the map, and using the * map's `operator[]` to lookup the keys. */ -class _MapBaseValueIterable extends IterableBase +class _MapBaseValueIterable extends Iterable implements EfficientLength { final Map _map; _MapBaseValueIterable(this._map); @@ -285,11 +285,11 @@ class Maps { */ static String mapToString(Map m) { // Reuse the list in IterableBase for detecting toString cycles. - if (IterableBase._isToStringVisiting(m)) { return '{...}'; } + if (_isToStringVisiting(m)) { return '{...}'; } var result = new StringBuffer(); try { - IterableBase._toStringVisiting.add(m); + _toStringVisiting.add(m); result.write('{'); bool first = true; m.forEach((k, v) { @@ -303,8 +303,8 @@ class Maps { }); result.write('}'); } finally { - assert(identical(IterableBase._toStringVisiting.last, m)); - IterableBase._toStringVisiting.removeLast(); + assert(identical(_toStringVisiting.last, m)); + _toStringVisiting.removeLast(); } return result.toString(); diff --git a/sdk/lib/collection/queue.dart b/sdk/lib/collection/queue.dart index c2f4bd5874c..ff17309b2f1 100644 --- a/sdk/lib/collection/queue.dart +++ b/sdk/lib/collection/queue.dart @@ -256,7 +256,7 @@ class _DoubleLinkedQueueSentinel extends _DoubleLinkedQueueEntry { * * Allows constant time add, remove-at-ends and peek operations. */ -class DoubleLinkedQueue extends IterableBase implements Queue { +class DoubleLinkedQueue extends Iterable implements Queue { _DoubleLinkedQueueSentinel _sentinel; int _elementCount = 0; @@ -440,7 +440,7 @@ class _DoubleLinkedQueueIterator implements Iterator { * * The structure is efficient for any queue or stack usage. */ -class ListQueue extends IterableBase implements Queue { +class ListQueue extends Iterable implements Queue { static const int _INITIAL_CAPACITY = 8; List _table; int _head; diff --git a/sdk/lib/collection/splay_tree.dart b/sdk/lib/collection/splay_tree.dart index b9c1994381c..b5fcb93876f 100644 --- a/sdk/lib/collection/splay_tree.dart +++ b/sdk/lib/collection/splay_tree.dart @@ -599,8 +599,8 @@ abstract class _SplayTreeIterator implements Iterator { T _getValue(_SplayTreeNode node); } -class _SplayTreeKeyIterable extends IterableBase - implements EfficientLength { +class _SplayTreeKeyIterable extends Iterable + implements EfficientLength { _SplayTree _tree; _SplayTreeKeyIterable(this._tree); int get length => _tree._count; @@ -617,7 +617,7 @@ class _SplayTreeKeyIterable extends IterableBase } } -class _SplayTreeValueIterable extends IterableBase +class _SplayTreeValueIterable extends Iterable implements EfficientLength { SplayTreeMap _map; _SplayTreeValueIterable(this._map); diff --git a/sdk/lib/core/iterable.dart b/sdk/lib/core/iterable.dart index 00d08212f95..dbc8c55d3ca 100644 --- a/sdk/lib/core/iterable.dart +++ b/sdk/lib/core/iterable.dart @@ -145,7 +145,7 @@ abstract class Iterable { * on any element where the result isn't needed. * For example, [elementAt] may call `f` only once. */ - Iterable map(f(E element)); + Iterable map(f(E element)) => new MappedIterable(this, f); /** * Returns a new lazy [Iterable] with all elements that satisfy the @@ -160,7 +160,7 @@ abstract class Iterable { * multiple times over the returned [Iterable] will invoke the supplied * function [test] multiple times on the same element. */ - Iterable where(bool test(E element)); + Iterable where(bool f(E element)) => new WhereIterable(this, f); /** * Expands each element of this [Iterable]into zero or more elements. @@ -171,7 +171,8 @@ abstract class Iterable { * The returned [Iterable] is lazy, and calls [f] for each element * of this every time it's iterated. */ - Iterable expand(Iterable f(E element)); + Iterable expand(Iterable f(E element)) => + new ExpandIterable(this, f); /** * Returns true if the collection contains an element equal to [element]. @@ -189,13 +190,21 @@ abstract class Iterable { * Likewise the `Iterable` returned by a [Map.keys] call * should use the same equality that the `Map` uses for keys. */ - bool contains(Object element); + bool contains(Object element) { + for (E e in this) { + if (e == element) return true; + } + return false; + } + /** * Applies the function [f] to each element of this collection in iteration * order. */ - void forEach(void f(E element)); + void forEach(void f(E element)) { + for (E element in this) f(element); + } /** * Reduces a collection to a single value by iteratively combining elements @@ -219,7 +228,17 @@ abstract class Iterable { * iterable.reduce((value, element) => value + element); * */ - E reduce(E combine(E value, E element)); + E reduce(E combine(E value, E element)) { + Iterator iterator = this.iterator; + if (!iterator.moveNext()) { + throw IterableElementError.noElement(); + } + E value = iterator.current; + while (iterator.moveNext()) { + value = combine(value, iterator.current); + } + return value; + } /** * Reduces a collection to a single value by iteratively combining each @@ -241,7 +260,11 @@ abstract class Iterable { * */ dynamic fold(var initialValue, - dynamic combine(var previousValue, E element)); + dynamic combine(var previousValue, E element)) { + var value = initialValue; + for (E element in this) value = combine(value, element); + return value; + } /** * Checks whether every element of this iterable satisfies [test]. @@ -249,7 +272,12 @@ abstract class Iterable { * Checks every element in iteration order, and returns `false` if * any of them make [test] return `false`, otherwise returns `true`. */ - bool every(bool test(E element)); + bool every(bool f(E element)) { + for (E element in this) { + if (!f(element)) return false; + } + return true; + } /** * Converts each element to a [String] and concatenates the strings. @@ -260,18 +288,36 @@ abstract class Iterable { * [separator] string interleaved between the elements. */ String join([String separator = ""]) { + Iterator iterator = this.iterator; + if (!iterator.moveNext()) return ""; StringBuffer buffer = new StringBuffer(); - buffer.writeAll(this, separator); + if (separator == null || separator == "") { + do { + buffer.write("${iterator.current}"); + } while (iterator.moveNext()); + } else { + buffer.write("${iterator.current}"); + while (iterator.moveNext()) { + buffer.write(separator); + buffer.write("${iterator.current}"); + } + } return buffer.toString(); } + /** * Checks whether any element of this iterable satisfies [test]. * * Checks every element in iteration order, and returns `true` if * any of them make [test] return `true`, otherwise returns false. */ - bool any(bool test(E element)); + bool any(bool f(E element)) { + for (E element in this) { + if (f(element)) return true; + } + return false; + } /** * Creates a [List] containing the elements of this [Iterable]. @@ -279,7 +325,8 @@ abstract class Iterable { * The elements are in iteration order. * The list is fixed-length if [growable] is false. */ - List toList({ bool growable: true }); + List toList({ bool growable: true }) => + new List.from(this, growable: growable); /** * Creates a [Set] containing the same elements as this iterable. @@ -290,7 +337,7 @@ abstract class Iterable { * The order of the elements in the set is not guaranteed to be the same * as for the iterable. */ - Set toSet(); + Set toSet() => new Set.from(this); /** * Returns the number of elements in [this]. @@ -299,23 +346,31 @@ abstract class Iterable { * therefore be slow. * Some iterables have a more efficient way to find the number of elements. */ - int get length; + int get length { + assert(this is! EfficientLength); + int count = 0; + Iterator it = iterator; + while (it.moveNext()) { + count++; + } + return count; + } /** * Returns `true` if there are no elements in this collection. * * May be computed by checking if `iterator.moveNext()` returns `false`. */ - bool get isEmpty; + bool get isEmpty => !iterator.moveNext(); /** * Returns true if there is at least one element in this collection. * * May be computed by checking if `iterator.moveNext()` returns `true`. */ - bool get isNotEmpty; + bool get isNotEmpty => !isEmpty; - /** + /** * Returns a lazy iterable of the [count] first elements of this iterable. * * The returned `Iterable` may contain fewer than `count` elements, if `this` @@ -326,7 +381,9 @@ abstract class Iterable { * * The `count` must not be negative. */ - Iterable take(int count); + Iterable take(int n) { + return new TakeIterable(this, n); + } /** * Returns a lazy iterable of the leading elements satisfying [test]. @@ -338,7 +395,9 @@ abstract class Iterable { * element is found where `test(element)` is false. At that point, * the returned iterable stops (its `moveNext()` returns false). */ - Iterable takeWhile(bool test(E value)); + Iterable takeWhile(bool test(E value)) { + return new TakeWhileIterable(this, test); + } /** * Returns an Iterable that provides all but the first [count] elements. @@ -352,7 +411,9 @@ abstract class Iterable { * * The `count` must not be negative. */ - Iterable skip(int count); + Iterable skip(int n) { + return new SkipIterable(this, n); + } /** * Returns an Iterable that skips leading elements while [test] is satisfied. @@ -366,7 +427,9 @@ abstract class Iterable { * otherwise it iterates the remaining elements in their original order, * starting with the first element for which `test(element)` returns false, */ - Iterable skipWhile(bool test(E value)); + Iterable skipWhile(bool test(E value)) { + return new SkipWhileIterable(this, test); + } /** * Returns the first element. @@ -375,7 +438,13 @@ abstract class Iterable { * Otherwise returs the first element in the iteration order, * equivalent to `(iterator..moveNext())..current`. */ - E get first; + E get first { + Iterator it = iterator; + if (!it.moveNext()) { + throw IterableElementError.noElement(); + } + return it.current; + } /** * Returns the last element. @@ -387,14 +456,30 @@ abstract class Iterable { * (for example a list can directly access the last element, * without iterating through the previous ones). */ - E get last; + E get last { + Iterator it = iterator; + if (!it.moveNext()) { + throw IterableElementError.noElement(); + } + E result; + do { + result = it.current; + } while(it.moveNext()); + return result; + } /** * Checks that this iterable has only one element, and returns that element. * * Throws a [StateError] if `this` is empty or has more than one element. */ - E get single; + E get single { + Iterator it = iterator; + if (!it.moveNext()) throw IterableElementError.noElement(); + E result = it.current; + if (it.moveNext()) throw IterableElementError.tooMany(); + return result; + } /** * Returns the first element that satisfies the given predicate [test]. @@ -405,7 +490,13 @@ abstract class Iterable { * function is returned. * If [orElse] is omitted, it defaults to throwing a [StateError]. */ - E firstWhere(bool test(E element), { E orElse() }); + E firstWhere(bool test(E element), { E orElse() }) { + for (E element in this) { + if (test(element)) return element; + } + if (orElse != null) return orElse(); + throw IterableElementError.noElement(); + } /** * Returns the last element that satisfies the given predicate [test]. @@ -421,7 +512,19 @@ abstract class Iterable { * function is returned. * If [orElse] is omitted, it defaults to throwing a [StateError]. */ - E lastWhere(bool test(E element), {E orElse()}); + E lastWhere(bool test(E element), {E orElse()}) { + E result = null; + bool foundMatching = false; + for (E element in this) { + if (test(element)) { + result = element; + foundMatching = true; + } + } + if (foundMatching) return result; + if (orElse != null) return orElse(); + throw IterableElementError.noElement(); + } /** * Returns the single element that satisfies [test]. @@ -431,7 +534,21 @@ abstract class Iterable { * Otherwise, if there are no matching elements, or if there is more than * one matching element, a [StateError] is thrown. */ - E singleWhere(bool test(E element)); + E singleWhere(bool test(E element)) { + E result = null; + bool foundMatching = false; + for (E element in this) { + if (test(element)) { + if (foundMatching) { + throw IterableElementError.tooMany(); + } + result = element; + foundMatching = true; + } + } + if (foundMatching) return result; + throw IterableElementError.noElement(); + } /** * Returns the [index]th element. @@ -444,12 +561,39 @@ abstract class Iterable { * first `index` elements and returning the next. * Some iterable may have more efficient ways to find the element. */ - E elementAt(int index); + E elementAt(int index) { + if (index is! int) throw new ArgumentError.notNull("index"); + RangeError.checkNotNegative(index, "index"); + int elementIndex = 0; + for (E element in this) { + if (index == elementIndex) return element; + elementIndex++; + } + throw new RangeError.index(index, this, "index", null, elementIndex); + } + + /** + * Returns a string representation of (some of) the elements of `this`. + * + * Elements are represented by their own `toString` results. + * + * The default representation always contains the first three elements. + * If there are less than a hundred elements in the iterable, it also + * contains the last two elements. + * + * If the resulting string isn't above 80 characters, more elements are + * included from the start of the iterable. + * + * The conversion may omit calling `toString` on some elements if they + * are known to not occur in the output, and it may stop iterating after + * a hundred elements. + */ + String toString() => IterableBase.iterableToShortString(this, '(', ')'); } typedef E _Generator(int index); -class _GeneratorIterable extends IterableBase +class _GeneratorIterable extends Iterable implements EfficientLength { final int _start; final int _end; diff --git a/sdk/lib/core/set.dart b/sdk/lib/core/set.dart index a52fa53ca17..2c6b52417de 100644 --- a/sdk/lib/core/set.dart +++ b/sdk/lib/core/set.dart @@ -31,7 +31,7 @@ part of dart.core; * iterating either the set itself or any [Iterable] that is backed by the set, * such as the ones returned by methods like [where] and [map]. */ -abstract class Set extends IterableBase implements EfficientLength { +abstract class Set extends Iterable implements EfficientLength { /** * Creates an empty [Set]. * diff --git a/sdk/lib/core/string.dart b/sdk/lib/core/string.dart index c92ca9f50e8..599ad0f0dda 100644 --- a/sdk/lib/core/string.dart +++ b/sdk/lib/core/string.dart @@ -603,7 +603,7 @@ abstract class String implements Comparable, Pattern { /** * The runes (integer Unicode code points) of a [String]. */ -class Runes extends IterableBase { +class Runes extends Iterable { final String string; Runes(this.string); diff --git a/sdk/lib/internal/iterable.dart b/sdk/lib/internal/iterable.dart index bc80b88ba40..47c94f8b0be 100644 --- a/sdk/lib/internal/iterable.dart +++ b/sdk/lib/internal/iterable.dart @@ -24,7 +24,7 @@ abstract class EfficientLength { * All other methods are implemented in terms of [length] and [elementAt], * including [iterator]. */ -abstract class ListIterable extends IterableBase +abstract class ListIterable extends Iterable implements EfficientLength { int get length; E elementAt(int i); @@ -346,7 +346,7 @@ class ListIterator implements Iterator { typedef T _Transformation(S value); -class MappedIterable extends IterableBase { +class MappedIterable extends Iterable { final Iterable _iterable; final _Transformation _f; @@ -416,7 +416,7 @@ class MappedListIterable extends ListIterable typedef bool _ElementPredicate(E element); -class WhereIterable extends IterableBase { +class WhereIterable extends Iterable { final Iterable _iterable; final _ElementPredicate _f; @@ -445,7 +445,7 @@ class WhereIterator extends Iterator { typedef Iterable _ExpandFunction(S sourceElement); -class ExpandIterable extends IterableBase { +class ExpandIterable extends Iterable { final Iterable _iterable; final _ExpandFunction _f; @@ -488,7 +488,7 @@ class ExpandIterator implements Iterator { } } -class TakeIterable extends IterableBase { +class TakeIterable extends Iterable { final Iterable _iterable; final int _takeCount; @@ -545,7 +545,7 @@ class TakeIterator extends Iterator { } } -class TakeWhileIterable extends IterableBase { +class TakeWhileIterable extends Iterable { final Iterable _iterable; final _ElementPredicate _f; @@ -578,7 +578,7 @@ class TakeWhileIterator extends Iterator { } } -class SkipIterable extends IterableBase { +class SkipIterable extends Iterable { final Iterable _iterable; final int _skipCount; @@ -638,7 +638,7 @@ class SkipIterator extends Iterator { E get current => _iterator.current; } -class SkipWhileIterable extends IterableBase { +class SkipWhileIterable extends Iterable { final Iterable _iterable; final _ElementPredicate _f; @@ -672,7 +672,7 @@ class SkipWhileIterator extends Iterator { /** * The always empty [Iterable]. */ -class EmptyIterable extends IterableBase implements EfficientLength { +class EmptyIterable extends Iterable implements EfficientLength { const EmptyIterable(); Iterator get iterator => const EmptyIterator();