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