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 |