| OLD | NEW |
| (Empty) |
| 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | |
| 2 // for details. All rights reserved. Use of this source code is governed by a | |
| 3 // BSD-style license that can be found in the LICENSE file. | |
| 4 | |
| 5 part of dart.collection; | |
| 6 | |
| 7 /** | |
| 8 * Base class for implementing a [Map]. | |
| 9 * | |
| 10 * This class has a basic implementation of all but five of the members of | |
| 11 * [Map]. | |
| 12 * A basic `Map` class can be implemented by extending this class and | |
| 13 * implementing `keys`, `operator[]`, `operator[]=`, `remove` and `clear`. | |
| 14 * The remaining operations are implemented in terms of these five. | |
| 15 * | |
| 16 * The `keys` iterable should have efficient [length] and [contains] | |
| 17 * operations, and it should catch concurrent modifications of the keys | |
| 18 * while iterating. | |
| 19 * | |
| 20 * A more efficient implementation is usually possible by overriding | |
| 21 * some of the other members as well. | |
| 22 */ | |
| 23 abstract class MapBase<K, V> = Object with MapMixin<K, V>; | |
| 24 | |
| 25 | |
| 26 /** | |
| 27 * Mixin implementing a [Map]. | |
| 28 * | |
| 29 * This mixin has a basic implementation of all but five of the members of | |
| 30 * [Map]. | |
| 31 * A basic `Map` class can be implemented by mixin in this class and | |
| 32 * implementing `keys`, `operator[]`, `operator[]=`, `remove` and `clear`. | |
| 33 * The remaining operations are implemented in terms of these five. | |
| 34 * | |
| 35 * The `keys` iterable should have efficient [length] and [contains] | |
| 36 * operations, and it should catch concurrent modifications of the keys | |
| 37 * while iterating. | |
| 38 * | |
| 39 * A more efficient implementation is usually possible by overriding | |
| 40 * some of the other members as well. | |
| 41 */ | |
| 42 abstract class MapMixin<K, V> implements Map<K, V> { | |
| 43 Iterable<K> get keys; | |
| 44 V operator[](Object key); | |
| 45 operator []=(K key, V value); | |
| 46 V remove(Object key); | |
| 47 // The `clear` operation should not be based on `remove`. | |
| 48 // It should clear the map even if some keys are not equal to themselves. | |
| 49 void clear(); | |
| 50 | |
| 51 void forEach(void action(K key, V value)) { | |
| 52 for (K key in keys) { | |
| 53 action(key, this[key]); | |
| 54 } | |
| 55 } | |
| 56 | |
| 57 void addAll(Map<K, V> other) { | |
| 58 for (K key in other.keys) { | |
| 59 this[key] = other[key]; | |
| 60 } | |
| 61 } | |
| 62 | |
| 63 bool containsValue(Object value) { | |
| 64 for (K key in keys) { | |
| 65 if (this[key] == value) return true; | |
| 66 } | |
| 67 return false; | |
| 68 } | |
| 69 | |
| 70 V putIfAbsent(K key, V ifAbsent()) { | |
| 71 if (containsKey(key)) { | |
| 72 return this[key]; | |
| 73 } | |
| 74 return this[key] = ifAbsent(); | |
| 75 } | |
| 76 | |
| 77 bool containsKey(Object key) => keys.contains(key); | |
| 78 int get length => keys.length; | |
| 79 bool get isEmpty => keys.isEmpty; | |
| 80 bool get isNotEmpty => keys.isNotEmpty; | |
| 81 Iterable<V> get values => new _MapBaseValueIterable<K, V>(this); | |
| 82 String toString() => Maps.mapToString(this); | |
| 83 } | |
| 84 | |
| 85 /** | |
| 86 * Basic implementation of an unmodifiable [Map]. | |
| 87 * | |
| 88 * This class has a basic implementation of all but two of the members of | |
| 89 * an umodifiable [Map]. | |
| 90 * A simple unmodifiable `Map` class can be implemented by extending this | |
| 91 * class and implementing `keys` and `operator[]`. | |
| 92 * | |
| 93 * Modifying operations throw when used. | |
| 94 * The remaining non-modifying operations are implemented in terms of `keys` | |
| 95 * and `operator[]`. | |
| 96 * | |
| 97 * The `keys` iterable should have efficient [length] and [contains] | |
| 98 * operations, and it should catch concurrent modifications of the keys | |
| 99 * while iterating. | |
| 100 * | |
| 101 * A more efficient implementation is usually possible by overriding | |
| 102 * some of the other members as well. | |
| 103 */ | |
| 104 abstract class UnmodifiableMapBase<K, V> = | |
| 105 MapBase<K, V> with _UnmodifiableMapMixin<K, V>; | |
| 106 | |
| 107 /** | |
| 108 * Implementation of [Map.values] based on the map and its [Map.keys] iterable. | |
| 109 * | |
| 110 * Iterable that iterates over the values of a `Map`. | |
| 111 * It accesses the values by iterating over the keys of the map, and using the | |
| 112 * map's `operator[]` to lookup the keys. | |
| 113 */ | |
| 114 class _MapBaseValueIterable<K, V> extends Iterable<V> | |
| 115 implements EfficientLength { | |
| 116 final Map<K, V> _map; | |
| 117 _MapBaseValueIterable(this._map); | |
| 118 | |
| 119 int get length => _map.length; | |
| 120 bool get isEmpty => _map.isEmpty; | |
| 121 bool get isNotEmpty => _map.isNotEmpty; | |
| 122 V get first => _map[_map.keys.first]; | |
| 123 V get single => _map[_map.keys.single]; | |
| 124 V get last => _map[_map.keys.last]; | |
| 125 | |
| 126 Iterator<V> get iterator => new _MapBaseValueIterator<K, V>(_map); | |
| 127 } | |
| 128 | |
| 129 /** | |
| 130 * Iterator created by [_MapBaseValueIterable]. | |
| 131 * | |
| 132 * Iterates over the values of a map by iterating its keys and lookup up the | |
| 133 * values. | |
| 134 */ | |
| 135 class _MapBaseValueIterator<K, V> implements Iterator<V> { | |
| 136 final Iterator<K> _keys; | |
| 137 final Map<K, V> _map; | |
| 138 V _current = null; | |
| 139 | |
| 140 _MapBaseValueIterator(Map<K, V> map) | |
| 141 : _map = map, | |
| 142 _keys = map.keys.iterator; | |
| 143 | |
| 144 bool moveNext() { | |
| 145 if (_keys.moveNext()) { | |
| 146 _current = _map[_keys.current]; | |
| 147 return true; | |
| 148 } | |
| 149 _current = null; | |
| 150 return false; | |
| 151 } | |
| 152 | |
| 153 V get current => _current; | |
| 154 } | |
| 155 | |
| 156 /** | |
| 157 * Mixin that overrides mutating map operations with implementations that throw. | |
| 158 */ | |
| 159 abstract class _UnmodifiableMapMixin<K, V> implements Map<K, V> { | |
| 160 void operator[]=(K key, V value) { | |
| 161 throw new UnsupportedError("Cannot modify unmodifiable map"); | |
| 162 } | |
| 163 void addAll(Map<K, V> other) { | |
| 164 throw new UnsupportedError("Cannot modify unmodifiable map"); | |
| 165 } | |
| 166 void clear() { | |
| 167 throw new UnsupportedError("Cannot modify unmodifiable map"); | |
| 168 } | |
| 169 V remove(Object key) { | |
| 170 throw new UnsupportedError("Cannot modify unmodifiable map"); | |
| 171 } | |
| 172 V putIfAbsent(K key, V ifAbsent()) { | |
| 173 throw new UnsupportedError("Cannot modify unmodifiable map"); | |
| 174 } | |
| 175 } | |
| 176 | |
| 177 /** | |
| 178 * Wrapper around a class that implements [Map] that only exposes `Map` members. | |
| 179 * | |
| 180 * A simple wrapper that delegates all `Map` members to the map provided in the | |
| 181 * constructor. | |
| 182 * | |
| 183 * Base for delegating map implementations like [UnmodifiableMapView]. | |
| 184 */ | |
| 185 class MapView<K, V> implements Map<K, V> { | |
| 186 final Map<K, V> _map; | |
| 187 const MapView(Map<K, V> map) : _map = map; | |
| 188 | |
| 189 V operator[](Object key) => _map[key]; | |
| 190 void operator[]=(K key, V value) { _map[key] = value; } | |
| 191 void addAll(Map<K, V> other) { _map.addAll(other); } | |
| 192 void clear() { _map.clear(); } | |
| 193 V putIfAbsent(K key, V ifAbsent()) => _map.putIfAbsent(key, ifAbsent); | |
| 194 bool containsKey(Object key) => _map.containsKey(key); | |
| 195 bool containsValue(Object value) => _map.containsValue(value); | |
| 196 void forEach(void action(K key, V value)) { _map.forEach(action); } | |
| 197 bool get isEmpty => _map.isEmpty; | |
| 198 bool get isNotEmpty => _map.isNotEmpty; | |
| 199 int get length => _map.length; | |
| 200 Iterable<K> get keys => _map.keys; | |
| 201 V remove(Object key) => _map.remove(key); | |
| 202 String toString() => _map.toString(); | |
| 203 Iterable<V> get values => _map.values; | |
| 204 } | |
| 205 | |
| 206 /** | |
| 207 * View of a [Map] that disallow modifying the map. | |
| 208 * | |
| 209 * A wrapper around a `Map` that forwards all members to the map provided in | |
| 210 * the constructor, except for operations that modify the map. | |
| 211 * Modifying operations throw instead. | |
| 212 */ | |
| 213 class UnmodifiableMapView<K, V> = | |
| 214 MapView<K, V> with _UnmodifiableMapMixin<K, V>; | |
| 215 | |
| 216 /** | |
| 217 * Helper class which implements complex [Map] operations | |
| 218 * in term of basic ones ([Map.keys], [Map.operator []], | |
| 219 * [Map.operator []=] and [Map.remove].) Not all methods are | |
| 220 * necessary to implement each particular operation. | |
| 221 */ | |
| 222 class Maps { | |
| 223 static bool containsValue(Map map, Object value) { | |
| 224 for (final v in map.values) { | |
| 225 if (v == value) { | |
| 226 return true; | |
| 227 } | |
| 228 } | |
| 229 return false; | |
| 230 } | |
| 231 | |
| 232 static bool containsKey(Map map, Object key) { | |
| 233 for (final k in map.keys) { | |
| 234 if (k == key) { | |
| 235 return true; | |
| 236 } | |
| 237 } | |
| 238 return false; | |
| 239 } | |
| 240 | |
| 241 static putIfAbsent(Map map, key, ifAbsent()) { | |
| 242 if (map.containsKey(key)) { | |
| 243 return map[key]; | |
| 244 } | |
| 245 final v = ifAbsent(); | |
| 246 map[key] = v; | |
| 247 return v; | |
| 248 } | |
| 249 | |
| 250 static clear(Map map) { | |
| 251 for (final k in map.keys.toList()) { | |
| 252 map.remove(k); | |
| 253 } | |
| 254 } | |
| 255 | |
| 256 static forEach(Map map, void f(key, value)) { | |
| 257 for (final k in map.keys) { | |
| 258 f(k, map[k]); | |
| 259 } | |
| 260 } | |
| 261 | |
| 262 static Iterable getValues(Map map) { | |
| 263 return map.keys.map((key) => map[key]); | |
| 264 } | |
| 265 | |
| 266 static int length(Map map) => map.keys.length; | |
| 267 | |
| 268 static bool isEmpty(Map map) => map.keys.isEmpty; | |
| 269 | |
| 270 static bool isNotEmpty(Map map) => map.keys.isNotEmpty; | |
| 271 | |
| 272 /** | |
| 273 * Returns a string representing the specified map. The returned string | |
| 274 * looks like this: [:'{key0: value0, key1: value1, ... keyN: valueN}':]. | |
| 275 * The value returned by its [toString] method is used to represent each | |
| 276 * key or value. | |
| 277 * | |
| 278 * If the map collection contains a reference to itself, either | |
| 279 * directly as a key or value, or indirectly through other collections | |
| 280 * or maps, the contained reference is rendered as [:'{...}':]. This | |
| 281 * prevents the infinite regress that would otherwise occur. So, for example, | |
| 282 * calling this method on a map whose sole entry maps the string key 'me' | |
| 283 * to a reference to the map would return [:'{me: {...}}':]. | |
| 284 * | |
| 285 * A typical implementation of a map's [toString] method will | |
| 286 * simply return the results of this method applied to the collection. | |
| 287 */ | |
| 288 static String mapToString(Map m) { | |
| 289 // Reuse the list in IterableBase for detecting toString cycles. | |
| 290 if (_isToStringVisiting(m)) { return '{...}'; } | |
| 291 | |
| 292 var result = new StringBuffer(); | |
| 293 try { | |
| 294 _toStringVisiting.add(m); | |
| 295 result.write('{'); | |
| 296 bool first = true; | |
| 297 m.forEach((k, v) { | |
| 298 if(!first) { | |
| 299 result.write(', '); | |
| 300 } | |
| 301 first = false; | |
| 302 result.write(k); | |
| 303 result.write(': '); | |
| 304 result.write(v); | |
| 305 }); | |
| 306 result.write('}'); | |
| 307 } finally { | |
| 308 assert(identical(_toStringVisiting.last, m)); | |
| 309 _toStringVisiting.removeLast(); | |
| 310 } | |
| 311 | |
| 312 return result.toString(); | |
| 313 } | |
| 314 | |
| 315 static _id(x) => x; | |
| 316 | |
| 317 /** | |
| 318 * Fills a map with key/value pairs computed from [iterable]. | |
| 319 * | |
| 320 * This method is used by Map classes in the named constructor fromIterable. | |
| 321 */ | |
| 322 static void _fillMapWithMappedIterable(Map map, Iterable iterable, | |
| 323 key(element), value(element)) { | |
| 324 if (key == null) key = _id; | |
| 325 if (value == null) value = _id; | |
| 326 | |
| 327 for (var element in iterable) { | |
| 328 map[key(element)] = value(element); | |
| 329 } | |
| 330 } | |
| 331 | |
| 332 /** | |
| 333 * Fills a map by associating the [keys] to [values]. | |
| 334 * | |
| 335 * This method is used by Map classes in the named constructor fromIterables. | |
| 336 */ | |
| 337 static void _fillMapWithIterables(Map map, Iterable keys, | |
| 338 Iterable values) { | |
| 339 Iterator keyIterator = keys.iterator; | |
| 340 Iterator valueIterator = values.iterator; | |
| 341 | |
| 342 bool hasNextKey = keyIterator.moveNext(); | |
| 343 bool hasNextValue = valueIterator.moveNext(); | |
| 344 | |
| 345 while (hasNextKey && hasNextValue) { | |
| 346 map[keyIterator.current] = valueIterator.current; | |
| 347 hasNextKey = keyIterator.moveNext(); | |
| 348 hasNextValue = valueIterator.moveNext(); | |
| 349 } | |
| 350 | |
| 351 if (hasNextKey || hasNextValue) { | |
| 352 throw new ArgumentError("Iterables do not have same length."); | |
| 353 } | |
| 354 } | |
| 355 } | |
| OLD | NEW |