| 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) { |
| (...skipping 900 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 911 var _previousEntry; | 911 var _previousEntry; |
| 912 | 912 |
| 913 /* patch */ factory LinkedHashMap({ bool equals(K key1, K key2), | 913 /* patch */ factory LinkedHashMap({ bool equals(K key1, K key2), |
| 914 int hashCode(K key), | 914 int hashCode(K key), |
| 915 bool isValidKey(potentialKey) }) { | 915 bool isValidKey(potentialKey) }) { |
| 916 if (isValidKey == null) { | 916 if (isValidKey == null) { |
| 917 if (hashCode == null) { | 917 if (hashCode == null) { |
| 918 if (equals == null) { | 918 if (equals == null) { |
| 919 if (_useInternalCached) { | 919 if (_useInternalCached) { |
| 920 return new _InternalLinkedHashMap<K, V>(); | 920 return new _InternalLinkedHashMap<K, V>(); |
| 921 } else if (_useCompactCached) { | 921 } else { |
| 922 return new _CompactLinkedHashMap<K, V>(); | 922 return new _CompactLinkedHashMap<K, V>(); |
| 923 } else { | |
| 924 return new _LinkedHashMap<K, V>(); | |
| 925 } | 923 } |
| 926 } | 924 } |
| 927 hashCode = _defaultHashCode; | 925 hashCode = _defaultHashCode; |
| 928 } else { | 926 } else { |
| 929 if (identical(identityHashCode, hashCode) && | 927 if (identical(identityHashCode, hashCode) && |
| 930 identical(identical, equals)) { | 928 identical(identical, equals)) { |
| 931 return new _LinkedIdentityHashMap<K, V>(); | 929 return new _CompactLinkedIdentityHashMap<K, V>(); |
| 932 } | 930 } |
| 933 if (equals == null) { | 931 if (equals == null) { |
| 934 equals = _defaultEquals; | 932 equals = _defaultEquals; |
| 935 } | 933 } |
| 936 } | 934 } |
| 937 } else { | 935 } else { |
| 938 if (hashCode == null) { | 936 if (hashCode == null) { |
| 939 hashCode = _defaultHashCode; | 937 hashCode = _defaultHashCode; |
| 940 } | 938 } |
| 941 if (equals == null) { | 939 if (equals == null) { |
| 942 equals = _defaultEquals; | 940 equals = _defaultEquals; |
| 943 } | 941 } |
| 944 } | 942 } |
| 945 return new _LinkedCustomHashMap<K, V>(equals, hashCode, isValidKey); | 943 return new _CompactLinkedCustomHashMap<K, V>(equals, hashCode, isValidKey); |
| 946 } | 944 } |
| 947 | 945 |
| 948 /* patch */ factory LinkedHashMap.identity() = _LinkedIdentityHashMap<K, V>; | 946 /* patch */ factory LinkedHashMap.identity() = |
| 947 _CompactLinkedIdentityHashMap<K, V>; |
| 949 | 948 |
| 950 static final bool _useInternalCached = _useInternal; | 949 static final bool _useInternalCached = _useInternal; |
| 951 static bool get _useInternal native "LinkedHashMap_useInternal"; | 950 static bool get _useInternal native "LinkedHashMap_useInternal"; |
| 952 static final bool _useCompactCached = _useCompact; | |
| 953 static bool get _useCompact native "LinkedHashMap_useCompact"; | |
| 954 } | 951 } |
| 955 | 952 |
| 956 // Methods that are exactly the same in all three linked hash map variants. | |
| 957 abstract class _LinkedHashMapMixin<K, V> implements LinkedHashMap<K, V> { | |
| 958 var _nextEntry; | |
| 959 var _previousEntry; | |
| 960 | |
| 961 | |
| 962 bool containsValue(Object value) { | |
| 963 int modificationCount = _modificationCount; | |
| 964 var cursor = _nextEntry; | |
| 965 while (!identical(cursor, this)) { | |
| 966 _HashMapEntry entry = cursor; | |
| 967 if (entry.value == value) return true; | |
| 968 if (modificationCount != _modificationCount) { | |
| 969 throw new ConcurrentModificationError(this); | |
| 970 } | |
| 971 cursor = cursor._nextEntry; | |
| 972 } | |
| 973 return false; | |
| 974 } | |
| 975 | |
| 976 void forEach(void action(K key, V value)) { | |
| 977 int modificationCount = _modificationCount; | |
| 978 var cursor = _nextEntry; | |
| 979 while (!identical(cursor, this)) { | |
| 980 _HashMapEntry entry = cursor; | |
| 981 action(entry.key, entry.value); | |
| 982 if (modificationCount != _modificationCount) { | |
| 983 throw new ConcurrentModificationError(this); | |
| 984 } | |
| 985 cursor = cursor._nextEntry; | |
| 986 } | |
| 987 } | |
| 988 | |
| 989 void clear() { | |
| 990 _nextEntry = _previousEntry = this; | |
| 991 _buckets = new List(_HashMap._INITIAL_CAPACITY); | |
| 992 if (_elementCount > 0) { | |
| 993 _elementCount = 0; | |
| 994 _modificationCount = (_modificationCount + 1) & _MODIFICATION_COUNT_MASK; | |
| 995 } | |
| 996 } | |
| 997 | |
| 998 void _addEntry(List buckets, int index, int length, | |
| 999 K key, V value, int hashCode) { | |
| 1000 _HashMapEntry entry = | |
| 1001 new _LinkedHashMapEntry(key, value, hashCode, buckets[index], | |
| 1002 _previousEntry, this); | |
| 1003 buckets[index] = entry; | |
| 1004 int newElements = _elementCount + 1; | |
| 1005 _elementCount = newElements; | |
| 1006 | |
| 1007 // If we end up with more than 75% non-empty entries, we | |
| 1008 // resize the backing store. | |
| 1009 if ((newElements << 2) > ((length << 1) + length)) _resize(); | |
| 1010 _modificationCount = (_modificationCount + 1) & _MODIFICATION_COUNT_MASK; | |
| 1011 } | |
| 1012 | |
| 1013 void _removeEntry(_LinkedHashMapEntry entry, | |
| 1014 _HashMapEntry previousInBucket, | |
| 1015 int bucketIndex) { | |
| 1016 var previousInChain = entry._previousEntry; | |
| 1017 var nextInChain = entry._nextEntry; | |
| 1018 previousInChain._nextEntry = nextInChain; | |
| 1019 nextInChain._previousEntry = previousInChain; | |
| 1020 if (previousInBucket == null) { | |
| 1021 _buckets[bucketIndex] = entry.next; | |
| 1022 } else { | |
| 1023 previousInBucket.next = entry.next; | |
| 1024 } | |
| 1025 } | |
| 1026 | |
| 1027 | |
| 1028 Iterable<K> get keys => new _LinkedHashMapKeyIterable<K>(this); | |
| 1029 Iterable<V> get values => new _LinkedHashMapValueIterable<V>(this); | |
| 1030 } | |
| 1031 | |
| 1032 class _LinkedHashMap<K, V> extends _HashMap<K, V> | |
| 1033 with _LinkedHashMapMixin<K, V> { | |
| 1034 _LinkedHashMap() { | |
| 1035 _nextEntry = _previousEntry = this; | |
| 1036 } | |
| 1037 | |
| 1038 Set<K> _newKeySet() => new _LinkedHashSet<K>(); | |
| 1039 } | |
| 1040 | |
| 1041 class _LinkedIdentityHashMap<K, V> extends _IdentityHashMap<K, V> | |
| 1042 with _LinkedHashMapMixin<K, V> { | |
| 1043 _LinkedIdentityHashMap() { | |
| 1044 _nextEntry = _previousEntry = this; | |
| 1045 } | |
| 1046 | |
| 1047 Set<K> _newKeySet() => new _LinkedIdentityHashSet<K>(); | |
| 1048 } | |
| 1049 | |
| 1050 class _LinkedCustomHashMap<K, V> extends _CustomHashMap<K, V> | |
| 1051 with _LinkedHashMapMixin<K, V> { | |
| 1052 _LinkedCustomHashMap(bool equals(K key1, K key2), | |
| 1053 int hashCode(K key), | |
| 1054 bool isValidKey(potentialKey)) | |
| 1055 : super(equals, hashCode, isValidKey) { | |
| 1056 _nextEntry = _previousEntry = this; | |
| 1057 } | |
| 1058 Set<K> _newKeySet() => | |
| 1059 new _LinkedCustomHashSet<K>(_equals, _hashCode, _validKey); | |
| 1060 } | |
| 1061 | |
| 1062 | |
| 1063 patch class LinkedHashSet<E> { | 953 patch class LinkedHashSet<E> { |
| 1064 /* patch */ factory LinkedHashSet({ bool equals(E e1, E e2), | 954 /* patch */ factory LinkedHashSet({ bool equals(E e1, E e2), |
| 1065 int hashCode(E e), | 955 int hashCode(E e), |
| 1066 bool isValidKey(potentialKey) }) { | 956 bool isValidKey(potentialKey) }) { |
| 1067 if (isValidKey == null) { | 957 if (isValidKey == null) { |
| 1068 if (hashCode == null) { | 958 if (hashCode == null) { |
| 1069 if (equals == null) { | 959 if (equals == null) { |
| 1070 if (LinkedHashMap._useCompactCached) { | 960 return new _CompactLinkedHashSet<E>(); |
| 1071 return new _CompactLinkedHashSet<E>(); | |
| 1072 } else { | |
| 1073 return new _LinkedHashSet<E>(); | |
| 1074 } | |
| 1075 } | 961 } |
| 1076 hashCode = _defaultHashCode; | 962 hashCode = _defaultHashCode; |
| 1077 } else { | 963 } else { |
| 1078 if (identical(identityHashCode, hashCode) && | 964 if (identical(identityHashCode, hashCode) && |
| 1079 identical(identical, equals)) { | 965 identical(identical, equals)) { |
| 1080 return new _LinkedIdentityHashSet<E>(); | 966 return new _CompactLinkedIdentityHashSet<E>(); |
| 1081 } | 967 } |
| 1082 if (equals == null) { | 968 if (equals == null) { |
| 1083 equals = _defaultEquals; | 969 equals = _defaultEquals; |
| 1084 } | 970 } |
| 1085 } | 971 } |
| 1086 } else { | 972 } else { |
| 1087 if (hashCode == null) { | 973 if (hashCode == null) { |
| 1088 hashCode = _defaultHashCode; | 974 hashCode = _defaultHashCode; |
| 1089 } | 975 } |
| 1090 if (equals == null) { | 976 if (equals == null) { |
| 1091 equals = _defaultEquals; | 977 equals = _defaultEquals; |
| 1092 } | 978 } |
| 1093 } | 979 } |
| 1094 return new _LinkedCustomHashSet<E>(equals, hashCode, isValidKey); | 980 return new _CompactLinkedCustomHashSet<E>(equals, hashCode, isValidKey); |
| 1095 } | 981 } |
| 1096 | 982 |
| 1097 /* patch */ factory LinkedHashSet.identity() = _LinkedIdentityHashSet<E>; | 983 /* patch */ factory LinkedHashSet.identity() = |
| 984 _CompactLinkedIdentityHashSet<E>; |
| 1098 } | 985 } |
| 1099 | |
| 1100 class _LinkedHashSetEntry extends _HashSetEntry { | |
| 1101 /// Links this element into a double-linked list of elements of a hash set. | |
| 1102 /// The hash set object itself is used as the head entry of the list, so | |
| 1103 /// the field is typed as "var". | |
| 1104 /// Both links are initialized to `this` when the object is created. | |
| 1105 var _nextEntry; | |
| 1106 var _previousEntry; | |
| 1107 _LinkedHashSetEntry(var key, int hashCode, _LinkedHashSetEntry next, | |
| 1108 this._previousEntry, this._nextEntry) | |
| 1109 : super(key, hashCode, next) { | |
| 1110 _previousEntry._nextEntry = _nextEntry._previousEntry = this; | |
| 1111 } | |
| 1112 | |
| 1113 _LinkedHashSetEntry remove() { | |
| 1114 _previousEntry._nextEntry = _nextEntry; | |
| 1115 _nextEntry._previousEntry = _previousEntry; | |
| 1116 _nextEntry = _previousEntry = this; | |
| 1117 return super.remove(); | |
| 1118 } | |
| 1119 } | |
| 1120 | |
| 1121 class _LinkedHashSet<E> extends _HashSet<E> | |
| 1122 implements LinkedHashSet<E> { | |
| 1123 /// Holds a double linked list of the element entries of the set in | |
| 1124 /// insertion order. | |
| 1125 /// The fields have the same names as the ones in [_LinkedHashSetEntry], | |
| 1126 /// allowing this object to be used as the head entry of the list. | |
| 1127 /// The fields are initialized to `this` when created, representing the | |
| 1128 /// empty list that only contains the head entry. | |
| 1129 var _nextEntry; | |
| 1130 var _previousEntry; | |
| 1131 | |
| 1132 _LinkedHashSet() { | |
| 1133 _nextEntry = _previousEntry = this; | |
| 1134 } | |
| 1135 | |
| 1136 // Iterable. | |
| 1137 | |
| 1138 Iterator<E> get iterator => new _LinkedHashSetIterator<E>(this); | |
| 1139 | |
| 1140 void forEach(void action(E element)) { | |
| 1141 var cursor = _nextEntry; | |
| 1142 int modificationCount = _modificationCount; | |
| 1143 while (!identical(cursor, this)) { | |
| 1144 _LinkedHashSetEntry entry = cursor; | |
| 1145 action(entry.key); | |
| 1146 if (_modificationCount != modificationCount) { | |
| 1147 throw new ConcurrentModificationError(this); | |
| 1148 } | |
| 1149 cursor = entry._nextEntry; | |
| 1150 } | |
| 1151 } | |
| 1152 | |
| 1153 E get first { | |
| 1154 if (identical(_nextEntry, this)) { | |
| 1155 throw new StateError("No elements"); | |
| 1156 } | |
| 1157 _LinkedHashSetEntry entry = _nextEntry; | |
| 1158 return entry.key; | |
| 1159 } | |
| 1160 | |
| 1161 E get last { | |
| 1162 if (identical(_previousEntry, this)) { | |
| 1163 throw new StateError("No elements"); | |
| 1164 } | |
| 1165 _LinkedHashSetEntry entry = _previousEntry; | |
| 1166 return entry.key; | |
| 1167 } | |
| 1168 | |
| 1169 // Set. | |
| 1170 | |
| 1171 void _filterWhere(bool test(E element), bool removeMatching) { | |
| 1172 var cursor = _nextEntry; | |
| 1173 while (!identical(cursor, this)) { | |
| 1174 _LinkedHashSetEntry entry = cursor; | |
| 1175 int modificationCount = _modificationCount; | |
| 1176 bool testResult = test(entry.key); | |
| 1177 if (modificationCount != _modificationCount) { | |
| 1178 throw new ConcurrentModificationError(this); | |
| 1179 } | |
| 1180 cursor = entry._nextEntry; | |
| 1181 if (testResult == removeMatching) { | |
| 1182 _remove(entry.key, entry.hashCode); | |
| 1183 } | |
| 1184 } | |
| 1185 } | |
| 1186 | |
| 1187 void _addEntry(E key, int hashCode, int index) { | |
| 1188 _buckets[index] = | |
| 1189 new _LinkedHashSetEntry(key, hashCode, _buckets[index], | |
| 1190 _previousEntry, this); | |
| 1191 int newElements = _elementCount + 1; | |
| 1192 _elementCount = newElements; | |
| 1193 int length = _buckets.length; | |
| 1194 // If we end up with more than 75% non-empty entries, we | |
| 1195 // resize the backing store. | |
| 1196 if ((newElements << 2) > ((length << 1) + length)) _resize(); | |
| 1197 _modificationCount = (_modificationCount + 1) & _MODIFICATION_COUNT_MASK; | |
| 1198 } | |
| 1199 | |
| 1200 void clear() { | |
| 1201 _nextEntry = _previousEntry = this; | |
| 1202 super.clear(); | |
| 1203 } | |
| 1204 | |
| 1205 HashSet<E> _newSet() => new _LinkedHashSet<E>(); | |
| 1206 } | |
| 1207 | |
| 1208 class _LinkedIdentityHashSet<E> extends _LinkedHashSet<E> { | |
| 1209 int _hashCode(e) => identityHashCode(e); | |
| 1210 bool _equals(e1, e2) => identical(e1, e2); | |
| 1211 HashSet<E> _newSet() => new _LinkedIdentityHashSet<E>(); | |
| 1212 } | |
| 1213 | |
| 1214 class _LinkedCustomHashSet<E> extends _LinkedHashSet<E> { | |
| 1215 final _Equality<E> _equality; | |
| 1216 final _Hasher<E> _hasher; | |
| 1217 final _Predicate _validKey; | |
| 1218 | |
| 1219 _LinkedCustomHashSet(this._equality, this._hasher, bool validKey(Object o)) | |
| 1220 : _validKey = (validKey != null) ? validKey : new _TypeTest<E>().test; | |
| 1221 | |
| 1222 bool _equals(e1, e2) => _equality(e1, e2); | |
| 1223 | |
| 1224 int _hashCode(e) => _hasher(e); | |
| 1225 | |
| 1226 bool contains(Object o) { | |
| 1227 if (!_validKey(o)) return false; | |
| 1228 return super.contains(o); | |
| 1229 } | |
| 1230 | |
| 1231 E lookup(Object o) { | |
| 1232 if (!_validKey(o)) return null; | |
| 1233 return super.lookup(o); | |
| 1234 } | |
| 1235 | |
| 1236 bool remove(Object o) { | |
| 1237 if (!_validKey(o)) return false; | |
| 1238 return super.remove(o); | |
| 1239 } | |
| 1240 | |
| 1241 bool containsAll(Iterable<Object> elements) { | |
| 1242 for (Object element in elements) { | |
| 1243 if (!_validKey(element) || !this.contains(element)) return false; | |
| 1244 } | |
| 1245 return true; | |
| 1246 } | |
| 1247 | |
| 1248 void removeAll(Iterable<Object> elements) { | |
| 1249 for (Object element in elements) { | |
| 1250 if (_validKey(element)) { | |
| 1251 super._remove(element, _hasher(element)); | |
| 1252 } | |
| 1253 } | |
| 1254 } | |
| 1255 | |
| 1256 HashSet<E> _newSet() => | |
| 1257 new _LinkedCustomHashSet<E>(_equality, _hasher, _validKey); | |
| 1258 } | |
| 1259 | |
| 1260 class _LinkedHashSetIterator<E> implements Iterator<E> { | |
| 1261 final _LinkedHashSet _set; | |
| 1262 final int _modificationCount; | |
| 1263 var _next; | |
| 1264 E _current; | |
| 1265 | |
| 1266 _LinkedHashSetIterator(_LinkedHashSet hashSet) | |
| 1267 : _set = hashSet, | |
| 1268 _modificationCount = hashSet._modificationCount, | |
| 1269 _next = hashSet._nextEntry; | |
| 1270 | |
| 1271 bool moveNext() { | |
| 1272 if (_modificationCount != _set._modificationCount) { | |
| 1273 throw new ConcurrentModificationError(_set); | |
| 1274 } | |
| 1275 if (identical(_set, _next)) { | |
| 1276 _current = null; | |
| 1277 return false; | |
| 1278 } | |
| 1279 _LinkedHashSetEntry entry = _next; | |
| 1280 _current = entry.key; | |
| 1281 _next = entry._nextEntry; | |
| 1282 return true; | |
| 1283 } | |
| 1284 | |
| 1285 E get current => _current; | |
| 1286 } | |
| OLD | NEW |