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 |