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 bool isValidKey(potentialKey) }) { |
9 if (isValidKey == null) { | 9 if (isValidKey == null) { |
10 if (hashCode == null) { | 10 if (hashCode == null) { |
11 if (equals == null) { | 11 if (equals == null) { |
12 return new _HashMap<K, V>(); | 12 return new _HashMap<K, V>(); |
13 } | 13 } |
14 if (identical(identical, equals)) { | 14 hashCode = _defaultHashCode; |
| 15 } else { |
| 16 if (identical(identityHashCode, hashCode) && |
| 17 identical(identical, equals)) { |
15 return new _IdentityHashMap<K, V>(); | 18 return new _IdentityHashMap<K, V>(); |
16 } | 19 } |
17 hashCode = _defaultHashCode; | 20 if (equals == null) { |
18 } else if (equals == null) { | 21 equals = _defaultEquals; |
19 equals = _defaultEquals; | 22 } |
20 } | 23 } |
21 } else { | 24 } else { |
22 if (hashCode == null) { | 25 if (hashCode == null) { |
23 hashCode = _defaultHashCode; | 26 hashCode = _defaultHashCode; |
24 } | 27 } |
25 if (equals == null) { | 28 if (equals == null) { |
26 equals = _defaultEquals; | 29 equals = _defaultEquals; |
27 } | 30 } |
28 } | 31 } |
29 return new _CustomHashMap<K, V>(equals, hashCode, isValidKey); | 32 return new _CustomHashMap<K, V>(equals, hashCode, isValidKey); |
30 } | 33 } |
| 34 |
| 35 /* patch */ factory HashMap.identity() = _IdentityHashMap<K, V>; |
31 } | 36 } |
32 | 37 |
| 38 |
33 const int _MODIFICATION_COUNT_MASK = 0x3fffffff; | 39 const int _MODIFICATION_COUNT_MASK = 0x3fffffff; |
34 | 40 |
35 class _HashMap<K, V> implements HashMap<K, V> { | 41 class _HashMap<K, V> implements HashMap<K, V> { |
36 static const int _INITIAL_CAPACITY = 8; | 42 static const int _INITIAL_CAPACITY = 8; |
37 | 43 |
38 | 44 |
39 int _elementCount = 0; | 45 int _elementCount = 0; |
40 List<_HashMapEntry> _buckets = new List(_INITIAL_CAPACITY); | 46 List<_HashMapEntry> _buckets = new List(_INITIAL_CAPACITY); |
41 int _modificationCount = 0; | 47 int _modificationCount = 0; |
42 | 48 |
(...skipping 270 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
313 } | 319 } |
314 return null; | 320 return null; |
315 } | 321 } |
316 | 322 |
317 String toString() => Maps.mapToString(this); | 323 String toString() => Maps.mapToString(this); |
318 } | 324 } |
319 | 325 |
320 class _IdentityHashMap<K, V> extends _HashMap<K, V> { | 326 class _IdentityHashMap<K, V> extends _HashMap<K, V> { |
321 | 327 |
322 bool containsKey(Object key) { | 328 bool containsKey(Object key) { |
323 int hashCode = key.hashCode; | 329 int hashCode = identityHashCode(key); |
324 List buckets = _buckets; | 330 List buckets = _buckets; |
325 int index = hashCode & (buckets.length - 1); | 331 int index = hashCode & (buckets.length - 1); |
326 _HashMapEntry entry = buckets[index]; | 332 _HashMapEntry entry = buckets[index]; |
327 while (entry != null) { | 333 while (entry != null) { |
328 if (hashCode == entry.hashCode && identical(entry.key, key)) return true; | 334 if (hashCode == entry.hashCode && identical(entry.key, key)) return true; |
329 entry = entry.next; | 335 entry = entry.next; |
330 } | 336 } |
331 return false; | 337 return false; |
332 } | 338 } |
333 | 339 |
334 V operator[](Object key) { | 340 V operator[](Object key) { |
335 int hashCode = key.hashCode; | 341 int hashCode = identityHashCode(key); |
336 List buckets = _buckets; | 342 List buckets = _buckets; |
337 int index = hashCode & (buckets.length - 1); | 343 int index = hashCode & (buckets.length - 1); |
338 _HashMapEntry entry = buckets[index]; | 344 _HashMapEntry entry = buckets[index]; |
339 while (entry != null) { | 345 while (entry != null) { |
340 if (hashCode == entry.hashCode && identical(entry.key, key)) { | 346 if (hashCode == entry.hashCode && identical(entry.key, key)) { |
341 return entry.value; | 347 return entry.value; |
342 } | 348 } |
343 entry = entry.next; | 349 entry = entry.next; |
344 } | 350 } |
345 return null; | 351 return null; |
346 } | 352 } |
347 | 353 |
348 void operator []=(K key, V value) { | 354 void operator []=(K key, V value) { |
349 int hashCode = key.hashCode; | 355 int hashCode = identityHashCode(key); |
350 List buckets = _buckets; | 356 List buckets = _buckets; |
351 int length = buckets.length; | 357 int length = buckets.length; |
352 int index = hashCode & (length - 1); | 358 int index = hashCode & (length - 1); |
353 _HashMapEntry entry = buckets[index]; | 359 _HashMapEntry entry = buckets[index]; |
354 while (entry != null) { | 360 while (entry != null) { |
355 if (hashCode == entry.hashCode && identical(entry.key, key)) { | 361 if (hashCode == entry.hashCode && identical(entry.key, key)) { |
356 entry.value = value; | 362 entry.value = value; |
357 return; | 363 return; |
358 } | 364 } |
359 entry = entry.next; | 365 entry = entry.next; |
360 } | 366 } |
361 _addEntry(buckets, index, length, key, value, hashCode); | 367 _addEntry(buckets, index, length, key, value, hashCode); |
362 } | 368 } |
363 | 369 |
364 V putIfAbsent(K key, V ifAbsent()) { | 370 V putIfAbsent(K key, V ifAbsent()) { |
365 int hashCode = key.hashCode; | 371 int hashCode = identityHashCode(key); |
366 List buckets = _buckets; | 372 List buckets = _buckets; |
367 int length = buckets.length; | 373 int length = buckets.length; |
368 int index = hashCode & (length - 1); | 374 int index = hashCode & (length - 1); |
369 _HashMapEntry entry = buckets[index]; | 375 _HashMapEntry entry = buckets[index]; |
370 while (entry != null) { | 376 while (entry != null) { |
371 if (hashCode == entry.hashCode && identical(entry.key, key)) { | 377 if (hashCode == entry.hashCode && identical(entry.key, key)) { |
372 return entry.value; | 378 return entry.value; |
373 } | 379 } |
374 entry = entry.next; | 380 entry = entry.next; |
375 } | 381 } |
376 int stamp = _modificationCount; | 382 int stamp = _modificationCount; |
377 V value = ifAbsent(); | 383 V value = ifAbsent(); |
378 if (stamp == _modificationCount) { | 384 if (stamp == _modificationCount) { |
379 _addEntry(buckets, index, length, key, value, hashCode); | 385 _addEntry(buckets, index, length, key, value, hashCode); |
380 } else { | 386 } else { |
381 this[key] = value; | 387 this[key] = value; |
382 } | 388 } |
383 return value; | 389 return value; |
384 } | 390 } |
385 | 391 |
386 V remove(Object key) { | 392 V remove(Object key) { |
387 int hashCode = key.hashCode; | 393 int hashCode = identityHashCode(key); |
388 List buckets = _buckets; | 394 List buckets = _buckets; |
389 int index = hashCode & (buckets.length - 1); | 395 int index = hashCode & (buckets.length - 1); |
390 _HashMapEntry entry = buckets[index]; | 396 _HashMapEntry entry = buckets[index]; |
391 _HashMapEntry previous = null; | 397 _HashMapEntry previous = null; |
392 while (entry != null) { | 398 while (entry != null) { |
393 _HashMapEntry next = entry.next; | 399 _HashMapEntry next = entry.next; |
394 if (hashCode == entry.hashCode && identical(entry.key, key)) { | 400 if (hashCode == entry.hashCode && identical(entry.key, key)) { |
395 _removeEntry(entry, previous, index); | 401 _removeEntry(entry, previous, index); |
396 _elementCount--; | 402 _elementCount--; |
397 _modificationCount = | 403 _modificationCount = |
(...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
502 | 508 |
503 patch class HashSet<E> { | 509 patch class HashSet<E> { |
504 /* patch */ factory HashSet({ bool equals(E e1, E e2), | 510 /* patch */ factory HashSet({ bool equals(E e1, E e2), |
505 int hashCode(E e), | 511 int hashCode(E e), |
506 bool isValidKey(potentialKey) }) { | 512 bool isValidKey(potentialKey) }) { |
507 if (isValidKey == null) { | 513 if (isValidKey == null) { |
508 if (hashCode == null) { | 514 if (hashCode == null) { |
509 if (equals == null) { | 515 if (equals == null) { |
510 return new _HashSet<E>(); | 516 return new _HashSet<E>(); |
511 } | 517 } |
512 if (identical(identical, equals)) { | 518 hashCode = _defaultHashCode; |
| 519 } else { |
| 520 if (identical(identityHashCode, hashCode) && |
| 521 identical(identical, equals)) { |
513 return new _IdentityHashSet<E>(); | 522 return new _IdentityHashSet<E>(); |
514 } | 523 } |
515 _hashCode = _defaultHashCode; | 524 if (equals == null) { |
516 } else if (equals == null) { | 525 equals = _defaultEquals; |
517 _equals = _defaultEquals; | 526 } |
518 } | 527 } |
519 isValidKey = new _TypeTest<E>().test; | |
520 } else { | 528 } else { |
521 if (hashCode == null) hashCode = _defaultHashCode; | 529 if (hashCode == null) { |
522 if (equals == null) equals = _defaultEquals; | 530 hashCode = _defaultHashCode; |
| 531 } |
| 532 if (equals == null) { |
| 533 equals = _defaultEquals; |
| 534 } |
523 } | 535 } |
524 return new _CustomHashSet<E>(equals, hashCode, isValidKey); | 536 return new _CustomHashSet<E>(equals, hashCode, isValidKey); |
525 } | 537 } |
| 538 |
| 539 /* patch */ factory HashSet.identity() = _IdentityHashSet<E>; |
526 } | 540 } |
527 | 541 |
528 class _HashSet<E> extends _HashSetBase<E> implements HashSet<E> { | 542 class _HashSet<E> extends _HashSetBase<E> implements HashSet<E> { |
529 static const int _INITIAL_CAPACITY = 8; | 543 static const int _INITIAL_CAPACITY = 8; |
530 | 544 |
531 List<_HashSetEntry> _buckets = new List(_INITIAL_CAPACITY); | 545 List<_HashSetEntry> _buckets = new List(_INITIAL_CAPACITY); |
532 int _elementCount = 0; | 546 int _elementCount = 0; |
533 int _modificationCount = 0; | 547 int _modificationCount = 0; |
534 | 548 |
535 bool _equals(e1, e2) => e1 == e2; | 549 bool _equals(e1, e2) => e1 == e2; |
(...skipping 145 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
681 entry = next; | 695 entry = next; |
682 } | 696 } |
683 } | 697 } |
684 _buckets = newBuckets; | 698 _buckets = newBuckets; |
685 } | 699 } |
686 | 700 |
687 HashSet<E> _newSet() => new _HashSet<E>(); | 701 HashSet<E> _newSet() => new _HashSet<E>(); |
688 } | 702 } |
689 | 703 |
690 class _IdentityHashSet<E> extends _HashSet<E> { | 704 class _IdentityHashSet<E> extends _HashSet<E> { |
| 705 int _hashCode(e) => identityHashCode(e); |
691 bool _equals(e1, e2) => identical(e1, e2); | 706 bool _equals(e1, e2) => identical(e1, e2); |
692 HashSet<E> _newSet() => new _IdentityHashSet<E>(); | 707 HashSet<E> _newSet() => new _IdentityHashSet<E>(); |
693 } | 708 } |
694 | 709 |
695 class _CustomHashSet<E> extends _HashSet<E> { | 710 class _CustomHashSet<E> extends _HashSet<E> { |
696 final _Equality<E> _equality; | 711 final _Equality<E> _equality; |
697 final _Hasher<E> _hasher; | 712 final _Hasher<E> _hasher; |
698 final _Predicate _validKey; | 713 final _Predicate _validKey; |
699 _CustomHashSet(this._equality, this._hasher, this._validKey); | 714 _CustomHashSet(this._equality, this._hasher, bool validKey(Object o)) |
| 715 : _validKey = (validKey != null) ? validKey : new _TypeTest<E>().test; |
700 | 716 |
701 bool remove(Object element) { | 717 bool remove(Object element) { |
702 if (!_validKey(element)) return false; | 718 if (!_validKey(element)) return false; |
703 return super.remove(element); | 719 return super.remove(element); |
704 } | 720 } |
705 | 721 |
706 bool contains(Object element) { | 722 bool contains(Object element) { |
707 if (!_validKey(element)) return false; | 723 if (!_validKey(element)) return false; |
708 return super.contains(element); | 724 return super.contains(element); |
709 } | 725 } |
(...skipping 160 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
870 var _previousEntry; | 886 var _previousEntry; |
871 | 887 |
872 /* patch */ factory LinkedHashMap({ bool equals(K key1, K key2), | 888 /* patch */ factory LinkedHashMap({ bool equals(K key1, K key2), |
873 int hashCode(K key), | 889 int hashCode(K key), |
874 bool isValidKey(potentialKey) }) { | 890 bool isValidKey(potentialKey) }) { |
875 if (isValidKey == null) { | 891 if (isValidKey == null) { |
876 if (hashCode == null) { | 892 if (hashCode == null) { |
877 if (equals == null) { | 893 if (equals == null) { |
878 return new _LinkedHashMap<K, V>(); | 894 return new _LinkedHashMap<K, V>(); |
879 } | 895 } |
880 if (identical(identical, equals)) { | 896 hashCode = _defaultHashCode; |
| 897 } else { |
| 898 if (identical(identityHashCode, hashCode) && |
| 899 identical(identical, equals)) { |
881 return new _LinkedIdentityHashMap<K, V>(); | 900 return new _LinkedIdentityHashMap<K, V>(); |
882 } | 901 } |
883 hashCode = _defaultHashCode; | 902 if (equals == null) { |
884 } else if (equals == null) { | 903 equals = _defaultEquals; |
885 equals = _defaultEquals; | 904 } |
886 } | 905 } |
887 } else { | 906 } else { |
888 if (hashCode == null) { | 907 if (hashCode == null) { |
889 hashCode = _defaultHashCode; | 908 hashCode = _defaultHashCode; |
890 } | 909 } |
891 if (equals == null) { | 910 if (equals == null) { |
892 equals = _defaultEquals; | 911 equals = _defaultEquals; |
893 } | 912 } |
894 } | 913 } |
895 return new _LinkedCustomHashMap<K, V>(equals, hashCode, isValidKey); | 914 return new _LinkedCustomHashMap<K, V>(equals, hashCode, isValidKey); |
896 } | 915 } |
| 916 |
| 917 /* patch */ factory LinkedHashMap.identity() = _LinkedIdentityHashMap<K, V>; |
897 } | 918 } |
898 | 919 |
899 // Methods that are exactly the same in all three linked hash map variants. | 920 // Methods that are exactly the same in all three linked hash map variants. |
900 abstract class _LinkedHashMapMixin<K, V> implements LinkedHashMap<K, V> { | 921 abstract class _LinkedHashMapMixin<K, V> implements LinkedHashMap<K, V> { |
901 var _nextEntry; | 922 var _nextEntry; |
902 var _previousEntry; | 923 var _previousEntry; |
903 | 924 |
904 | 925 |
905 bool containsValue(Object value) { | 926 bool containsValue(Object value) { |
906 int modificationCount = _modificationCount; | 927 int modificationCount = _modificationCount; |
(...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
997 | 1018 |
998 patch class LinkedHashSet<E> { | 1019 patch class LinkedHashSet<E> { |
999 /* patch */ factory LinkedHashSet({ bool equals(E e1, E e2), | 1020 /* patch */ factory LinkedHashSet({ bool equals(E e1, E e2), |
1000 int hashCode(E e), | 1021 int hashCode(E e), |
1001 bool isValidKey(potentialKey) }) { | 1022 bool isValidKey(potentialKey) }) { |
1002 if (isValidKey == null) { | 1023 if (isValidKey == null) { |
1003 if (hashCode == null) { | 1024 if (hashCode == null) { |
1004 if (equals == null) { | 1025 if (equals == null) { |
1005 return new _LinkedHashSet<E>(); | 1026 return new _LinkedHashSet<E>(); |
1006 } | 1027 } |
1007 if (identical(identical, equals)) { | 1028 hashCode = _defaultHashCode; |
| 1029 } else { |
| 1030 if (identical(identityHashCode, hashCode) && |
| 1031 identical(identical, equals)) { |
1008 return new _LinkedIdentityHashSet<E>(); | 1032 return new _LinkedIdentityHashSet<E>(); |
1009 } | 1033 } |
1010 _hashCode = _defaultHashCode; | 1034 if (equals == null) { |
1011 } else if (equals == null) { | 1035 equals = _defaultEquals; |
1012 _equals = _defaultEquals; | 1036 } |
1013 } | 1037 } |
1014 isValidKey = new _TypeTest<E>().test; | |
1015 } else { | 1038 } else { |
1016 if (hashCode == null) hashCode = _defaultHashCode; | 1039 if (hashCode == null) { |
1017 if (equals == null) equals = _defaultEquals; | 1040 hashCode = _defaultHashCode; |
| 1041 } |
| 1042 if (equals == null) { |
| 1043 equals = _defaultEquals; |
| 1044 } |
1018 } | 1045 } |
1019 return new _LinkedCustomHashSet<E>(equals, hashCode, isValidKey); | 1046 return new _LinkedCustomHashSet<E>(equals, hashCode, isValidKey); |
1020 } | 1047 } |
| 1048 |
| 1049 /* patch */ factory LinkedHashSet.identity() = _LinkedIdentityHashSet<E>; |
1021 } | 1050 } |
1022 | 1051 |
1023 class _LinkedHashSetEntry extends _HashSetEntry { | 1052 class _LinkedHashSetEntry extends _HashSetEntry { |
1024 /// Links this element into a double-linked list of elements of a hash set. | 1053 /// Links this element into a double-linked list of elements of a hash set. |
1025 /// The hash set object itself is used as the head entry of the list, so | 1054 /// The hash set object itself is used as the head entry of the list, so |
1026 /// the field is typed as "var". | 1055 /// the field is typed as "var". |
1027 /// Both links are initialized to `this` when the object is created. | 1056 /// Both links are initialized to `this` when the object is created. |
1028 var _nextEntry; | 1057 var _nextEntry; |
1029 var _previousEntry; | 1058 var _previousEntry; |
1030 _LinkedHashSetEntry(var key, int hashCode, _LinkedHashSetEntry next, | 1059 _LinkedHashSetEntry(var key, int hashCode, _LinkedHashSetEntry next, |
(...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1122 | 1151 |
1123 void clear() { | 1152 void clear() { |
1124 _nextEntry = _previousEntry = this; | 1153 _nextEntry = _previousEntry = this; |
1125 super.clear(); | 1154 super.clear(); |
1126 } | 1155 } |
1127 | 1156 |
1128 HashSet<E> _newSet() => new _LinkedHashSet<E>(); | 1157 HashSet<E> _newSet() => new _LinkedHashSet<E>(); |
1129 } | 1158 } |
1130 | 1159 |
1131 class _LinkedIdentityHashSet<E> extends _LinkedHashSet<E> { | 1160 class _LinkedIdentityHashSet<E> extends _LinkedHashSet<E> { |
| 1161 int _hashCode(e) => identityHashCode(e); |
1132 bool _equals(e1, e2) => identical(e1, e2); | 1162 bool _equals(e1, e2) => identical(e1, e2); |
1133 HashSet<E> _newSet() => new _LinkedIdentityHashSet<E>(); | 1163 HashSet<E> _newSet() => new _LinkedIdentityHashSet<E>(); |
1134 } | 1164 } |
1135 | 1165 |
1136 class _LinkedCustomHashSet<E> extends _LinkedHashSet<E> { | 1166 class _LinkedCustomHashSet<E> extends _LinkedHashSet<E> { |
1137 final _Equality<E> _equality; | 1167 final _Equality<E> _equality; |
1138 final _Hasher<E> _hasher; | 1168 final _Hasher<E> _hasher; |
1139 final _Predicate _validKey; | 1169 final _Predicate _validKey; |
1140 | 1170 |
1141 _LinkedCustomHashSet(this._equality, this._hasher, bool validKey(object)) | 1171 _LinkedCustomHashSet(this._equality, this._hasher, bool validKey(Object o)) |
1142 : _validKey = (validKey != null) ? validKey : new _TypeTest<E>().test; | 1172 : _validKey = (validKey != null) ? validKey : new _TypeTest<E>().test; |
1143 | 1173 |
1144 bool _equals(e1, e2) => _equality(e1, e2); | 1174 bool _equals(e1, e2) => _equality(e1, e2); |
1145 | 1175 |
1146 int _hashCode(e) => _hasher(e); | 1176 int _hashCode(e) => _hasher(e); |
1147 | 1177 |
1148 bool contains(Object o) { | 1178 bool contains(Object o) { |
1149 if (!_validKey(o)) return false; | 1179 if (!_validKey(o)) return false; |
1150 return super.contains(o); | 1180 return super.contains(o); |
1151 } | 1181 } |
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1198 return false; | 1228 return false; |
1199 } | 1229 } |
1200 _LinkedHashSetEntry entry = _next; | 1230 _LinkedHashSetEntry entry = _next; |
1201 _current = entry.key; | 1231 _current = entry.key; |
1202 _next = entry._nextEntry; | 1232 _next = entry._nextEntry; |
1203 return true; | 1233 return true; |
1204 } | 1234 } |
1205 | 1235 |
1206 E get current => _current; | 1236 E get current => _current; |
1207 } | 1237 } |
OLD | NEW |