| // 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.collection; | 
 |  | 
 | /// Base class for implementing a [Map]. | 
 | /// | 
 | /// This class has a basic implementation of all but five of the members of | 
 | /// [Map]. | 
 | /// A basic `Map` class can be implemented by extending this class and | 
 | /// implementing `keys`, `operator[]`, `operator[]=`, `remove` and `clear`. | 
 | /// The remaining operations are implemented in terms of these five. | 
 | /// | 
 | /// The `keys` iterable should have efficient [Iterable.length] and | 
 | /// [Iterable.contains] operations, and it should catch concurrent modifications | 
 | /// of the keys while iterating. | 
 | /// | 
 | /// A more efficient implementation is usually possible by overriding | 
 | /// some of the other members as well. | 
 | abstract class MapBase<K, V> extends MapMixin<K, V> { | 
 |   static String mapToString(Map<Object?, Object?> m) { | 
 |     // Reuses the list in IterableBase for detecting toString cycles. | 
 |     if (_isToStringVisiting(m)) { | 
 |       return '{...}'; | 
 |     } | 
 |  | 
 |     var result = StringBuffer(); | 
 |     try { | 
 |       _toStringVisiting.add(m); | 
 |       result.write('{'); | 
 |       bool first = true; | 
 |       m.forEach((Object? k, Object? v) { | 
 |         if (!first) { | 
 |           result.write(', '); | 
 |         } | 
 |         first = false; | 
 |         result.write(k); | 
 |         result.write(': '); | 
 |         result.write(v); | 
 |       }); | 
 |       result.write('}'); | 
 |     } finally { | 
 |       assert(identical(_toStringVisiting.last, m)); | 
 |       _toStringVisiting.removeLast(); | 
 |     } | 
 |  | 
 |     return result.toString(); | 
 |   } | 
 |  | 
 |   static Object? _id(Object? x) => x; | 
 |  | 
 |   /// Fills a [Map] with key/value pairs computed from [iterable]. | 
 |   /// | 
 |   /// This method is used by [Map] classes in the named constructor | 
 |   /// `fromIterable`. | 
 |   static void _fillMapWithMappedIterable( | 
 |       Map<Object?, Object?> map, | 
 |       Iterable<Object?> iterable, | 
 |       Object? Function(Object? element)? key, | 
 |       Object? Function(Object? element)? value) { | 
 |     key ??= _id; | 
 |     value ??= _id; | 
 |  | 
 |     if (key == null) throw "!"; // TODO(38493): The `??=` should promote. | 
 |     if (value == null) throw "!"; // TODO(38493): The `??=` should promote. | 
 |  | 
 |     for (var element in iterable) { | 
 |       map[key(element)] = value(element); | 
 |     } | 
 |   } | 
 |  | 
 |   /// Fills a map by associating the [keys] to [values]. | 
 |   /// | 
 |   /// This method is used by [Map] classes in the named constructor | 
 |   /// `fromIterables`. | 
 |   static void _fillMapWithIterables(Map<Object?, Object?> map, | 
 |       Iterable<Object?> keys, Iterable<Object?> values) { | 
 |     Iterator<Object?> keyIterator = keys.iterator; | 
 |     Iterator<Object?> valueIterator = values.iterator; | 
 |  | 
 |     bool hasNextKey = keyIterator.moveNext(); | 
 |     bool hasNextValue = valueIterator.moveNext(); | 
 |  | 
 |     while (hasNextKey && hasNextValue) { | 
 |       map[keyIterator.current] = valueIterator.current; | 
 |       hasNextKey = keyIterator.moveNext(); | 
 |       hasNextValue = valueIterator.moveNext(); | 
 |     } | 
 |  | 
 |     if (hasNextKey || hasNextValue) { | 
 |       throw ArgumentError("Iterables do not have same length."); | 
 |     } | 
 |   } | 
 | } | 
 |  | 
 | /// Mixin implementing a [Map]. | 
 | /// | 
 | /// This mixin has a basic implementation of all but five of the members of | 
 | /// [Map]. | 
 | /// A basic `Map` class can be implemented by mixin in this class and | 
 | /// implementing `keys`, `operator[]`, `operator[]=`, `remove` and `clear`. | 
 | /// The remaining operations are implemented in terms of these five. | 
 | /// | 
 | /// The `keys` iterable should have efficient [Iterable.length] and | 
 | /// [Iterable.contains] operations, and it should catch concurrent modifications | 
 | /// of the keys while iterating. | 
 | /// | 
 | /// A more efficient implementation is usually possible by overriding | 
 | /// some of the other members as well. | 
 | abstract class MapMixin<K, V> implements Map<K, V> { | 
 |   Iterable<K> get keys; | 
 |   V? operator [](Object? key); | 
 |   operator []=(K key, V value); | 
 |   V? remove(Object? key); | 
 |   // The `clear` operation should not be based on `remove`. | 
 |   // It should clear the map even if some keys are not equal to themselves. | 
 |   void clear(); | 
 |  | 
 |   Map<RK, RV> cast<RK, RV>() => Map.castFrom<K, V, RK, RV>(this); | 
 |   void forEach(void action(K key, V value)) { | 
 |     for (K key in keys) { | 
 |       action(key, this[key] as V); | 
 |     } | 
 |   } | 
 |  | 
 |   void addAll(Map<K, V> other) { | 
 |     for (K key in other.keys) { | 
 |       this[key] = other[key] as V; | 
 |     } | 
 |   } | 
 |  | 
 |   bool containsValue(Object? value) { | 
 |     for (K key in keys) { | 
 |       if (this[key] == value) return true; | 
 |     } | 
 |     return false; | 
 |   } | 
 |  | 
 |   V putIfAbsent(K key, V ifAbsent()) { | 
 |     if (containsKey(key)) { | 
 |       return this[key] as V; | 
 |     } | 
 |     return this[key] = ifAbsent(); | 
 |   } | 
 |  | 
 |   V update(K key, V update(V value), {V Function()? ifAbsent}) { | 
 |     if (this.containsKey(key)) { | 
 |       return this[key] = update(this[key] as V); | 
 |     } | 
 |     if (ifAbsent != null) { | 
 |       return this[key] = ifAbsent(); | 
 |     } | 
 |     throw ArgumentError.value(key, "key", "Key not in map."); | 
 |   } | 
 |  | 
 |   void updateAll(V update(K key, V value)) { | 
 |     for (var key in this.keys) { | 
 |       this[key] = update(key, this[key] as V); | 
 |     } | 
 |   } | 
 |  | 
 |   Iterable<MapEntry<K, V>> get entries { | 
 |     return keys.map((K key) => MapEntry<K, V>(key, this[key] as V)); | 
 |   } | 
 |  | 
 |   Map<K2, V2> map<K2, V2>(MapEntry<K2, V2> transform(K key, V value)) { | 
 |     var result = <K2, V2>{}; | 
 |     for (var key in this.keys) { | 
 |       var entry = transform(key, this[key] as V); | 
 |       result[entry.key] = entry.value; | 
 |     } | 
 |     return result; | 
 |   } | 
 |  | 
 |   void addEntries(Iterable<MapEntry<K, V>> newEntries) { | 
 |     for (var entry in newEntries) { | 
 |       this[entry.key] = entry.value; | 
 |     } | 
 |   } | 
 |  | 
 |   void removeWhere(bool test(K key, V value)) { | 
 |     var keysToRemove = <K>[]; | 
 |     for (var key in keys) { | 
 |       if (test(key, this[key] as V)) keysToRemove.add(key); | 
 |     } | 
 |     for (var key in keysToRemove) { | 
 |       this.remove(key); | 
 |     } | 
 |   } | 
 |  | 
 |   bool containsKey(Object? key) => keys.contains(key); | 
 |   int get length => keys.length; | 
 |   bool get isEmpty => keys.isEmpty; | 
 |   bool get isNotEmpty => keys.isNotEmpty; | 
 |   Iterable<V> get values => _MapBaseValueIterable<K, V>(this); | 
 |   String toString() => MapBase.mapToString(this); | 
 | } | 
 |  | 
 | /// Basic implementation of an unmodifiable [Map]. | 
 | /// | 
 | /// This class has a basic implementation of all but two of the members of | 
 | /// an umodifiable [Map]. | 
 | /// A simple unmodifiable `Map` class can be implemented by extending this | 
 | /// class and implementing `keys` and `operator[]`. | 
 | /// | 
 | /// Modifying operations throw when used. | 
 | /// The remaining non-modifying operations are implemented in terms of `keys` | 
 | /// and `operator[]`. | 
 | /// | 
 | /// The `keys` iterable should have efficient [Iterable.length] and | 
 | /// [Iterable.contains] operations, and it should catch concurrent modifications | 
 | /// of the keys while iterating. | 
 | /// | 
 | /// A more efficient implementation is usually possible by overriding | 
 | /// some of the other members as well. | 
 | abstract class UnmodifiableMapBase<K, V> = MapBase<K, V> | 
 |     with _UnmodifiableMapMixin<K, V>; | 
 |  | 
 | /// Implementation of [Map.values] based on the map and its [Map.keys] iterable. | 
 | /// | 
 | /// Iterable that iterates over the values of a `Map`. | 
 | /// It accesses the values by iterating over the keys of the map, and using the | 
 | /// map's `operator[]` to lookup the keys. | 
 | class _MapBaseValueIterable<K, V> extends EfficientLengthIterable<V> { | 
 |   final Map<K, V> _map; | 
 |   _MapBaseValueIterable(this._map); | 
 |  | 
 |   int get length => _map.length; | 
 |   bool get isEmpty => _map.isEmpty; | 
 |   bool get isNotEmpty => _map.isNotEmpty; | 
 |   V get first => _map[_map.keys.first] as V; | 
 |   V get single => _map[_map.keys.single] as V; | 
 |   V get last => _map[_map.keys.last] as V; | 
 |  | 
 |   Iterator<V> get iterator => _MapBaseValueIterator<K, V>(_map); | 
 | } | 
 |  | 
 | /// Iterator created by [_MapBaseValueIterable]. | 
 | /// | 
 | /// Iterates over the values of a map by iterating its keys and lookup up the | 
 | /// values. | 
 | class _MapBaseValueIterator<K, V> implements Iterator<V> { | 
 |   final Iterator<K> _keys; | 
 |   final Map<K, V> _map; | 
 |   V? _current; | 
 |  | 
 |   _MapBaseValueIterator(Map<K, V> map) | 
 |       : _map = map, | 
 |         _keys = map.keys.iterator; | 
 |  | 
 |   bool moveNext() { | 
 |     if (_keys.moveNext()) { | 
 |       _current = _map[_keys.current]; | 
 |       return true; | 
 |     } | 
 |     _current = null; | 
 |     return false; | 
 |   } | 
 |  | 
 |   V get current => _current as V; | 
 | } | 
 |  | 
 | /// Mixin that overrides mutating map operations with implementations that | 
 | /// throw. | 
 | abstract class _UnmodifiableMapMixin<K, V> implements Map<K, V> { | 
 |   /// This operation is not supported by an unmodifiable map. | 
 |   void operator []=(K key, V value) { | 
 |     throw UnsupportedError("Cannot modify unmodifiable map"); | 
 |   } | 
 |  | 
 |   /// This operation is not supported by an unmodifiable map. | 
 |   void addAll(Map<K, V> other) { | 
 |     throw UnsupportedError("Cannot modify unmodifiable map"); | 
 |   } | 
 |  | 
 |   /// This operation is not supported by an unmodifiable map. | 
 |   void addEntries(Iterable<MapEntry<K, V>> entries) { | 
 |     throw UnsupportedError("Cannot modify unmodifiable map"); | 
 |   } | 
 |  | 
 |   /// This operation is not supported by an unmodifiable map. | 
 |   void clear() { | 
 |     throw UnsupportedError("Cannot modify unmodifiable map"); | 
 |   } | 
 |  | 
 |   /// This operation is not supported by an unmodifiable map. | 
 |   V? remove(Object? key) { | 
 |     throw UnsupportedError("Cannot modify unmodifiable map"); | 
 |   } | 
 |  | 
 |   /// This operation is not supported by an unmodifiable map. | 
 |   void removeWhere(bool test(K key, V value)) { | 
 |     throw UnsupportedError("Cannot modify unmodifiable map"); | 
 |   } | 
 |  | 
 |   /// This operation is not supported by an unmodifiable map. | 
 |   V putIfAbsent(K key, V ifAbsent()) { | 
 |     throw UnsupportedError("Cannot modify unmodifiable map"); | 
 |   } | 
 |  | 
 |   /// This operation is not supported by an unmodifiable map. | 
 |   V update(K key, V update(V value), {V Function()? ifAbsent}) { | 
 |     throw UnsupportedError("Cannot modify unmodifiable map"); | 
 |   } | 
 |  | 
 |   /// This operation is not supported by an unmodifiable map. | 
 |   void updateAll(V update(K key, V value)) { | 
 |     throw UnsupportedError("Cannot modify unmodifiable map"); | 
 |   } | 
 | } | 
 |  | 
 | /// Wrapper around a class that implements [Map] that only exposes `Map` | 
 | /// members. | 
 | /// | 
 | /// A simple wrapper that delegates all `Map` members to the map provided in the | 
 | /// constructor. | 
 | /// | 
 | /// Base for delegating map implementations like [UnmodifiableMapView]. | 
 | class MapView<K, V> implements Map<K, V> { | 
 |   final Map<K, V> _map; | 
 |   const MapView(Map<K, V> map) : _map = map; | 
 |  | 
 |   Map<RK, RV> cast<RK, RV>() => _map.cast<RK, RV>(); | 
 |   V? operator [](Object? key) => _map[key]; | 
 |   void operator []=(K key, V value) { | 
 |     _map[key] = value; | 
 |   } | 
 |  | 
 |   void addAll(Map<K, V> other) { | 
 |     _map.addAll(other); | 
 |   } | 
 |  | 
 |   void clear() { | 
 |     _map.clear(); | 
 |   } | 
 |  | 
 |   V putIfAbsent(K key, V ifAbsent()) => _map.putIfAbsent(key, ifAbsent); | 
 |   bool containsKey(Object? key) => _map.containsKey(key); | 
 |   bool containsValue(Object? value) => _map.containsValue(value); | 
 |   void forEach(void action(K key, V value)) { | 
 |     _map.forEach(action); | 
 |   } | 
 |  | 
 |   bool get isEmpty => _map.isEmpty; | 
 |   bool get isNotEmpty => _map.isNotEmpty; | 
 |   int get length => _map.length; | 
 |   Iterable<K> get keys => _map.keys; | 
 |   V? remove(Object? key) => _map.remove(key); | 
 |   String toString() => _map.toString(); | 
 |   Iterable<V> get values => _map.values; | 
 |  | 
 |   Iterable<MapEntry<K, V>> get entries => _map.entries; | 
 |  | 
 |   void addEntries(Iterable<MapEntry<K, V>> entries) { | 
 |     _map.addEntries(entries); | 
 |   } | 
 |  | 
 |   Map<K2, V2> map<K2, V2>(MapEntry<K2, V2> transform(K key, V value)) => | 
 |       _map.map<K2, V2>(transform); | 
 |  | 
 |   V update(K key, V update(V value), {V Function()? ifAbsent}) => | 
 |       _map.update(key, update, ifAbsent: ifAbsent); | 
 |  | 
 |   void updateAll(V update(K key, V value)) { | 
 |     _map.updateAll(update); | 
 |   } | 
 |  | 
 |   void removeWhere(bool test(K key, V value)) { | 
 |     _map.removeWhere(test); | 
 |   } | 
 | } | 
 |  | 
 | /// View of a [Map] that disallow modifying the map. | 
 | /// | 
 | /// A wrapper around a `Map` that forwards all members to the map provided in | 
 | /// the constructor, except for operations that modify the map. | 
 | /// Modifying operations throw instead. | 
 | class UnmodifiableMapView<K, V> extends MapView<K, V> | 
 |     with _UnmodifiableMapMixin<K, V> { | 
 |   UnmodifiableMapView(Map<K, V> map) : super(map); | 
 |  | 
 |   Map<RK, RV> cast<RK, RV>() => | 
 |       UnmodifiableMapView<RK, RV>(_map.cast<RK, RV>()); | 
 | } |