| OLD | NEW |
| (Empty) |
| 1 // Copyright (c) 2013, 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 /** | |
| 9 * Hash map version of the [Map] interface. A [HashMap] does not | |
| 10 * provide any guarantees on the order of keys and values in [keys] | |
| 11 * and [values]. | |
| 12 */ | |
| 13 abstract class HashMap<K, V> extends Map<K, V> { | |
| 14 /** | |
| 15 * Creates a map with the default implementation. | |
| 16 */ | |
| 17 factory HashMap() => new _HashMapImpl<K, V>(); | |
| 18 | |
| 19 /** | |
| 20 * Creates a [HashMap] that contains all key value pairs of [other]. | |
| 21 */ | |
| 22 factory HashMap.from(Map<K, V> other) => new _HashMapImpl<K, V>.from(other); | |
| 23 } | |
| 24 | |
| 25 /** | |
| 26 * Hash map version of the [Map] interface that preserves insertion | |
| 27 * order. | |
| 28 */ | |
| 29 abstract class LinkedHashMap<K, V> extends HashMap<K, V> { | |
| 30 /** | |
| 31 * Creates a map with the default implementation. | |
| 32 */ | |
| 33 factory LinkedHashMap() => new _LinkedHashMapImpl<K, V>(); | |
| 34 | |
| 35 /** | |
| 36 * Creates a [LinkedHashMap] that contains all key value pairs of [other]. | |
| 37 */ | |
| 38 factory LinkedHashMap.from(Map<K, V> other) | |
| 39 => new _LinkedHashMapImpl<K, V>.from(other); | |
| 40 } | |
| 41 | |
| 42 | |
| 43 // Hash map implementation with open addressing and quadratic probing. | |
| 44 class _HashMapImpl<K, V> implements HashMap<K, V> { | |
| 45 | |
| 46 // The [_keys] list contains the keys inserted in the map. | |
| 47 // The [_keys] list must be a raw list because it | |
| 48 // will contain both elements of type K, and the [_DELETED_KEY] of type | |
| 49 // [_DeletedKeySentinel]. | |
| 50 // The alternative of declaring the [_keys] list as of type Object | |
| 51 // does not work, because the HashSetIterator constructor would fail: | |
| 52 // HashSetIterator(HashSet<E> set) | |
| 53 // : _nextValidIndex = -1, | |
| 54 // _entries = set_._backingMap._keys { | |
| 55 // _advance(); | |
| 56 // } | |
| 57 // With K being type int, for example, it would fail because | |
| 58 // List<Object> is not assignable to type List<int> of entries. | |
| 59 List _keys; | |
| 60 | |
| 61 // The values inserted in the map. For a filled entry index in this | |
| 62 // list, there is always the corresponding key in the [keys_] list | |
| 63 // at the same entry index. | |
| 64 List<V> _values; | |
| 65 | |
| 66 // The load limit is the number of entries we allow until we double | |
| 67 // the size of the lists. | |
| 68 int _loadLimit; | |
| 69 | |
| 70 // The current number of entries in the map. Will never be greater | |
| 71 // than [_loadLimit]. | |
| 72 int _numberOfEntries; | |
| 73 | |
| 74 // The current number of deleted entries in the map. | |
| 75 int _numberOfDeleted; | |
| 76 | |
| 77 // The sentinel when a key is deleted from the map. | |
| 78 static const _DeletedKeySentinel _DELETED_KEY = const _DeletedKeySentinel(); | |
| 79 | |
| 80 // The initial capacity of a hash map. | |
| 81 static const int _INITIAL_CAPACITY = 8; // must be power of 2 | |
| 82 | |
| 83 _HashMapImpl() { | |
| 84 _numberOfEntries = 0; | |
| 85 _numberOfDeleted = 0; | |
| 86 _loadLimit = _computeLoadLimit(_INITIAL_CAPACITY); | |
| 87 _keys = new List.fixedLength(_INITIAL_CAPACITY); | |
| 88 _values = new List<V>.fixedLength(_INITIAL_CAPACITY); | |
| 89 } | |
| 90 | |
| 91 factory _HashMapImpl.from(Map<K, V> other) { | |
| 92 Map<K, V> result = new _HashMapImpl<K, V>(); | |
| 93 other.forEach((K key, V value) { result[key] = value; }); | |
| 94 return result; | |
| 95 } | |
| 96 | |
| 97 static int _computeLoadLimit(int capacity) { | |
| 98 return (capacity * 3) ~/ 4; | |
| 99 } | |
| 100 | |
| 101 static int _firstProbe(int hashCode, int length) { | |
| 102 return hashCode & (length - 1); | |
| 103 } | |
| 104 | |
| 105 static int _nextProbe(int currentProbe, int numberOfProbes, int length) { | |
| 106 return (currentProbe + numberOfProbes) & (length - 1); | |
| 107 } | |
| 108 | |
| 109 int _probeForAdding(K key) { | |
| 110 if (key == null) throw new ArgumentError(null); | |
| 111 int hash = _firstProbe(key.hashCode, _keys.length); | |
| 112 int numberOfProbes = 1; | |
| 113 int initialHash = hash; | |
| 114 // insertionIndex points to a slot where a key was deleted. | |
| 115 int insertionIndex = -1; | |
| 116 while (true) { | |
| 117 // [existingKey] can be either of type [K] or [_DeletedKeySentinel]. | |
| 118 Object existingKey = _keys[hash]; | |
| 119 if (existingKey == null) { | |
| 120 // We are sure the key is not already in the set. | |
| 121 // If the current slot is empty and we didn't find any | |
| 122 // insertion slot before, return this slot. | |
| 123 if (insertionIndex < 0) return hash; | |
| 124 // If we did find an insertion slot before, return it. | |
| 125 return insertionIndex; | |
| 126 } else if (existingKey == key) { | |
| 127 // The key is already in the map. Return its slot. | |
| 128 return hash; | |
| 129 } else if ((insertionIndex < 0) && | |
| 130 (identical(existingKey, _DELETED_KEY))) { | |
| 131 // The slot contains a deleted element. Because previous calls to this | |
| 132 // method may not have had this slot deleted, we must continue iterate | |
| 133 // to find if there is a slot with the given key. | |
| 134 insertionIndex = hash; | |
| 135 } | |
| 136 | |
| 137 // We did not find an insertion slot. Look at the next one. | |
| 138 hash = _nextProbe(hash, numberOfProbes++, _keys.length); | |
| 139 // _ensureCapacity has guaranteed the following cannot happen. | |
| 140 // assert(hash != initialHash); | |
| 141 } | |
| 142 } | |
| 143 | |
| 144 int _probeForLookup(K key) { | |
| 145 if (key == null) throw new ArgumentError(null); | |
| 146 int hash = _firstProbe(key.hashCode, _keys.length); | |
| 147 int numberOfProbes = 1; | |
| 148 int initialHash = hash; | |
| 149 while (true) { | |
| 150 // [existingKey] can be either of type [K] or [_DeletedKeySentinel]. | |
| 151 Object existingKey = _keys[hash]; | |
| 152 // If the slot does not contain anything (in particular, it does not | |
| 153 // contain a deleted key), we know the key is not in the map. | |
| 154 if (existingKey == null) return -1; | |
| 155 // The key is in the map, return its index. | |
| 156 if (existingKey == key) return hash; | |
| 157 // Go to the next probe. | |
| 158 hash = _nextProbe(hash, numberOfProbes++, _keys.length); | |
| 159 // _ensureCapacity has guaranteed the following cannot happen. | |
| 160 // assert(hash != initialHash); | |
| 161 } | |
| 162 } | |
| 163 | |
| 164 void _ensureCapacity() { | |
| 165 int newNumberOfEntries = _numberOfEntries + 1; | |
| 166 // Test if adding an element will reach the load limit. | |
| 167 if (newNumberOfEntries >= _loadLimit) { | |
| 168 _grow(_keys.length * 2); | |
| 169 return; | |
| 170 } | |
| 171 | |
| 172 // Make sure that we don't have poor performance when a map | |
| 173 // contains lots of deleted entries: we _grow if | |
| 174 // there are more deleted entried than free entries. | |
| 175 int capacity = _keys.length; | |
| 176 int numberOfFreeOrDeleted = capacity - newNumberOfEntries; | |
| 177 int numberOfFree = numberOfFreeOrDeleted - _numberOfDeleted; | |
| 178 // assert(numberOfFree > 0); | |
| 179 if (_numberOfDeleted > numberOfFree) { | |
| 180 _grow(_keys.length); | |
| 181 } | |
| 182 } | |
| 183 | |
| 184 static bool _isPowerOfTwo(int x) { | |
| 185 return ((x & (x - 1)) == 0); | |
| 186 } | |
| 187 | |
| 188 void _grow(int newCapacity) { | |
| 189 assert(_isPowerOfTwo(newCapacity)); | |
| 190 int capacity = _keys.length; | |
| 191 _loadLimit = _computeLoadLimit(newCapacity); | |
| 192 List oldKeys = _keys; | |
| 193 List<V> oldValues = _values; | |
| 194 _keys = new List.fixedLength(newCapacity); | |
| 195 _values = new List<V>.fixedLength(newCapacity); | |
| 196 for (int i = 0; i < capacity; i++) { | |
| 197 // [key] can be either of type [K] or [_DeletedKeySentinel]. | |
| 198 Object key = oldKeys[i]; | |
| 199 // If there is no key, we don't need to deal with the current slot. | |
| 200 if (key == null || identical(key, _DELETED_KEY)) { | |
| 201 continue; | |
| 202 } | |
| 203 V value = oldValues[i]; | |
| 204 // Insert the {key, value} pair in their new slot. | |
| 205 int newIndex = _probeForAdding(key); | |
| 206 _keys[newIndex] = key; | |
| 207 _values[newIndex] = value; | |
| 208 } | |
| 209 _numberOfDeleted = 0; | |
| 210 } | |
| 211 | |
| 212 void clear() { | |
| 213 _numberOfEntries = 0; | |
| 214 _numberOfDeleted = 0; | |
| 215 int length = _keys.length; | |
| 216 for (int i = 0; i < length; i++) { | |
| 217 _keys[i] = null; | |
| 218 _values[i] = null; | |
| 219 } | |
| 220 } | |
| 221 | |
| 222 void operator []=(K key, V value) { | |
| 223 _ensureCapacity(); | |
| 224 int index = _probeForAdding(key); | |
| 225 if ((_keys[index] == null) || (identical(_keys[index], _DELETED_KEY))) { | |
| 226 _numberOfEntries++; | |
| 227 } | |
| 228 _keys[index] = key; | |
| 229 _values[index] = value; | |
| 230 } | |
| 231 | |
| 232 V operator [](K key) { | |
| 233 int index = _probeForLookup(key); | |
| 234 if (index < 0) return null; | |
| 235 return _values[index]; | |
| 236 } | |
| 237 | |
| 238 V putIfAbsent(K key, V ifAbsent()) { | |
| 239 int index = _probeForLookup(key); | |
| 240 if (index >= 0) return _values[index]; | |
| 241 | |
| 242 V value = ifAbsent(); | |
| 243 this[key] = value; | |
| 244 return value; | |
| 245 } | |
| 246 | |
| 247 V remove(K key) { | |
| 248 int index = _probeForLookup(key); | |
| 249 if (index >= 0) { | |
| 250 _numberOfEntries--; | |
| 251 V value = _values[index]; | |
| 252 _values[index] = null; | |
| 253 // Set the key to the sentinel to not break the probing chain. | |
| 254 _keys[index] = _DELETED_KEY; | |
| 255 _numberOfDeleted++; | |
| 256 return value; | |
| 257 } | |
| 258 return null; | |
| 259 } | |
| 260 | |
| 261 bool get isEmpty { | |
| 262 return _numberOfEntries == 0; | |
| 263 } | |
| 264 | |
| 265 int get length { | |
| 266 return _numberOfEntries; | |
| 267 } | |
| 268 | |
| 269 void forEach(void f(K key, V value)) { | |
| 270 Iterator<int> it = new _HashMapImplIndexIterator(this); | |
| 271 while (it.moveNext()) { | |
| 272 f(_keys[it.current], _values[it.current]); | |
| 273 } | |
| 274 } | |
| 275 | |
| 276 Iterable<K> get keys => new _HashMapImplKeyIterable<K>(this); | |
| 277 | |
| 278 Iterable<V> get values => new _HashMapImplValueIterable<V>(this); | |
| 279 | |
| 280 bool containsKey(K key) { | |
| 281 return (_probeForLookup(key) != -1); | |
| 282 } | |
| 283 | |
| 284 bool containsValue(V value) => values.contains(value); | |
| 285 | |
| 286 String toString() { | |
| 287 return Maps.mapToString(this); | |
| 288 } | |
| 289 } | |
| 290 | |
| 291 class _HashMapImplKeyIterable<E> extends Iterable<E> { | |
| 292 final _HashMapImpl _map; | |
| 293 _HashMapImplKeyIterable(this._map); | |
| 294 | |
| 295 Iterator<E> get iterator => new _HashMapImplKeyIterator<E>(_map); | |
| 296 } | |
| 297 | |
| 298 class _HashMapImplValueIterable<E> extends Iterable<E> { | |
| 299 final _HashMapImpl _map; | |
| 300 _HashMapImplValueIterable(this._map); | |
| 301 | |
| 302 Iterator<E> get iterator => new _HashMapImplValueIterator<E>(_map); | |
| 303 } | |
| 304 | |
| 305 abstract class _HashMapImplIterator<E> implements Iterator<E> { | |
| 306 final _HashMapImpl _map; | |
| 307 int _index = -1; | |
| 308 E _current; | |
| 309 | |
| 310 _HashMapImplIterator(this._map); | |
| 311 | |
| 312 E _computeCurrentFromIndex(int index, List keys, List values); | |
| 313 | |
| 314 bool moveNext() { | |
| 315 int length = _map._keys.length; | |
| 316 int newIndex = _index + 1; | |
| 317 while (newIndex < length) { | |
| 318 var key = _map._keys[newIndex]; | |
| 319 if ((key != null) && (!identical(key, _HashMapImpl._DELETED_KEY))) { | |
| 320 _current = _computeCurrentFromIndex(newIndex, _map._keys, _map._values); | |
| 321 _index = newIndex; | |
| 322 return true; | |
| 323 } | |
| 324 newIndex++; | |
| 325 } | |
| 326 _index = length; | |
| 327 _current = null; | |
| 328 return false; | |
| 329 } | |
| 330 | |
| 331 E get current => _current; | |
| 332 } | |
| 333 | |
| 334 class _HashMapImplKeyIterator<E> extends _HashMapImplIterator<E> { | |
| 335 _HashMapImplKeyIterator(_HashMapImpl map) : super(map); | |
| 336 | |
| 337 E _computeCurrentFromIndex(int index, List keys, List values) { | |
| 338 return keys[index]; | |
| 339 } | |
| 340 } | |
| 341 | |
| 342 class _HashMapImplValueIterator<E> extends _HashMapImplIterator<E> { | |
| 343 _HashMapImplValueIterator(_HashMapImpl map) : super(map); | |
| 344 | |
| 345 E _computeCurrentFromIndex(int index, List keys, List values) { | |
| 346 return values[index]; | |
| 347 } | |
| 348 } | |
| 349 | |
| 350 class _HashMapImplIndexIterator extends _HashMapImplIterator<int> { | |
| 351 _HashMapImplIndexIterator(_HashMapImpl map) : super(map); | |
| 352 | |
| 353 int _computeCurrentFromIndex(int index, List keys, List values) { | |
| 354 return index; | |
| 355 } | |
| 356 } | |
| 357 | |
| 358 /** | |
| 359 * A singleton sentinel used to represent when a key is deleted from the map. | |
| 360 * We can't use [: const Object() :] as a sentinel because it would end up | |
| 361 * canonicalized and then we cannot distinguish the deleted key from the | |
| 362 * canonicalized [: Object() :]. | |
| 363 */ | |
| 364 class _DeletedKeySentinel { | |
| 365 const _DeletedKeySentinel(); | |
| 366 } | |
| 367 | |
| 368 | |
| 369 /** | |
| 370 * This class represents a pair of two objects, used by LinkedHashMap | |
| 371 * to store a {key, value} in a list. | |
| 372 */ | |
| 373 class _KeyValuePair<K, V> { | |
| 374 _KeyValuePair(this.key, this.value) {} | |
| 375 | |
| 376 final K key; | |
| 377 V value; | |
| 378 } | |
| 379 | |
| 380 /** | |
| 381 * A LinkedHashMap is a hash map that preserves the insertion order | |
| 382 * when iterating over the keys or the values. Updating the value of a | |
| 383 * key does not change the order. | |
| 384 */ | |
| 385 class _LinkedHashMapImpl<K, V> implements LinkedHashMap<K, V> { | |
| 386 DoubleLinkedQueue<_KeyValuePair<K, V>> _list; | |
| 387 HashMap<K, DoubleLinkedQueueEntry<_KeyValuePair<K, V>>> _map; | |
| 388 | |
| 389 _LinkedHashMapImpl() { | |
| 390 _map = new HashMap<K, DoubleLinkedQueueEntry<_KeyValuePair<K, V>>>(); | |
| 391 _list = new DoubleLinkedQueue<_KeyValuePair<K, V>>(); | |
| 392 } | |
| 393 | |
| 394 factory _LinkedHashMapImpl.from(Map<K, V> other) { | |
| 395 Map<K, V> result = new _LinkedHashMapImpl<K, V>(); | |
| 396 other.forEach((K key, V value) { result[key] = value; }); | |
| 397 return result; | |
| 398 } | |
| 399 | |
| 400 void operator []=(K key, V value) { | |
| 401 if (_map.containsKey(key)) { | |
| 402 _map[key].element.value = value; | |
| 403 } else { | |
| 404 _list.addLast(new _KeyValuePair<K, V>(key, value)); | |
| 405 _map[key] = _list.lastEntry(); | |
| 406 } | |
| 407 } | |
| 408 | |
| 409 V operator [](K key) { | |
| 410 DoubleLinkedQueueEntry<_KeyValuePair<K, V>> entry = _map[key]; | |
| 411 if (entry == null) return null; | |
| 412 return entry.element.value; | |
| 413 } | |
| 414 | |
| 415 V remove(K key) { | |
| 416 DoubleLinkedQueueEntry<_KeyValuePair<K, V>> entry = _map.remove(key); | |
| 417 if (entry == null) return null; | |
| 418 entry.remove(); | |
| 419 return entry.element.value; | |
| 420 } | |
| 421 | |
| 422 V putIfAbsent(K key, V ifAbsent()) { | |
| 423 V value = this[key]; | |
| 424 if ((this[key] == null) && !(containsKey(key))) { | |
| 425 value = ifAbsent(); | |
| 426 this[key] = value; | |
| 427 } | |
| 428 return value; | |
| 429 } | |
| 430 | |
| 431 Iterable<K> get keys { | |
| 432 return new MappedIterable<_KeyValuePair<K, V>, K>( | |
| 433 _list, (_KeyValuePair<K, V> entry) => entry.key); | |
| 434 } | |
| 435 | |
| 436 | |
| 437 Iterable<V> get values { | |
| 438 return new MappedIterable<_KeyValuePair<K, V>, V>( | |
| 439 _list, (_KeyValuePair<K, V> entry) => entry.value); | |
| 440 } | |
| 441 | |
| 442 void forEach(void f(K key, V value)) { | |
| 443 _list.forEach((_KeyValuePair<K, V> entry) { | |
| 444 f(entry.key, entry.value); | |
| 445 }); | |
| 446 } | |
| 447 | |
| 448 bool containsKey(K key) { | |
| 449 return _map.containsKey(key); | |
| 450 } | |
| 451 | |
| 452 bool containsValue(V value) { | |
| 453 return _list.any((_KeyValuePair<K, V> entry) { | |
| 454 return (entry.value == value); | |
| 455 }); | |
| 456 } | |
| 457 | |
| 458 int get length { | |
| 459 return _map.length; | |
| 460 } | |
| 461 | |
| 462 bool get isEmpty { | |
| 463 return length == 0; | |
| 464 } | |
| 465 | |
| 466 void clear() { | |
| 467 _map.clear(); | |
| 468 _list.clear(); | |
| 469 } | |
| 470 | |
| 471 String toString() { | |
| 472 return Maps.mapToString(this); | |
| 473 } | |
| 474 } | |
| OLD | NEW |