| // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
| // for details. All rights reserved. Use of this source code is governed by a |
| // BSD-style license that can be found in the LICENSE file. |
| |
| part of dart._internal; |
| |
| // Casting wrappers for collection classes. |
| |
| abstract class _CastIterableBase<S, T> extends Iterable<T> { |
| Iterable<S> get _source; |
| |
| Iterator<T> get iterator => new CastIterator<S, T>(_source.iterator); |
| |
| // The following members use the default implementation on the |
| // throwing iterator. These are all operations that have no more efficient |
| // implementation than visiting every element in order, |
| // or that has no more efficient way to get the correct type (toList, toSet). |
| // |
| // * map |
| // * where |
| // * expand |
| // * forEach |
| // * reduce |
| // * fold |
| // * every |
| // * any |
| // * join |
| // * toList |
| // * toSet |
| // * skipWhile |
| // * takeWhile |
| // * firstWhere |
| // * singleWhere |
| |
| int get length => _source.length; |
| bool get isEmpty => _source.isEmpty; |
| bool get isNotEmpty => _source.isNotEmpty; |
| |
| Iterable<T> skip(int count) => new CastIterable<S, T>(_source.skip(count)); |
| Iterable<T> take(int count) => new CastIterable<S, T>(_source.take(count)); |
| |
| T elementAt(int index) => _source.elementAt(index) as T; |
| T get first => _source.first as T; |
| T get last => _source.last as T; |
| T get single => _source.single as T; |
| |
| bool contains(Object other) => _source.contains(other); |
| |
| // Might be implemented by testing backwards from the end, |
| // so use the _source's implementation. |
| T lastWhere(bool test(T element), {T orElse()}) => |
| _source.lastWhere((S element) => test(element as T), |
| orElse: (orElse == null) ? null : () => orElse() as S) as T; |
| |
| String toString() => _source.toString(); |
| } |
| |
| class CastIterator<S, T> implements Iterator<T> { |
| Iterator<S> _source; |
| CastIterator(this._source); |
| bool moveNext() => _source.moveNext(); |
| T get current => _source.current as T; |
| } |
| |
| class CastIterable<S, T> extends _CastIterableBase<S, T> { |
| final Iterable<S> _source; |
| |
| CastIterable._(this._source); |
| |
| factory CastIterable(Iterable<S> source) { |
| if (source is EfficientLengthIterable<S>) { |
| return new _EfficientLengthCastIterable<S, T>(source); |
| } |
| return new CastIterable<S, T>._(source); |
| } |
| |
| Iterable<R> cast<R>() => new CastIterable<S, R>(_source); |
| } |
| |
| class _EfficientLengthCastIterable<S, T> extends CastIterable<S, T> |
| implements EfficientLengthIterable<T> { |
| _EfficientLengthCastIterable(EfficientLengthIterable<S> source) |
| : super._(source); |
| } |
| |
| abstract class _CastListBase<S, T> extends _CastIterableBase<S, T> |
| with ListMixin<T> { |
| List<S> get _source; |
| |
| // Using the default implementation from ListMixin: |
| // * reversed |
| // * shuffle |
| // * indexOf |
| // * lastIndexOf |
| // * clear |
| // * sublist |
| // * asMap |
| |
| T operator [](int index) => _source[index] as T; |
| |
| void operator []=(int index, T value) { |
| _source[index] = value as S; |
| } |
| |
| void set length(int length) { |
| _source.length = length; |
| } |
| |
| void add(T value) { |
| _source.add(value as S); |
| } |
| |
| void addAll(Iterable<T> values) { |
| _source.addAll(new CastIterable<T, S>(values)); |
| } |
| |
| void sort([int compare(T v1, T v2)]) { |
| _source.sort((S v1, S v2) => compare(v1 as T, v2 as T)); |
| } |
| |
| void shuffle([Random random]) { |
| _source.shuffle(random); |
| } |
| |
| void insert(int index, T element) { |
| _source.insert(index, element as S); |
| } |
| |
| void insertAll(int index, Iterable<T> elements) { |
| _source.insertAll(index, new CastIterable<T, S>(elements)); |
| } |
| |
| void setAll(int index, Iterable<T> elements) { |
| _source.setAll(index, new CastIterable<T, S>(elements)); |
| } |
| |
| bool remove(Object value) => _source.remove(value); |
| |
| T removeAt(int index) => _source.removeAt(index) as T; |
| |
| T removeLast() => _source.removeLast() as T; |
| |
| void removeWhere(bool test(T element)) { |
| _source.removeWhere((S element) => test(element as T)); |
| } |
| |
| void retainWhere(bool test(T element)) { |
| _source.retainWhere((S element) => test(element as T)); |
| } |
| |
| Iterable<T> getRange(int start, int end) => |
| new CastIterable<S, T>(_source.getRange(start, end)); |
| |
| void setRange(int start, int end, Iterable<T> iterable, [int skipCount = 0]) { |
| _source.setRange(start, end, new CastIterable<T, S>(iterable), skipCount); |
| } |
| |
| void removeRange(int start, int end) { |
| _source.removeRange(start, end); |
| } |
| |
| void fillRange(int start, int end, [T fillValue]) { |
| _source.fillRange(start, end, fillValue as S); |
| } |
| |
| void replaceRange(int start, int end, Iterable<T> replacement) { |
| _source.replaceRange(start, end, new CastIterable<T, S>(replacement)); |
| } |
| } |
| |
| class CastList<S, T> extends _CastListBase<S, T> { |
| final List<S> _source; |
| CastList(this._source); |
| |
| List<R> cast<R>() => new CastList<S, R>(_source); |
| } |
| |
| class CastSet<S, T> extends _CastIterableBase<S, T> implements Set<T> { |
| final Set<S> _source; |
| |
| /// Creates a new empty set of the same *kind* as [_source], |
| /// but with `<R>` as type argument. |
| /// Used by [toSet] and [union]. |
| final Set<R> Function<R>() _emptySet; |
| |
| CastSet(this._source, this._emptySet); |
| |
| static Set<R> _defaultEmptySet<R>() => new Set<R>(); |
| |
| Set<R> cast<R>() { |
| Set<Object> self = this; |
| if (self is Set<R>) return self; |
| return this.retype<R>(); |
| } |
| |
| Set<R> retype<R>() => new CastSet<S, R>(_source, _emptySet); |
| |
| bool add(T value) => _source.add(value as S); |
| |
| void addAll(Iterable<T> elements) { |
| _source.addAll(new CastIterable<T, S>(elements)); |
| } |
| |
| bool remove(Object object) => _source.remove(object); |
| |
| void removeAll(Iterable<Object> objects) { |
| _source.removeAll(objects); |
| } |
| |
| void retainAll(Iterable<Object> objects) { |
| _source.retainAll(objects); |
| } |
| |
| void removeWhere(bool test(T element)) { |
| _source.removeWhere((S element) => test(element as T)); |
| } |
| |
| void retainWhere(bool test(T element)) { |
| _source.retainWhere((S element) => test(element as T)); |
| } |
| |
| bool containsAll(Iterable<Object> objects) => _source.containsAll(objects); |
| |
| Set<T> intersection(Set<Object> other) { |
| if (_emptySet != null) return _conditionalAdd(other, true); |
| return new CastSet<S, T>(_source.intersection(other), null); |
| } |
| |
| Set<T> difference(Set<Object> other) { |
| if (_emptySet != null) return _conditionalAdd(other, false); |
| return new CastSet<S, T>(_source.difference(other), null); |
| } |
| |
| Set<T> _conditionalAdd(Set<Object> other, bool otherContains) { |
| Set<T> result = (_emptySet == null) ? new Set<T>() : _emptySet<T>(); |
| for (var element in _source) { |
| T castElement = element as T; |
| if (otherContains == other.contains(castElement)) result.add(castElement); |
| } |
| return result; |
| } |
| |
| Set<T> union(Set<T> other) => _clone()..addAll(other); |
| |
| void clear() { |
| _source.clear(); |
| } |
| |
| Set<T> _clone() { |
| Set<T> result = (_emptySet == null) ? new Set<T>() : _emptySet<T>(); |
| result.addAll(this); |
| return result; |
| } |
| |
| Set<T> toSet() => _clone(); |
| |
| T lookup(Object key) => _source.lookup(key) as T; |
| } |
| |
| abstract class _CastQueueMixin<S, T> implements Queue<T> { |
| Queue<S> get _source; |
| |
| T removeFirst() => _source.removeFirst() as T; |
| T removeLast() => _source.removeLast() as T; |
| |
| @deprecated |
| void add(T value) { |
| _source.add(value as S); |
| } |
| |
| void addFirst(T value) { |
| _source.addFirst(value as S); |
| } |
| |
| void addLast(T value) { |
| _source.addLast(value as S); |
| } |
| |
| bool remove(Object other) => _source.remove(other); |
| void addAll(Iterable<T> elements) { |
| _source.addAll(new CastIterable<T, S>(elements)); |
| } |
| |
| void removeWhere(bool test(T element)) { |
| _source.removeWhere((S element) => test(element as T)); |
| } |
| |
| void retainWhere(bool test(T element)) { |
| _source.retainWhere((S element) => test(element as T)); |
| } |
| |
| void clear() { |
| _source.clear(); |
| } |
| } |
| |
| class CastMap<SK, SV, K, V> extends MapBase<K, V> { |
| final Map<SK, SV> _source; |
| |
| CastMap(this._source); |
| |
| Map<RK, RV> cast<RK, RV>() => new CastMap<SK, SV, RK, RV>(_source); |
| |
| bool containsValue(Object value) => _source.containsValue(value); |
| |
| bool containsKey(Object key) => _source.containsKey(key); |
| |
| V operator [](Object key) => _source[key] as V; |
| |
| void operator []=(K key, V value) { |
| _source[key as SK] = value as SV; |
| } |
| |
| V putIfAbsent(K key, V ifAbsent()) => _source.putIfAbsent( |
| key as SK, (ifAbsent == null) ? null : () => ifAbsent() as SV) as V; |
| |
| void addAll(Map<K, V> other) { |
| _source.addAll(new CastMap<K, V, SK, SV>(other)); |
| } |
| |
| V remove(Object key) => _source.remove(key) as V; |
| |
| void clear() { |
| _source.clear(); |
| } |
| |
| void forEach(void f(K key, V value)) { |
| _source.forEach((SK key, SV value) { |
| f(key as K, value as V); |
| }); |
| } |
| |
| Iterable<K> get keys => new CastIterable<SK, K>(_source.keys); |
| |
| Iterable<V> get values => new CastIterable<SV, V>(_source.values); |
| |
| int get length => _source.length; |
| |
| bool get isEmpty => _source.isEmpty; |
| |
| bool get isNotEmpty => _source.isNotEmpty; |
| |
| V update(K key, V update(V value), {V ifAbsent()}) { |
| return _source.update(key as SK, (SV value) => update(value as V) as SV, |
| ifAbsent: (ifAbsent == null) ? null : () => ifAbsent() as SV) as V; |
| } |
| |
| void updateAll(V update(K key, V value)) { |
| _source.updateAll((SK key, SV value) => update(key as K, value as V) as SV); |
| } |
| |
| Iterable<MapEntry<K, V>> get entries { |
| return _source.entries.map<MapEntry<K, V>>( |
| (MapEntry<SK, SV> e) => new MapEntry<K, V>(e.key as K, e.value as V)); |
| } |
| |
| void addEntries(Iterable<MapEntry<K, V>> entries) { |
| for (var entry in entries) { |
| _source[entry.key as SK] = entry.value as SV; |
| } |
| } |
| |
| void removeWhere(bool test(K key, V value)) { |
| _source.removeWhere((SK key, SV value) => test(key as K, value as V)); |
| } |
| } |
| |
| class CastQueue<S, T> extends _CastIterableBase<S, T> |
| with _CastQueueMixin<S, T> { |
| final Queue<S> _source; |
| CastQueue(this._source); |
| Queue<R> cast<R>() { |
| Queue<Object> self = this; |
| if (self is Queue<R>) return self; |
| return retype<R>(); |
| } |
| |
| Queue<R> retype<R>() => new CastQueue<S, R>(_source); |
| } |
| |
| // TODO(lrn): Use when ListQueue implements List. |
| // class CastListQueue<S, T> |
| // extends _CastListBase<S, T> with _CastQueueMixin<S, T> |
| // implements ListQueue<T> { |
| // final ListQueue<S> _source; |
| // CastListQueue(this._source); |
| // ListQueue<R> cast<R>() => new CastListQueue<S, R>(_source); |
| // } |