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 |