| OLD | NEW | 
|---|
| 1 // Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file | 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 | 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. | 3 // BSD-style license that can be found in the LICENSE file. | 
| 4 | 4 | 
| 5 patch class HashMap<K, V> { | 5 patch class HashMap<K, V> { | 
| 6   /* patch */ factory HashMap({ bool equals(K key1, K key2), | 6   /* patch */ factory HashMap({ bool equals(K key1, K key2), | 
| 7                                 int hashCode(K key), | 7                                 int hashCode(K key) }) { | 
| 8                                 bool isValidKey(potentialKey) }) { | 8     if (hashCode == null) { | 
| 9     if (isValidKey == null) { | 9       if (equals == null) { | 
| 10       if (hashCode == null) { | 10         return new _HashMapImpl<K, V>(); | 
| 11         if (equals == null) { |  | 
| 12           return new _HashMap<K, V>(); |  | 
| 13         } |  | 
| 14         if (identical(identical, equals)) { |  | 
| 15           return new _IdentityHashMap<K, V>(); |  | 
| 16         } |  | 
| 17         hashCode = _defaultHashCode; |  | 
| 18       } else if (equals == null) { |  | 
| 19         equals = _defaultEquals; |  | 
| 20       } | 11       } | 
| 21     } else { | 12       if (identical(identical, equals)) { | 
| 22       if (hashCode == null) { | 13         return new _IdentityHashMap<K, V>(); | 
| 23         hashCode = _defaultHashCode; |  | 
| 24       } | 14       } | 
| 25       if (equals == null) { | 15       hashCode = _defaultHashCode; | 
| 26         equals = _defaultEquals; | 16     } else if (equals == null) { | 
| 27       } | 17       equals = _defaultEquals; | 
| 28     } | 18     } | 
| 29     return new _CustomHashMap<K, V>(equals, hashCode, isValidKey); | 19     return new _CustomHashMap<K, V>(equals, hashCode); | 
| 30   } | 20   } | 
| 31 } | 21 } | 
| 32 | 22 | 
| 33 const int _MODIFICATION_COUNT_MASK = 0x3fffffff; | 23 const int _MODIFICATION_COUNT_MASK = 0x3fffffff; | 
| 34 | 24 | 
| 35 class _HashMap<K, V> implements HashMap<K, V> { | 25 class _HashMapImpl<K, V> implements HashMap<K, V> { | 
| 36   static const int _INITIAL_CAPACITY = 8; | 26   static const int _INITIAL_CAPACITY = 8; | 
| 37 | 27 | 
| 38   int _elementCount = 0; | 28   int _elementCount = 0; | 
| 39   List<_HashMapEntry> _buckets = new List(_INITIAL_CAPACITY); | 29   List<_HashMapEntry> _buckets = new List(_INITIAL_CAPACITY); | 
| 40   int _modificationCount = 0; | 30   int _modificationCount = 0; | 
| 41 | 31 | 
| 42   int get length => _elementCount; | 32   int get length => _elementCount; | 
| 43   bool get isEmpty => _elementCount == 0; | 33   bool get isEmpty => _elementCount == 0; | 
| 44   bool get isNotEmpty => _elementCount != 0; | 34   bool get isNotEmpty => _elementCount != 0; | 
| 45 | 35 | 
| (...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 147 | 137 | 
| 148   V remove(Object key) { | 138   V remove(Object key) { | 
| 149     int hashCode = key.hashCode; | 139     int hashCode = key.hashCode; | 
| 150     List buckets = _buckets; | 140     List buckets = _buckets; | 
| 151     int index = hashCode & (buckets.length - 1); | 141     int index = hashCode & (buckets.length - 1); | 
| 152     _HashMapEntry entry = buckets[index]; | 142     _HashMapEntry entry = buckets[index]; | 
| 153     _HashMapEntry previous = null; | 143     _HashMapEntry previous = null; | 
| 154     while (entry != null) { | 144     while (entry != null) { | 
| 155       _HashMapEntry next = entry.next; | 145       _HashMapEntry next = entry.next; | 
| 156       if (hashCode == entry.hashCode && entry.key == key) { | 146       if (hashCode == entry.hashCode && entry.key == key) { | 
| 157         _removeEntry(entry, previous, index); | 147         if (previous == null) { | 
|  | 148           buckets[index] = next; | 
|  | 149         } else { | 
|  | 150           previous.next = next; | 
|  | 151         } | 
| 158         _elementCount--; | 152         _elementCount--; | 
| 159         _modificationCount = | 153         _modificationCount = | 
| 160             (_modificationCount + 1) & _MODIFICATION_COUNT_MASK; | 154             (_modificationCount + 1) & _MODIFICATION_COUNT_MASK; | 
| 161         return entry.value; | 155         return entry.value; | 
| 162       } | 156       } | 
| 163       previous = entry; | 157       previous = entry; | 
| 164       entry = next; | 158       entry = next; | 
| 165     } | 159     } | 
| 166     return null; | 160     return null; | 
| 167   } | 161   } | 
| 168 | 162 | 
| 169   void clear() { | 163   void clear() { | 
| 170     _elementCount = 0; | 164     _elementCount = 0; | 
| 171     _buckets = new List(_INITIAL_CAPACITY); | 165     _buckets = new List(_INITIAL_CAPACITY); | 
| 172     _modificationCount = (_modificationCount + 1) & _MODIFICATION_COUNT_MASK; | 166     _modificationCount = (_modificationCount + 1) & _MODIFICATION_COUNT_MASK; | 
| 173   } | 167   } | 
| 174 | 168 | 
| 175   void _removeEntry(_HashMapEntry entry, |  | 
| 176                     _HashMapEntry previousInBucket, |  | 
| 177                     int bucketIndex) { |  | 
| 178     if (previousInBucket == null) { |  | 
| 179       _buckets[bucketIndex] = entry.next; |  | 
| 180     } else { |  | 
| 181       previousInBucket.next = entry.next; |  | 
| 182     } |  | 
| 183   } |  | 
| 184 |  | 
| 185   void _addEntry(List buckets, int index, int length, | 169   void _addEntry(List buckets, int index, int length, | 
| 186                  K key, V value, int hashCode) { | 170                  K key, V value, int hashCode) { | 
| 187     _HashMapEntry entry = | 171     _HashMapEntry entry = | 
| 188         new _HashMapEntry(key, value, hashCode, buckets[index]); | 172         new _HashMapEntry(key, value, hashCode, buckets[index]); | 
| 189     buckets[index] = entry; | 173     buckets[index] = entry; | 
| 190     int newElements = _elementCount + 1; | 174     int newElements = _elementCount + 1; | 
| 191     _elementCount = newElements; | 175     _elementCount = newElements; | 
| 192     // If we end up with more than 75% non-empty entries, we | 176     // If we end up with more than 75% non-empty entries, we | 
| 193     // resize the backing store. | 177     // resize the backing store. | 
| 194     if ((newElements << 2) > ((length << 1) + length)) _resize(); | 178     if ((newElements << 2) > ((length << 1) + length)) _resize(); | 
| (...skipping 15 matching lines...) Expand all  Loading... | 
| 210         newBuckets[index] = entry; | 194         newBuckets[index] = entry; | 
| 211         entry = next; | 195         entry = next; | 
| 212       } | 196       } | 
| 213     } | 197     } | 
| 214     _buckets = newBuckets; | 198     _buckets = newBuckets; | 
| 215   } | 199   } | 
| 216 | 200 | 
| 217   String toString() => Maps.mapToString(this); | 201   String toString() => Maps.mapToString(this); | 
| 218 } | 202 } | 
| 219 | 203 | 
| 220 class _CustomHashMap<K, V> extends _HashMap<K, V> { | 204 class _CustomHashMap<K, V> extends _HashMapImpl<K, V> { | 
| 221   final _Equality<K> _equals; | 205   final _Equality<K> _equals; | 
| 222   final _Hasher<K> _hashCode; | 206   final _Hasher<K> _hashCode; | 
| 223   final _Predicate _validKey; | 207   _CustomHashMap(this._equals, this._hashCode); | 
| 224   _CustomHashMap(this._equals, this._hashCode, validKey) |  | 
| 225       : _validKey = (validKey != null) ? validKey : new _TypeTest<K>().test; |  | 
| 226 | 208 | 
| 227   bool containsKey(Object key) { | 209   bool containsKey(Object key) { | 
| 228     if (!_validKey(key)) return false; |  | 
| 229     int hashCode = _hashCode(key); | 210     int hashCode = _hashCode(key); | 
| 230     List buckets = _buckets; | 211     List buckets = _buckets; | 
| 231     int index = hashCode & (buckets.length - 1); | 212     int index = hashCode & (buckets.length - 1); | 
| 232     _HashMapEntry entry = buckets[index]; | 213     _HashMapEntry entry = buckets[index]; | 
| 233     while (entry != null) { | 214     while (entry != null) { | 
| 234       if (hashCode == entry.hashCode && _equals(entry.key, key)) return true; | 215       if (hashCode == entry.hashCode && _equals(entry.key, key)) return true; | 
| 235       entry = entry.next; | 216       entry = entry.next; | 
| 236     } | 217     } | 
| 237     return false; | 218     return false; | 
| 238   } | 219   } | 
| 239 | 220 | 
| 240   V operator[](Object key) { | 221   V operator[](Object key) { | 
| 241     if (!_validKey(key)) return null; |  | 
| 242     int hashCode = _hashCode(key); | 222     int hashCode = _hashCode(key); | 
| 243     List buckets = _buckets; | 223     List buckets = _buckets; | 
| 244     int index = hashCode & (buckets.length - 1); | 224     int index = hashCode & (buckets.length - 1); | 
| 245     _HashMapEntry entry = buckets[index]; | 225     _HashMapEntry entry = buckets[index]; | 
| 246     while (entry != null) { | 226     while (entry != null) { | 
| 247       if (hashCode == entry.hashCode && _equals(entry.key, key)) { | 227       if (hashCode == entry.hashCode && _equals(entry.key, key)) { | 
| 248         return entry.value; | 228         return entry.value; | 
| 249       } | 229       } | 
| 250       entry = entry.next; | 230       entry = entry.next; | 
| 251     } | 231     } | 
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 284     V value = ifAbsent(); | 264     V value = ifAbsent(); | 
| 285     if (stamp == _modificationCount) { | 265     if (stamp == _modificationCount) { | 
| 286       _addEntry(buckets, index, length, key, value, hashCode); | 266       _addEntry(buckets, index, length, key, value, hashCode); | 
| 287     } else { | 267     } else { | 
| 288       this[key] = value; | 268       this[key] = value; | 
| 289     } | 269     } | 
| 290     return value; | 270     return value; | 
| 291   } | 271   } | 
| 292 | 272 | 
| 293   V remove(Object key) { | 273   V remove(Object key) { | 
| 294     if (!_validKey(key)) return null; |  | 
| 295     int hashCode = _hashCode(key); | 274     int hashCode = _hashCode(key); | 
| 296     List buckets = _buckets; | 275     List buckets = _buckets; | 
| 297     int index = hashCode & (buckets.length - 1); | 276     int index = hashCode & (buckets.length - 1); | 
| 298     _HashMapEntry entry = buckets[index]; | 277     _HashMapEntry entry = buckets[index]; | 
| 299     _HashMapEntry previous = null; | 278     _HashMapEntry previous = null; | 
| 300     while (entry != null) { | 279     while (entry != null) { | 
| 301       _HashMapEntry next = entry.next; | 280       _HashMapEntry next = entry.next; | 
| 302       if (hashCode == entry.hashCode && _equals(entry.key, key)) { | 281       if (hashCode == entry.hashCode && _equals(entry.key, key)) { | 
| 303         _removeEntry(entry, previous, index); | 282         if (previous == null) { | 
|  | 283           buckets[index] = next; | 
|  | 284         } else { | 
|  | 285           previous.next = next; | 
|  | 286         } | 
| 304         _elementCount--; | 287         _elementCount--; | 
| 305         _modificationCount = | 288         _modificationCount = | 
| 306             (_modificationCount + 1) & _MODIFICATION_COUNT_MASK; | 289             (_modificationCount + 1) & _MODIFICATION_COUNT_MASK; | 
| 307         return entry.value; | 290         return entry.value; | 
| 308       } | 291       } | 
| 309       previous = entry; | 292       previous = entry; | 
| 310       entry = next; | 293       entry = next; | 
| 311     } | 294     } | 
| 312     return null; | 295     return null; | 
| 313   } | 296   } | 
| 314 | 297 | 
| 315   String toString() => Maps.mapToString(this); | 298   String toString() => Maps.mapToString(this); | 
| 316 } | 299 } | 
| 317 | 300 | 
| 318 class _IdentityHashMap<K, V> extends _HashMap<K, V> { | 301 class _IdentityHashMap<K, V> extends _HashMapImpl<K, V> { | 
| 319   bool containsKey(Object key) { | 302   bool containsKey(Object key) { | 
| 320     int hashCode = key.hashCode; | 303     int hashCode = key.hashCode; | 
| 321     List buckets = _buckets; | 304     List buckets = _buckets; | 
| 322     int index = hashCode & (buckets.length - 1); | 305     int index = hashCode & (buckets.length - 1); | 
| 323     _HashMapEntry entry = buckets[index]; | 306     _HashMapEntry entry = buckets[index]; | 
| 324     while (entry != null) { | 307     while (entry != null) { | 
| 325       if (hashCode == entry.hashCode && identical(entry.key, key)) return true; | 308       if (hashCode == entry.hashCode && identical(entry.key, key)) return true; | 
| 326       entry = entry.next; | 309       entry = entry.next; | 
| 327     } | 310     } | 
| 328     return false; | 311     return false; | 
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 382 | 365 | 
| 383   V remove(Object key) { | 366   V remove(Object key) { | 
| 384     int hashCode = key.hashCode; | 367     int hashCode = key.hashCode; | 
| 385     List buckets = _buckets; | 368     List buckets = _buckets; | 
| 386     int index = hashCode & (buckets.length - 1); | 369     int index = hashCode & (buckets.length - 1); | 
| 387     _HashMapEntry entry = buckets[index]; | 370     _HashMapEntry entry = buckets[index]; | 
| 388     _HashMapEntry previous = null; | 371     _HashMapEntry previous = null; | 
| 389     while (entry != null) { | 372     while (entry != null) { | 
| 390       _HashMapEntry next = entry.next; | 373       _HashMapEntry next = entry.next; | 
| 391       if (hashCode == entry.hashCode && identical(entry.key, key)) { | 374       if (hashCode == entry.hashCode && identical(entry.key, key)) { | 
| 392         _removeEntry(entry, previous, index); | 375         if (previous == null) { | 
|  | 376           buckets[index] = next; | 
|  | 377         } else { | 
|  | 378           previous.next = next; | 
|  | 379         } | 
| 393         _elementCount--; | 380         _elementCount--; | 
| 394         _modificationCount = | 381         _modificationCount = | 
| 395             (_modificationCount + 1) & _MODIFICATION_COUNT_MASK; | 382             (_modificationCount + 1) & _MODIFICATION_COUNT_MASK; | 
| 396         return entry.value; | 383         return entry.value; | 
| 397       } | 384       } | 
| 398       previous = entry; | 385       previous = entry; | 
| 399       entry = next; | 386       entry = next; | 
| 400     } | 387     } | 
| 401     return null; | 388     return null; | 
| 402   } | 389   } | 
| (...skipping 199 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 602   LinkedHashMap<dynamic, V> _map; | 589   LinkedHashMap<dynamic, V> _map; | 
| 603   _LinkedHashMapValueIterable(this._map); | 590   _LinkedHashMapValueIterable(this._map); | 
| 604   Iterator<K> get iterator => new _LinkedHashMapValueIterator<V>(_map); | 591   Iterator<K> get iterator => new _LinkedHashMapValueIterator<V>(_map); | 
| 605   bool contains(V value) => _map.containsValue(value); | 592   bool contains(V value) => _map.containsValue(value); | 
| 606   bool get isEmpty => _map.isEmpty; | 593   bool get isEmpty => _map.isEmpty; | 
| 607   bool get isNotEmpty => _map.isNotEmpty; | 594   bool get isNotEmpty => _map.isNotEmpty; | 
| 608   int get length => _map.length; | 595   int get length => _map.length; | 
| 609 } | 596 } | 
| 610 | 597 | 
| 611 abstract class _LinkedHashMapIterator<T> implements Iterator<T> { | 598 abstract class _LinkedHashMapIterator<T> implements Iterator<T> { | 
| 612   final LinkedHashMap _map; | 599   final _LinkedHashMap _map; | 
| 613   var _next; | 600   var _next; | 
| 614   T _current; | 601   T _current; | 
| 615   int _modificationCount; | 602   int _modificationCount; | 
| 616   _LinkedHashMapIterator(LinkedHashMap map) | 603   _LinkedHashMapIterator(_LinkedHashMap map) | 
| 617       : _map = map, | 604       : _map = map, | 
| 618         _current = null, | 605         _current = null, | 
| 619         _next = map._nextEntry, | 606         _next = map._nextEntry, | 
| 620         _modificationCount = map._modificationCount; | 607         _modificationCount = map._modificationCount; | 
| 621 | 608 | 
| 622   bool moveNext() { | 609   bool moveNext() { | 
| 623     if (_modificationCount != _map._modificationCount) { | 610     if (_modificationCount != _map._modificationCount) { | 
| 624       throw new ConcurrentModificationError(_map); | 611       throw new ConcurrentModificationError(_map); | 
| 625     } | 612     } | 
| 626     if (identical(_map, _next)) { | 613     if (identical(_map, _next)) { | 
| 627       _current = null; | 614       _current = null; | 
| 628       return false; | 615       return false; | 
| 629     } | 616     } | 
| 630     _LinkedHashMapEntry entry = _next; | 617     _LinkedHashMapEntry entry = _next; | 
| 631     _next = entry._nextEntry; | 618     _next = entry._nextEntry; | 
| 632     _current = _getValue(entry); | 619     _current = _getValue(entry); | 
| 633     return true; | 620     return true; | 
| 634   } | 621   } | 
| 635 | 622 | 
| 636   T _getValue(_LinkedHashMapEntry entry); | 623   T _getValue(_LinkedHashMapEntry entry); | 
| 637 | 624 | 
| 638   T get current => _current; | 625   T get current => _current; | 
| 639 } | 626 } | 
| 640 | 627 | 
| 641 class _LinkedHashMapKeyIterator<K> extends _LinkedHashMapIterator<K> { | 628 class _LinkedHashMapKeyIterator<K> extends _LinkedHashMapIterator<K> { | 
| 642   _LinkedHashMapKeyIterator(LinkedHashMap map) : super(map); | 629   _LinkedHashMapKeyIterator(_LinkedHashMap map) : super(map); | 
| 643   K _getValue(_LinkedHashMapEntry entry) => entry.key; | 630   K _getValue(_LinkedHashMapEntry entry) => entry.key; | 
| 644 } | 631 } | 
| 645 | 632 | 
| 646 class _LinkedHashMapValueIterator<V> extends _LinkedHashMapIterator<V> { | 633 class _LinkedHashMapValueIterator<V> extends _LinkedHashMapIterator<V> { | 
| 647   _LinkedHashMapValueIterator(LinkedHashMap map) : super(map); | 634   _LinkedHashMapValueIterator(_LinkedHashMap map) : super(map); | 
| 648   V _getValue(_LinkedHashMapEntry entry) => entry.value; | 635   V _getValue(_LinkedHashMapEntry entry) => entry.value; | 
| 649 } | 636 } | 
| 650 | 637 | 
| 651 | 638 | 
| 652 /** | 639 /** | 
| 653  * A hash-based map that iterates keys and values in key insertion order. | 640  * A hash-based map that iterates keys and values in key insertion order. | 
| 654  */ | 641  */ | 
| 655 patch class LinkedHashMap<K, V> { | 642 patch class LinkedHashMap<K, V> { | 
|  | 643   static const int _INITIAL_CAPACITY = 8; | 
|  | 644   static const int _MODIFICATION_COUNT_MASK = 0x3fffffff; | 
|  | 645 | 
|  | 646   int _elementCount = 0; | 
|  | 647   List<_HashMapEntry> _buckets = new List(_INITIAL_CAPACITY); | 
|  | 648   int _modificationCount = 0; | 
|  | 649 | 
| 656   var _nextEntry; | 650   var _nextEntry; | 
| 657   var _previousEntry; | 651   var _previousEntry; | 
| 658 | 652 | 
| 659   /* patch */ factory LinkedHashMap({ bool equals(K key1, K key2), | 653   /* patch */ LinkedHashMap() { | 
| 660                                       int hashCode(K key), | 654     _nextEntry = _previousEntry = this; | 
| 661                                       bool isValidKey(potentialKey) }) { | 655   } | 
| 662     if (isValidKey == null) { | 656 | 
| 663       if (hashCode == null) { | 657   /* patch */ int get length => _elementCount; | 
| 664         if (equals == null) { | 658   /* patch */ bool get isEmpty => _elementCount == 0; | 
| 665           return new _LinkedHashMap<K, V>(); | 659   /* patch */ bool get isNotEmpty => _elementCount != 0; | 
| 666         } | 660 | 
| 667         if (identical(identical, equals)) { | 661   /* patch */ Iterable<K> get keys => new _LinkedHashMapKeyIterable<K>(this); | 
| 668           return new _LinkedIdentityHashMap<K, V>(); | 662   /* patch */ Iterable<V> get values => new _LinkedHashMapValueIterable<V>(this)
      ; | 
| 669         } | 663 | 
| 670         hashCode = _defaultHashCode; | 664   /* patch */ bool containsKey(Object key) { | 
| 671       } else if (equals == null) { | 665     int hashCode = key.hashCode; | 
| 672         equals = _defaultEquals; | 666     List buckets = _buckets; | 
| 673       } | 667     int index = hashCode & (buckets.length - 1); | 
| 674     } else { | 668     _HashMapEntry entry = buckets[index]; | 
| 675       if (hashCode == null) { | 669     while (entry != null) { | 
| 676         hashCode = _defaultHashCode; | 670       if (hashCode == entry.hashCode && entry.key == key) return true; | 
| 677       } | 671       entry = entry.next; | 
| 678       if (equals == null) { |  | 
| 679         equals = _defaultEquals; |  | 
| 680       } |  | 
| 681     } | 672     } | 
| 682     return new _LinkedCustomHashMap<K, V>(equals, hashCode, isValidKey); | 673     return false; | 
| 683   } | 674   } | 
| 684 } |  | 
| 685 | 675 | 
| 686 // Methods that are exactly the same in all three linked hash map variants. | 676   /* patch */ bool containsValue(Object value) { | 
| 687 abstract class _LinkedHashMapMixin<K, V> implements LinkedHashMap<K, V> { | 677     var cursor = _nextEntry; | 
| 688   var _nextEntry; |  | 
| 689   var _previousEntry; |  | 
| 690 |  | 
| 691   bool containsValue(Object value) { |  | 
| 692     int modificationCount = _modificationCount; | 678     int modificationCount = _modificationCount; | 
| 693     var cursor = _nextEntry; |  | 
| 694     while (!identical(cursor, this)) { | 679     while (!identical(cursor, this)) { | 
| 695       _HashMapEntry entry = cursor; | 680       _HashMapEntry entry = cursor; | 
| 696       if (entry.value == value) return true; | 681       if (entry.value == value) return true; | 
| 697       if (modificationCount != _modificationCount) { |  | 
| 698         throw new ConcurrentModificationError(this); |  | 
| 699       } |  | 
| 700       cursor = cursor._nextEntry; | 682       cursor = cursor._nextEntry; | 
| 701     } | 683     } | 
| 702     return false; | 684     return false; | 
| 703   } | 685   } | 
| 704 | 686 | 
| 705   void forEach(void action(K key, V value)) { | 687   /* patch */ V operator[](Object key) { | 
| 706     int modificationCount = _modificationCount; | 688     int hashCode = key.hashCode; | 
|  | 689     List buckets = _buckets; | 
|  | 690     int index = hashCode & (buckets.length - 1); | 
|  | 691     _HashMapEntry entry = buckets[index]; | 
|  | 692     while (entry != null) { | 
|  | 693       if (hashCode == entry.hashCode && entry.key == key) { | 
|  | 694         return entry.value; | 
|  | 695       } | 
|  | 696       entry = entry.next; | 
|  | 697     } | 
|  | 698     return null; | 
|  | 699   } | 
|  | 700 | 
|  | 701   /* patch */ void operator []=(K key, V value) { | 
|  | 702     int hashCode = key.hashCode; | 
|  | 703     List buckets = _buckets; | 
|  | 704     int length = buckets.length; | 
|  | 705     int index = hashCode & (length - 1); | 
|  | 706     _HashMapEntry entry = buckets[index]; | 
|  | 707     while (entry != null) { | 
|  | 708       if (hashCode == entry.hashCode && entry.key == key) { | 
|  | 709         entry.value = value; | 
|  | 710         return; | 
|  | 711       } | 
|  | 712       entry = entry.next; | 
|  | 713     } | 
|  | 714     _addEntry(buckets, index, length, key, value, hashCode); | 
|  | 715   } | 
|  | 716 | 
|  | 717   /* patch */ V putIfAbsent(K key, V ifAbsent()) { | 
|  | 718     int hashCode = key.hashCode; | 
|  | 719     List buckets = _buckets; | 
|  | 720     int length = buckets.length; | 
|  | 721     int index = hashCode & (length - 1); | 
|  | 722     _HashMapEntry entry = buckets[index]; | 
|  | 723     while (entry != null) { | 
|  | 724       if (hashCode == entry.hashCode && entry.key == key) { | 
|  | 725         return entry.value; | 
|  | 726       } | 
|  | 727       entry = entry.next; | 
|  | 728     } | 
|  | 729     int stamp = _modificationCount; | 
|  | 730     V value = ifAbsent(); | 
|  | 731     if (stamp == _modificationCount) { | 
|  | 732       _addEntry(buckets, index, length, key, value, hashCode); | 
|  | 733     } else { | 
|  | 734       this[key] = value; | 
|  | 735     } | 
|  | 736     return value; | 
|  | 737   } | 
|  | 738 | 
|  | 739   /* patch */ void addAll(Map<K, V> other) { | 
|  | 740     other.forEach((K key, V value) { | 
|  | 741       this[key] = value; | 
|  | 742     }); | 
|  | 743   } | 
|  | 744 | 
|  | 745   /* patch */ void forEach(void action(K key, V value)) { | 
|  | 746     int stamp = _modificationCount; | 
| 707     var cursor = _nextEntry; | 747     var cursor = _nextEntry; | 
| 708     while (!identical(cursor, this)) { | 748     while (!identical(cursor, this)) { | 
| 709       _HashMapEntry entry = cursor; | 749       _HashMapEntry entry = cursor; | 
| 710       action(entry.key, entry.value); | 750       action(entry.key, entry.value); | 
| 711       if (modificationCount != _modificationCount) { | 751       if (stamp != _modificationCount) { | 
| 712         throw new ConcurrentModificationError(this); | 752         throw new ConcurrentModificationError(this); | 
| 713       } | 753       } | 
| 714       cursor = cursor._nextEntry; | 754       cursor = cursor._nextEntry; | 
| 715     } | 755     } | 
| 716   } | 756   } | 
| 717 | 757 | 
| 718   void clear() { | 758   /* patch */ V remove(Object key) { | 
|  | 759     int hashCode = key.hashCode; | 
|  | 760     List buckets = _buckets; | 
|  | 761     int index = hashCode & (buckets.length - 1); | 
|  | 762     _LinkedHashMapEntry entry = buckets[index]; | 
|  | 763     _HashMapEntry previous = null; | 
|  | 764     while (entry != null) { | 
|  | 765       _HashMapEntry next = entry.next; | 
|  | 766       if (hashCode == entry.hashCode && entry.key == key) { | 
|  | 767         if (previous == null) { | 
|  | 768           buckets[index] = next; | 
|  | 769         } else { | 
|  | 770           previous.next = next; | 
|  | 771         } | 
|  | 772         entry._previousEntry._nextEntry = entry._nextEntry; | 
|  | 773         entry._nextEntry._previousEntry = entry._previousEntry; | 
|  | 774         entry._nextEntry = entry._previousEntry = null; | 
|  | 775         _elementCount--; | 
|  | 776         _modificationCount = | 
|  | 777             (_modificationCount + 1) & _MODIFICATION_COUNT_MASK; | 
|  | 778         return entry.value; | 
|  | 779       } | 
|  | 780       previous = entry; | 
|  | 781       entry = next; | 
|  | 782     } | 
|  | 783     return null; | 
|  | 784   } | 
|  | 785 | 
|  | 786   /* patch */ void clear() { | 
|  | 787     _elementCount = 0; | 
| 719     _nextEntry = _previousEntry = this; | 788     _nextEntry = _previousEntry = this; | 
| 720     _elementCount = 0; | 789     _buckets = new List(_INITIAL_CAPACITY); | 
| 721     _buckets = new List(_HashMap._INITIAL_CAPACITY); |  | 
| 722     _modificationCount = (_modificationCount + 1) & _MODIFICATION_COUNT_MASK; | 790     _modificationCount = (_modificationCount + 1) & _MODIFICATION_COUNT_MASK; | 
| 723   } | 791   } | 
| 724 | 792 | 
| 725   void _addEntry(List buckets, int index, int length, | 793   void _addEntry(List buckets, int index, int length, | 
| 726                  K key, V value, int hashCode) { | 794                  K key, V value, int hashCode) { | 
| 727     _HashMapEntry entry = | 795     _HashMapEntry entry = | 
| 728         new _LinkedHashMapEntry(key, value, hashCode, buckets[index], | 796         new _LinkedHashMapEntry(key, value, hashCode, buckets[index], | 
| 729                                 _previousEntry, this); | 797                                 _previousEntry, this); | 
| 730     buckets[index] = entry; | 798     buckets[index] = entry; | 
| 731     int newElements = _elementCount + 1; | 799     int newElements = _elementCount + 1; | 
| 732     _elementCount = newElements; | 800     _elementCount = newElements; | 
| 733     // If we end up with more than 75% non-empty entries, we | 801     // If we end up with more than 75% non-empty entries, we | 
| 734     // resize the backing store. | 802     // resize the backing store. | 
| 735     if ((newElements << 2) > ((length << 1) + length)) _resize(); | 803     if ((newElements << 2) > ((length << 1) + length)) _resize(); | 
| 736     _modificationCount = (_modificationCount + 1) & _MODIFICATION_COUNT_MASK; | 804     _modificationCount = (_modificationCount + 1) & _MODIFICATION_COUNT_MASK; | 
| 737   } | 805   } | 
| 738 | 806 | 
| 739   void _removeEntry(_LinkedHashMapEntry entry, | 807   void _resize() { | 
| 740                     _HashMapEntry previousInBucket, | 808     List oldBuckets = _buckets; | 
| 741                     int bucketIndex) { | 809     int oldLength = oldBuckets.length; | 
| 742     var previousInChain = entry._previousEntry; | 810     int newLength = oldLength << 1; | 
| 743     var nextInChain = entry._nextEntry; | 811     List newBuckets = new List(newLength); | 
| 744     previousInChain._nextEntry = nextInChain; | 812     for (int i = 0; i < oldLength; i++) { | 
| 745     nextInChain._previousEntry = previousInChain; | 813       _HashMapEntry entry = oldBuckets[i]; | 
| 746     if (previousInBucket == null) { | 814       while (entry != null) { | 
| 747       _buckets[bucketIndex] = entry.next; | 815         _HashMapEntry next = entry.next; | 
| 748     } else { | 816         int hashCode = entry.hashCode; | 
| 749       previousInBucket.next = entry.next; | 817         int index = hashCode & (newLength - 1); | 
|  | 818         entry.next = newBuckets[index]; | 
|  | 819         newBuckets[index] = entry; | 
|  | 820         entry = next; | 
|  | 821       } | 
| 750     } | 822     } | 
| 751   } | 823     _buckets = newBuckets; | 
| 752 |  | 
| 753 |  | 
| 754   Iterable<K> get keys => new _LinkedHashMapKeyIterable<K>(this); |  | 
| 755   Iterable<V> get values => new _LinkedHashMapValueIterable<V>(this); |  | 
| 756 } |  | 
| 757 |  | 
| 758 class _LinkedHashMap<K, V> extends _HashMap<K, V> |  | 
| 759                            with _LinkedHashMapMixin<K, V> { |  | 
| 760   _LinkedHashMap() { |  | 
| 761     _nextEntry = _previousEntry = this; |  | 
| 762   } | 824   } | 
| 763 } | 825 } | 
| 764 | 826 | 
| 765 class _LinkedIdentityHashMap<K, V> extends _IdentityHashMap<K, V> |  | 
| 766                                    with _LinkedHashMapMixin<K, V> { |  | 
| 767   _LinkedIdentityHashMap() { |  | 
| 768     _nextEntry = _previousEntry = this; |  | 
| 769   } |  | 
| 770 } |  | 
| 771 |  | 
| 772 class _LinkedCustomHashMap<K, V> extends _CustomHashMap<K, V> |  | 
| 773                                  with _LinkedHashMapMixin<K, V> { |  | 
| 774   _LinkedCustomHashMap(bool equals(K key1, K key2), |  | 
| 775                        int hashCode(K key), |  | 
| 776                        bool isValidKey(potentialKey)) |  | 
| 777       : super(equals, hashCode, isValidKey) { |  | 
| 778     _nextEntry = _previousEntry = this; |  | 
| 779   } |  | 
| 780 } |  | 
| 781 |  | 
| 782 |  | 
| 783 patch class LinkedHashSet<E> extends _HashSetBase<E> { | 827 patch class LinkedHashSet<E> extends _HashSetBase<E> { | 
| 784   static const int _INITIAL_CAPACITY = 8; | 828   static const int _INITIAL_CAPACITY = 8; | 
| 785   _LinkedHashTable<E> _table; | 829   _LinkedHashTable<E> _table; | 
| 786 | 830 | 
| 787   /* patch */ LinkedHashSet() { | 831   /* patch */ LinkedHashSet() { | 
| 788     _table = new _LinkedHashTable(_INITIAL_CAPACITY); | 832     _table = new _LinkedHashTable(_INITIAL_CAPACITY); | 
| 789     _table._container = this; | 833     _table._container = this; | 
| 790   } | 834   } | 
| 791 | 835 | 
| 792   // Iterable. | 836   // Iterable. | 
| (...skipping 680 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 1473 | 1517 | 
| 1474   _LinkedHashMapTable() : super(_INITIAL_CAPACITY); | 1518   _LinkedHashMapTable() : super(_INITIAL_CAPACITY); | 
| 1475 | 1519 | 
| 1476   V _value(int offset) => _table[offset + _VALUE_INDEX]; | 1520   V _value(int offset) => _table[offset + _VALUE_INDEX]; | 
| 1477   void _setValue(int offset, V value) { _table[offset + _VALUE_INDEX] = value; } | 1521   void _setValue(int offset, V value) { _table[offset + _VALUE_INDEX] = value; } | 
| 1478 | 1522 | 
| 1479   _copyEntry(List oldTable, int fromOffset, int toOffset) { | 1523   _copyEntry(List oldTable, int fromOffset, int toOffset) { | 
| 1480     _table[toOffset + _VALUE_INDEX] = oldTable[fromOffset + _VALUE_INDEX]; | 1524     _table[toOffset + _VALUE_INDEX] = oldTable[fromOffset + _VALUE_INDEX]; | 
| 1481   } | 1525   } | 
| 1482 } | 1526 } | 
| OLD | NEW | 
|---|