// Copyright (c) 2013, 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. import 'dart:collection'; import 'dart:math' as math; import 'unmodifiable_wrappers.dart'; /// A base class for delegating iterables. /// /// Subclasses can provide a [_base] that should be delegated to. Unlike /// [DelegatingIterable], this allows the base to be created on demand. abstract class _DelegatingIterableBase implements Iterable { Iterable get _base; const _DelegatingIterableBase(); @override bool any(bool Function(E) test) => _base.any(test); @override Iterable cast() => _base.cast(); @override bool contains(Object? element) => _base.contains(element); @override E elementAt(int index) => _base.elementAt(index); @override bool every(bool Function(E) test) => _base.every(test); @override Iterable expand(Iterable Function(E) f) => _base.expand(f); @override E get first => _base.first; @override E firstWhere(bool Function(E) test, {E Function()? orElse}) => _base.firstWhere(test, orElse: orElse); @override T fold(T initialValue, T Function(T previousValue, E element) combine) => _base.fold(initialValue, combine); @override Iterable followedBy(Iterable other) => _base.followedBy(other); @override void forEach(void Function(E) f) => _base.forEach(f); @override bool get isEmpty => _base.isEmpty; @override bool get isNotEmpty => _base.isNotEmpty; @override Iterator get iterator => _base.iterator; @override String join([String separator = '']) => _base.join(separator); @override E get last => _base.last; @override E lastWhere(bool Function(E) test, {E Function()? orElse}) => _base.lastWhere(test, orElse: orElse); @override int get length => _base.length; @override Iterable map(T Function(E) f) => _base.map(f); @override E reduce(E Function(E value, E element) combine) => _base.reduce(combine); @Deprecated('Use cast instead') Iterable retype() => cast(); @override E get single => _base.single; @override E singleWhere(bool Function(E) test, {E Function()? orElse}) { return _base.singleWhere(test, orElse: orElse); } @override Iterable skip(int n) => _base.skip(n); @override Iterable skipWhile(bool Function(E) test) => _base.skipWhile(test); @override Iterable take(int n) => _base.take(n); @override Iterable takeWhile(bool Function(E) test) => _base.takeWhile(test); @override List toList({bool growable = true}) => _base.toList(growable: growable); @override Set toSet() => _base.toSet(); @override Iterable where(bool Function(E) test) => _base.where(test); @override Iterable whereType() => _base.whereType(); @override String toString() => _base.toString(); } /// An [Iterable] that delegates all operations to a base iterable. /// /// This class can be used to hide non-`Iterable` methods of an iterable object, /// or it can be extended to add extra functionality on top of an existing /// iterable object. class DelegatingIterable extends _DelegatingIterableBase { @override final Iterable _base; /// Creates a wrapper that forwards operations to [base]. const DelegatingIterable(Iterable base) : _base = base; /// Creates a wrapper that asserts the types of values in [base]. /// /// This soundly converts an [Iterable] without a generic type to an /// `Iterable` by asserting that its elements are instances of `E` whenever /// they're accessed. If they're not, it throws a [TypeError]. /// /// This forwards all operations to [base], so any changes in [base] will be /// reflected in `this`. If [base] is already an `Iterable`, it's returned /// unmodified. @Deprecated('Use iterable.cast instead.') static Iterable typed(Iterable base) => base.cast(); } /// A [List] that delegates all operations to a base list. /// /// This class can be used to hide non-`List` methods of a list object, or it /// can be extended to add extra functionality on top of an existing list /// object. class DelegatingList extends _DelegatingIterableBase implements List { @override final List _base; const DelegatingList(List base) : _base = base; /// Creates a wrapper that asserts the types of values in [base]. /// /// This soundly converts a [List] without a generic type to a `List` by /// asserting that its elements are instances of `E` whenever they're /// accessed. If they're not, it throws a [TypeError]. Note that even if an /// operation throws a [TypeError], it may still mutate the underlying /// collection. /// /// This forwards all operations to [base], so any changes in [base] will be /// reflected in `this`. If [base] is already a `List`, it's returned /// unmodified. @Deprecated('Use list.cast instead.') static List typed(List base) => base.cast(); @override E operator [](int index) => _base[index]; @override void operator []=(int index, E value) { _base[index] = value; } @override List operator +(List other) => _base + other; @override void add(E value) { _base.add(value); } @override void addAll(Iterable iterable) { _base.addAll(iterable); } @override Map asMap() => _base.asMap(); @override List cast() => _base.cast(); @override void clear() { _base.clear(); } @override void fillRange(int start, int end, [E? fillValue]) { _base.fillRange(start, end, fillValue); } @override set first(E value) { if (isEmpty) throw RangeError.index(0, this); this[0] = value; } @override Iterable getRange(int start, int end) => _base.getRange(start, end); @override int indexOf(E element, [int start = 0]) => _base.indexOf(element, start); @override int indexWhere(bool Function(E) test, [int start = 0]) => _base.indexWhere(test, start); @override void insert(int index, E element) { _base.insert(index, element); } @override void insertAll(int index, Iterable iterable) { _base.insertAll(index, iterable); } @override set last(E value) { if (isEmpty) throw RangeError.index(0, this); this[length - 1] = value; } @override int lastIndexOf(E element, [int? start]) => _base.lastIndexOf(element, start); @override int lastIndexWhere(bool Function(E) test, [int? start]) => _base.lastIndexWhere(test, start); @override set length(int newLength) { _base.length = newLength; } @override bool remove(Object? value) => _base.remove(value); @override E removeAt(int index) => _base.removeAt(index); @override E removeLast() => _base.removeLast(); @override void removeRange(int start, int end) { _base.removeRange(start, end); } @override void removeWhere(bool Function(E) test) { _base.removeWhere(test); } @override void replaceRange(int start, int end, Iterable iterable) { _base.replaceRange(start, end, iterable); } @override void retainWhere(bool Function(E) test) { _base.retainWhere(test); } @Deprecated('Use cast instead') @override List retype() => cast(); @override Iterable get reversed => _base.reversed; @override void setAll(int index, Iterable iterable) { _base.setAll(index, iterable); } @override void setRange(int start, int end, Iterable iterable, [int skipCount = 0]) { _base.setRange(start, end, iterable, skipCount); } @override void shuffle([math.Random? random]) { _base.shuffle(random); } @override void sort([int Function(E, E)? compare]) { _base.sort(compare); } @override List sublist(int start, [int? end]) => _base.sublist(start, end); } /// A [Set] that delegates all operations to a base set. /// /// This class can be used to hide non-`Set` methods of a set object, or it can /// be extended to add extra functionality on top of an existing set object. class DelegatingSet extends _DelegatingIterableBase implements Set { @override final Set _base; const DelegatingSet(Set base) : _base = base; /// Creates a wrapper that asserts the types of values in [base]. /// /// This soundly converts a [Set] without a generic type to a `Set` by /// asserting that its elements are instances of `E` whenever they're /// accessed. If they're not, it throws a [TypeError]. Note that even if an /// operation throws a [TypeError], it may still mutate the underlying /// collection. /// /// This forwards all operations to [base], so any changes in [base] will be /// reflected in `this`. If [base] is already a `Set`, it's returned /// unmodified. @Deprecated('Use set.cast instead.') static Set typed(Set base) => base.cast(); @override bool add(E value) => _base.add(value); @override void addAll(Iterable elements) { _base.addAll(elements); } @override Set cast() => _base.cast(); @override void clear() { _base.clear(); } @override bool containsAll(Iterable other) => _base.containsAll(other); @override Set difference(Set other) => _base.difference(other); @override Set intersection(Set other) => _base.intersection(other); @override E? lookup(Object? element) => _base.lookup(element); @override bool remove(Object? value) => _base.remove(value); @override void removeAll(Iterable elements) { _base.removeAll(elements); } @override void removeWhere(bool Function(E) test) { _base.removeWhere(test); } @override void retainAll(Iterable elements) { _base.retainAll(elements); } @Deprecated('Use cast instead') @override Set retype() => cast(); @override void retainWhere(bool Function(E) test) { _base.retainWhere(test); } @override Set union(Set other) => _base.union(other); @override Set toSet() => DelegatingSet(_base.toSet()); } /// A [Queue] that delegates all operations to a base queue. /// /// This class can be used to hide non-`Queue` methods of a queue object, or it /// can be extended to add extra functionality on top of an existing queue /// object. class DelegatingQueue extends _DelegatingIterableBase implements Queue { @override final Queue _base; const DelegatingQueue(Queue queue) : _base = queue; /// Creates a wrapper that asserts the types of values in [base]. /// /// This soundly converts a [Queue] without a generic type to a `Queue` by /// asserting that its elements are instances of `E` whenever they're /// accessed. If they're not, it throws a [TypeError]. Note that even if an /// operation throws a [TypeError], it may still mutate the underlying /// collection. /// /// This forwards all operations to [base], so any changes in [base] will be /// reflected in `this`. If [base] is already a `Queue`, it's returned /// unmodified. @Deprecated('Use queue.cast instead.') static Queue typed(Queue base) => base.cast(); @override void add(E value) { _base.add(value); } @override void addAll(Iterable iterable) { _base.addAll(iterable); } @override void addFirst(E value) { _base.addFirst(value); } @override void addLast(E value) { _base.addLast(value); } @override Queue cast() => _base.cast(); @override void clear() { _base.clear(); } @override bool remove(Object? object) => _base.remove(object); @override void removeWhere(bool Function(E) test) { _base.removeWhere(test); } @override void retainWhere(bool Function(E) test) { _base.retainWhere(test); } @Deprecated('Use cast instead') @override Queue retype() => cast(); @override E removeFirst() => _base.removeFirst(); @override E removeLast() => _base.removeLast(); } /// A [Map] that delegates all operations to a base map. /// /// This class can be used to hide non-`Map` methods of an object that extends /// `Map`, or it can be extended to add extra functionality on top of an /// existing map object. class DelegatingMap implements Map { final Map _base; const DelegatingMap(Map base) : _base = base; /// Creates a wrapper that asserts the types of keys and values in [base]. /// /// This soundly converts a [Map] without generic types to a `Map` by /// asserting that its keys are instances of `E` and its values are instances /// of `V` whenever they're accessed. If they're not, it throws a [TypeError]. /// Note that even if an operation throws a [TypeError], it may still mutate /// the underlying collection. /// /// This forwards all operations to [base], so any changes in [base] will be /// reflected in `this`. If [base] is already a `Map`, it's returned /// unmodified. @Deprecated('Use map.cast instead.') static Map typed(Map base) => base.cast(); @override V? operator [](Object? key) => _base[key]; @override void operator []=(K key, V value) { _base[key] = value; } @override void addAll(Map other) { _base.addAll(other); } @override void addEntries(Iterable> entries) { _base.addEntries(entries); } @override void clear() { _base.clear(); } @override Map cast() => _base.cast(); @override bool containsKey(Object? key) => _base.containsKey(key); @override bool containsValue(Object? value) => _base.containsValue(value); @override Iterable> get entries => _base.entries; @override void forEach(void Function(K, V) f) { _base.forEach(f); } @override bool get isEmpty => _base.isEmpty; @override bool get isNotEmpty => _base.isNotEmpty; @override Iterable get keys => _base.keys; @override int get length => _base.length; @override Map map(MapEntry Function(K, V) transform) => _base.map(transform); @override V putIfAbsent(K key, V Function() ifAbsent) => _base.putIfAbsent(key, ifAbsent); @override V? remove(Object? key) => _base.remove(key); @override void removeWhere(bool Function(K, V) test) => _base.removeWhere(test); @Deprecated('Use cast instead') Map retype() => cast(); @override Iterable get values => _base.values; @override String toString() => _base.toString(); @override V update(K key, V Function(V) update, {V Function()? ifAbsent}) => _base.update(key, update, ifAbsent: ifAbsent); @override void updateAll(V Function(K, V) update) => _base.updateAll(update); } /// An unmodifiable [Set] view of the keys of a [Map]. /// /// The set delegates all operations to the underlying map. /// /// A `Map` can only contain each key once, so its keys can always /// be viewed as a `Set` without any loss, even if the [Map.keys] /// getter only shows an [Iterable] view of the keys. /// /// Note that [lookup] is not supported for this set. class MapKeySet extends _DelegatingIterableBase with UnmodifiableSetMixin { final Map _baseMap; MapKeySet(this._baseMap); @override Iterable get _base => _baseMap.keys; @override Set cast() { if (this is MapKeySet) { return this as MapKeySet; } return Set.castFrom(this); } @override bool contains(Object? element) => _baseMap.containsKey(element); @override bool get isEmpty => _baseMap.isEmpty; @override bool get isNotEmpty => _baseMap.isNotEmpty; @override int get length => _baseMap.length; @override String toString() => SetBase.setToString(this); @override bool containsAll(Iterable other) => other.every(contains); /// Returns a new set with the the elements of `this` that are not in [other]. /// /// That is, the returned set contains all the elements of this [Set] that are /// not elements of [other] according to `other.contains`. /// /// Note that the returned set will use the default equality operation, which /// may be different than the equality operation `this` uses. @override Set difference(Set other) => where((element) => !other.contains(element)).toSet(); /// Returns a new set which is the intersection between `this` and [other]. /// /// That is, the returned set contains all the elements of this [Set] that are /// also elements of [other] according to `other.contains`. /// /// Note that the returned set will use the default equality operation, which /// may be different than the equality operation `this` uses. @override Set intersection(Set other) => where(other.contains).toSet(); /// Throws an [UnsupportedError] since there's no corresponding method for /// [Map]s. @override E lookup(Object? element) => throw UnsupportedError("MapKeySet doesn't support lookup()."); @Deprecated('Use cast instead') @override Set retype() => Set.castFrom(this); /// Returns a new set which contains all the elements of `this` and [other]. /// /// That is, the returned set contains all the elements of this [Set] and all /// the elements of [other]. /// /// Note that the returned set will use the default equality operation, which /// may be different than the equality operation `this` uses. @override Set union(Set other) => toSet()..addAll(other); } /// Creates a modifiable [Set] view of the values of a [Map]. /// /// The `Set` view assumes that the keys of the `Map` can be uniquely determined /// from the values. The `keyForValue` function passed to the constructor finds /// the key for a single value. The `keyForValue` function should be consistent /// with equality. If `value1 == value2` then `keyForValue(value1)` and /// `keyForValue(value2)` should be considered equal keys by the underlying map, /// and vice versa. /// /// Modifying the set will modify the underlying map based on the key returned /// by `keyForValue`. /// /// If the `Map` contents are not compatible with the `keyForValue` function, /// the set will not work consistently, and may give meaningless responses or do /// inconsistent updates. /// /// This set can, for example, be used on a map from database record IDs to the /// records. It exposes the records as a set, and allows for writing both /// `recordSet.add(databaseRecord)` and `recordMap[id]`. /// /// Effectively, the map will act as a kind of index for the set. class MapValueSet extends _DelegatingIterableBase implements Set { final Map _baseMap; final K Function(V) _keyForValue; /// Creates a new [MapValueSet] based on [_baseMap]. /// /// [_keyForValue] returns the key in the map that should be associated with /// the given value. The set's notion of equality is identical to the equality /// of the return values of [_keyForValue]. MapValueSet(this._baseMap, this._keyForValue); @override Iterable get _base => _baseMap.values; @override Set cast() { if (this is Set) { return this as Set; } return Set.castFrom(this); } @override bool contains(Object? element) { if (element is! V) return false; var key = _keyForValue(element); return _baseMap.containsKey(key); } @override bool get isEmpty => _baseMap.isEmpty; @override bool get isNotEmpty => _baseMap.isNotEmpty; @override int get length => _baseMap.length; @override String toString() => toSet().toString(); @override bool add(V value) { var key = _keyForValue(value); var result = false; _baseMap.putIfAbsent(key, () { result = true; return value; }); return result; } @override void addAll(Iterable elements) => elements.forEach(add); @override void clear() => _baseMap.clear(); @override bool containsAll(Iterable other) => other.every(contains); /// Returns a new set with the the elements of `this` that are not in [other]. /// /// That is, the returned set contains all the elements of this [Set] that are /// not elements of [other] according to `other.contains`. /// /// Note that the returned set will use the default equality operation, which /// may be different than the equality operation `this` uses. @override Set difference(Set other) => where((element) => !other.contains(element)).toSet(); /// Returns a new set which is the intersection between `this` and [other]. /// /// That is, the returned set contains all the elements of this [Set] that are /// also elements of [other] according to `other.contains`. /// /// Note that the returned set will use the default equality operation, which /// may be different than the equality operation `this` uses. @override Set intersection(Set other) => where(other.contains).toSet(); @override V? lookup(Object? element) { if (element is! V) return null; var key = _keyForValue(element); return _baseMap[key]; } @override bool remove(Object? element) { if (element is! V) return false; var key = _keyForValue(element); if (!_baseMap.containsKey(key)) return false; _baseMap.remove(key); return true; } @override void removeAll(Iterable elements) => elements.forEach(remove); @override void removeWhere(bool Function(V) test) { var toRemove = []; _baseMap.forEach((key, value) { if (test(value)) toRemove.add(key); }); toRemove.forEach(_baseMap.remove); } @override void retainAll(Iterable elements) { var valuesToRetain = Set.identity(); for (var element in elements) { if (element is! V) continue; var key = _keyForValue(element); if (!_baseMap.containsKey(key)) continue; valuesToRetain.add(_baseMap[key] ?? null as V); } var keysToRemove = []; _baseMap.forEach((k, v) { if (!valuesToRetain.contains(v)) keysToRemove.add(k); }); keysToRemove.forEach(_baseMap.remove); } @override void retainWhere(bool Function(V) test) => removeWhere((element) => !test(element)); @Deprecated('Use cast instead') @override Set retype() => Set.castFrom(this); /// Returns a new set which contains all the elements of `this` and [other]. /// /// That is, the returned set contains all the elements of this [Set] and all /// the elements of [other]. /// /// Note that the returned set will use the default equality operation, which /// may be different than the equality operation `this` uses. @override Set union(Set other) => toSet()..addAll(other); }