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