Chromium Code Reviews| 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), | |
| 7 int hashCode(K key) }) { | |
| 8 if (hashCode == null) { | |
| 9 if (equals == null) { | |
| 10 return new _HashMapImpl<K, V>(); | |
| 11 } | |
| 12 if (identical(identical, equals)) { | |
| 13 return new _IdentityHashMap<K, V>(); | |
| 14 } | |
| 15 hashCode = _defaultHashCode; | |
| 16 } else if (equals == null) { | |
| 17 equals = _defaultEquals; | |
| 18 } | |
| 19 return new _CustomHashMap<K, V>(equals, hashCode); | |
| 20 } | |
| 21 } | |
| 22 | |
| 23 const int _MODIFICATION_COUNT_MASK = 0x3fffffff; | |
| 24 | |
| 25 class _HashMapImpl<K, V> implements HashMap<K, V> { | |
| 6 static const int _INITIAL_CAPACITY = 8; | 26 static const int _INITIAL_CAPACITY = 8; |
| 7 static const int _MODIFICATION_COUNT_MASK = 0x3fffffff; | |
| 8 | 27 |
| 9 int _elementCount = 0; | 28 int _elementCount = 0; |
| 10 List<_HashMapEntry> _buckets = new List(_INITIAL_CAPACITY); | 29 List<_HashMapEntry> _buckets = new List(_INITIAL_CAPACITY); |
| 11 int _modificationCount = 0; | 30 int _modificationCount = 0; |
| 12 | 31 |
| 13 /* patch */ HashMap._internal(); | 32 int get length => _elementCount; |
| 33 bool get isEmpty => _elementCount == 0; | |
| 34 bool get isNotEmpty => _elementCount != 0; | |
| 14 | 35 |
| 15 /* patch */ int get length => _elementCount; | 36 Iterable<K> get keys => new _HashMapKeyIterable<K>(this); |
| 16 /* patch */ bool get isEmpty => _elementCount == 0; | 37 Iterable<V> get values => new _HashMapValueIterable<V>(this); |
| 17 /* patch */ bool get isNotEmpty => _elementCount != 0; | |
| 18 | 38 |
| 19 /* patch */ Iterable<K> get keys => new _HashMapKeyIterable<K>(this); | 39 bool containsKey(Object key) { |
| 20 /* patch */ Iterable<V> get values => new _HashMapValueIterable<V>(this); | |
| 21 | |
| 22 /* patch */ bool containsKey(Object key) { | |
| 23 int hashCode = key.hashCode; | 40 int hashCode = key.hashCode; |
| 24 List buckets = _buckets; | 41 List buckets = _buckets; |
| 25 int index = hashCode & (buckets.length - 1); | 42 int index = hashCode & (buckets.length - 1); |
| 26 _HashMapEntry entry = buckets[index]; | 43 _HashMapEntry entry = buckets[index]; |
| 27 while (entry != null) { | 44 while (entry != null) { |
| 28 if (hashCode == entry.hashCode && entry.key == key) return true; | 45 if (hashCode == entry.hashCode && entry.key == key) return true; |
| 29 entry = entry.next; | 46 entry = entry.next; |
| 30 } | 47 } |
| 31 return false; | 48 return false; |
| 32 } | 49 } |
| 33 | 50 |
| 34 /* patch */ bool containsValue(Object value) { | 51 bool containsValue(Object value) { |
| 35 List buckets = _buckets; | 52 List buckets = _buckets; |
| 36 int length = buckets.length; | 53 int length = buckets.length; |
| 37 for (int i = 0; i < length; i++) { | 54 for (int i = 0; i < length; i++) { |
| 38 _HashMapEntry entry = buckets[i]; | 55 _HashMapEntry entry = buckets[i]; |
| 39 while (entry != null) { | 56 while (entry != null) { |
| 40 if (entry.value == value) return true; | 57 if (entry.value == value) return true; |
| 41 entry = entry.next; | 58 entry = entry.next; |
| 42 } | 59 } |
| 43 } | 60 } |
| 44 return false; | 61 return false; |
| 45 } | 62 } |
| 46 | 63 |
| 47 /* patch */ V operator[](Object key) { | 64 V operator[](Object key) { |
| 48 int hashCode = key.hashCode; | 65 int hashCode = key.hashCode; |
| 49 List buckets = _buckets; | 66 List buckets = _buckets; |
| 50 int index = hashCode & (buckets.length - 1); | 67 int index = hashCode & (buckets.length - 1); |
| 51 _HashMapEntry entry = buckets[index]; | 68 _HashMapEntry entry = buckets[index]; |
| 52 while (entry != null) { | 69 while (entry != null) { |
| 53 if (hashCode == entry.hashCode && entry.key == key) { | 70 if (hashCode == entry.hashCode && entry.key == key) { |
| 54 return entry.value; | 71 return entry.value; |
| 55 } | 72 } |
| 56 entry = entry.next; | 73 entry = entry.next; |
| 57 } | 74 } |
| 58 return null; | 75 return null; |
| 59 } | 76 } |
| 60 | 77 |
| 61 /* patch */ void operator []=(K key, V value) { | 78 void operator []=(K key, V value) { |
| 62 int hashCode = key.hashCode; | 79 int hashCode = key.hashCode; |
| 63 List buckets = _buckets; | 80 List buckets = _buckets; |
| 64 int length = buckets.length; | 81 int length = buckets.length; |
| 65 int index = hashCode & (length - 1); | 82 int index = hashCode & (length - 1); |
| 66 _HashMapEntry entry = buckets[index]; | 83 _HashMapEntry entry = buckets[index]; |
| 67 while (entry != null) { | 84 while (entry != null) { |
| 68 if (hashCode == entry.hashCode && entry.key == key) { | 85 if (hashCode == entry.hashCode && entry.key == key) { |
| 69 entry.value = value; | 86 entry.value = value; |
| 70 return; | 87 return; |
| 71 } | 88 } |
| 72 entry = entry.next; | 89 entry = entry.next; |
| 73 } | 90 } |
| 74 _addEntry(buckets, index, length, key, value, hashCode); | 91 _addEntry(buckets, index, length, key, value, hashCode); |
| 75 } | 92 } |
| 76 | 93 |
| 77 /* patch */ V putIfAbsent(K key, V ifAbsent()) { | 94 V putIfAbsent(K key, V ifAbsent()) { |
| 78 int hashCode = key.hashCode; | 95 int hashCode = key.hashCode; |
| 79 List buckets = _buckets; | 96 List buckets = _buckets; |
| 80 int length = buckets.length; | 97 int length = buckets.length; |
| 81 int index = hashCode & (length - 1); | 98 int index = hashCode & (length - 1); |
| 82 _HashMapEntry entry = buckets[index]; | 99 _HashMapEntry entry = buckets[index]; |
| 83 while (entry != null) { | 100 while (entry != null) { |
| 84 if (hashCode == entry.hashCode && entry.key == key) { | 101 if (hashCode == entry.hashCode && entry.key == key) { |
| 85 return entry.value; | 102 return entry.value; |
| 86 } | 103 } |
| 87 entry = entry.next; | 104 entry = entry.next; |
| 88 } | 105 } |
| 89 int stamp = _modificationCount; | 106 int stamp = _modificationCount; |
| 90 V value = ifAbsent(); | 107 V value = ifAbsent(); |
| 91 if (stamp == _modificationCount) { | 108 if (stamp == _modificationCount) { |
| 92 _addEntry(buckets, index, length, key, value, hashCode); | 109 _addEntry(buckets, index, length, key, value, hashCode); |
| 93 } else { | 110 } else { |
| 94 this[key] = value; | 111 this[key] = value; |
| 95 } | 112 } |
| 96 return value; | 113 return value; |
| 97 } | 114 } |
| 98 | 115 |
| 99 /* patch */ void addAll(Map<K, V> other) { | 116 void addAll(Map<K, V> other) { |
| 100 other.forEach((K key, V value) { | 117 other.forEach((K key, V value) { |
| 101 this[key] = value; | 118 this[key] = value; |
| 102 }); | 119 }); |
| 103 } | 120 } |
| 104 | 121 |
| 105 /* patch */ void forEach(void action(K key, V value)) { | 122 void forEach(void action(K key, V value)) { |
| 106 int stamp = _modificationCount; | 123 int stamp = _modificationCount; |
| 107 List buckets = _buckets; | 124 List buckets = _buckets; |
| 108 int length = buckets.length; | 125 int length = buckets.length; |
| 109 for (int i = 0; i < length; i++) { | 126 for (int i = 0; i < length; i++) { |
| 110 _HashMapEntry entry = buckets[i]; | 127 _HashMapEntry entry = buckets[i]; |
| 111 while (entry != null) { | 128 while (entry != null) { |
| 112 action(entry.key, entry.value); | 129 action(entry.key, entry.value); |
| 113 if (stamp != _modificationCount) { | 130 if (stamp != _modificationCount) { |
| 114 throw new ConcurrentModificationError(this); | 131 throw new ConcurrentModificationError(this); |
| 115 } | 132 } |
| 116 entry = entry.next; | 133 entry = entry.next; |
| 117 } | 134 } |
| 118 } | 135 } |
| 119 } | 136 } |
| 120 | 137 |
| 121 /* patch */ V remove(Object key) { | 138 V remove(Object key) { |
| 122 int hashCode = key.hashCode; | 139 int hashCode = key.hashCode; |
| 123 List buckets = _buckets; | 140 List buckets = _buckets; |
| 124 int index = hashCode & (buckets.length - 1); | 141 int index = hashCode & (buckets.length - 1); |
| 125 _HashMapEntry entry = buckets[index]; | 142 _HashMapEntry entry = buckets[index]; |
| 126 _HashMapEntry previous = null; | 143 _HashMapEntry previous = null; |
| 127 while (entry != null) { | 144 while (entry != null) { |
| 128 _HashMapEntry next = entry.next; | 145 _HashMapEntry next = entry.next; |
| 129 if (hashCode == entry.hashCode && entry.key == key) { | 146 if (hashCode == entry.hashCode && entry.key == key) { |
| 130 if (previous == null) { | 147 if (previous == null) { |
| 131 buckets[index] = next; | 148 buckets[index] = next; |
| 132 } else { | 149 } else { |
| 133 previous.next = next; | 150 previous.next = next; |
| 134 } | 151 } |
| 135 _elementCount--; | 152 _elementCount--; |
| 136 _modificationCount = | 153 _modificationCount = |
| 137 (_modificationCount + 1) & _MODIFICATION_COUNT_MASK; | 154 (_modificationCount + 1) & _MODIFICATION_COUNT_MASK; |
| 138 return entry.value; | 155 return entry.value; |
| 139 } | 156 } |
| 140 previous = entry; | 157 previous = entry; |
| 141 entry = next; | 158 entry = next; |
| 142 } | 159 } |
| 143 return null; | 160 return null; |
| 144 } | 161 } |
| 145 | 162 |
| 146 /* patch */ void clear() { | 163 void clear() { |
| 147 _elementCount = 0; | 164 _elementCount = 0; |
| 148 _buckets = new List(_INITIAL_CAPACITY); | 165 _buckets = new List(_INITIAL_CAPACITY); |
| 149 _modificationCount = (_modificationCount + 1) & _MODIFICATION_COUNT_MASK; | 166 _modificationCount = (_modificationCount + 1) & _MODIFICATION_COUNT_MASK; |
| 150 } | 167 } |
| 151 | 168 |
| 152 void _addEntry(List buckets, int index, int length, | 169 void _addEntry(List buckets, int index, int length, |
| 153 K key, V value, int hashCode) { | 170 K key, V value, int hashCode) { |
| 154 _HashMapEntry entry = | 171 _HashMapEntry entry = |
| 155 new _HashMapEntry(key, value, hashCode, buckets[index]); | 172 new _HashMapEntry(key, value, hashCode, buckets[index]); |
| 156 buckets[index] = entry; | 173 buckets[index] = entry; |
| (...skipping 18 matching lines...) Expand all Loading... | |
| 175 int index = hashCode & (newLength - 1); | 192 int index = hashCode & (newLength - 1); |
| 176 entry.next = newBuckets[index]; | 193 entry.next = newBuckets[index]; |
| 177 newBuckets[index] = entry; | 194 newBuckets[index] = entry; |
| 178 entry = next; | 195 entry = next; |
| 179 } | 196 } |
| 180 } | 197 } |
| 181 _buckets = newBuckets; | 198 _buckets = newBuckets; |
| 182 } | 199 } |
| 183 } | 200 } |
| 184 | 201 |
| 202 class _CustomHashMap<K, V> extends _HashMapImpl<K, V> { | |
|
floitsch
2013/09/03 13:59:08
File a bug against the VM asking for customization
Lasse Reichstein Nielsen
2013/09/04 05:59:21
I can avoid the code duplication myself by abstrac
| |
| 203 final Function _equals; | |
| 204 final Function _hashCode; | |
| 205 _CustomHashMap(this._equals, this._hashCode); | |
| 206 | |
| 207 bool containsKey(Object key) { | |
| 208 int hashCode = _hashCode(key); | |
| 209 List buckets = _buckets; | |
| 210 int index = hashCode & (buckets.length - 1); | |
| 211 _HashMapEntry entry = buckets[index]; | |
| 212 while (entry != null) { | |
| 213 if (hashCode == entry.hashCode && _equals(entry.key, key)) return true; | |
| 214 entry = entry.next; | |
| 215 } | |
| 216 return false; | |
| 217 } | |
| 218 | |
| 219 V operator[](Object key) { | |
| 220 int hashCode = _hashCode(key); | |
| 221 List buckets = _buckets; | |
| 222 int index = hashCode & (buckets.length - 1); | |
| 223 _HashMapEntry entry = buckets[index]; | |
| 224 while (entry != null) { | |
| 225 if (hashCode == entry.hashCode && _equals(entry.key, key)) { | |
| 226 return entry.value; | |
| 227 } | |
| 228 entry = entry.next; | |
| 229 } | |
| 230 return null; | |
| 231 } | |
| 232 | |
| 233 void operator []=(K key, V value) { | |
| 234 int hashCode = _hashCode(key); | |
| 235 List buckets = _buckets; | |
| 236 int length = buckets.length; | |
| 237 int index = hashCode & (length - 1); | |
| 238 _HashMapEntry entry = buckets[index]; | |
| 239 while (entry != null) { | |
| 240 if (hashCode == entry.hashCode && _equals(entry.key, key)) { | |
| 241 entry.value = value; | |
| 242 return; | |
| 243 } | |
| 244 entry = entry.next; | |
| 245 } | |
| 246 _addEntry(buckets, index, length, key, value, hashCode); | |
| 247 } | |
| 248 | |
| 249 V putIfAbsent(K key, V ifAbsent()) { | |
| 250 int hashCode = _hashCode(key); | |
| 251 List buckets = _buckets; | |
| 252 int length = buckets.length; | |
| 253 int index = hashCode & (length - 1); | |
| 254 _HashMapEntry entry = buckets[index]; | |
| 255 while (entry != null) { | |
| 256 if (hashCode == entry.hashCode && _equals(entry.key, key)) { | |
| 257 return entry.value; | |
| 258 } | |
| 259 entry = entry.next; | |
| 260 } | |
| 261 int stamp = _modificationCount; | |
| 262 V value = ifAbsent(); | |
| 263 if (stamp == _modificationCount) { | |
| 264 _addEntry(buckets, index, length, key, value, hashCode); | |
| 265 } else { | |
| 266 this[key] = value; | |
| 267 } | |
| 268 return value; | |
| 269 } | |
| 270 | |
| 271 V remove(Object key) { | |
| 272 int hashCode = _hashCode(key); | |
| 273 List buckets = _buckets; | |
| 274 int index = hashCode & (buckets.length - 1); | |
| 275 _HashMapEntry entry = buckets[index]; | |
| 276 _HashMapEntry previous = null; | |
| 277 while (entry != null) { | |
| 278 _HashMapEntry next = entry.next; | |
| 279 if (hashCode == entry.hashCode && _equals(entry.key, key)) { | |
| 280 if (previous == null) { | |
| 281 buckets[index] = next; | |
| 282 } else { | |
| 283 previous.next = next; | |
| 284 } | |
| 285 _elementCount--; | |
| 286 _modificationCount = | |
| 287 (_modificationCount + 1) & _MODIFICATION_COUNT_MASK; | |
| 288 return entry.value; | |
| 289 } | |
| 290 previous = entry; | |
| 291 entry = next; | |
| 292 } | |
| 293 return null; | |
| 294 } | |
| 295 } | |
| 296 | |
| 297 class _IdentityHashMap<K, V> extends _HashMapImpl<K, V> { | |
|
floitsch
2013/09/03 13:59:08
I'm not sure we need to have Identity maps to be c
Lasse Reichstein Nielsen
2013/09/04 05:59:21
I expect IdentityMap to be the main usage of custo
| |
| 298 bool containsKey(Object key) { | |
| 299 int hashCode = key.hashCode; | |
| 300 List buckets = _buckets; | |
| 301 int index = hashCode & (buckets.length - 1); | |
| 302 _HashMapEntry entry = buckets[index]; | |
| 303 while (entry != null) { | |
| 304 if (hashCode == entry.hashCode && identical(entry.key, key)) return true; | |
| 305 entry = entry.next; | |
| 306 } | |
| 307 return false; | |
| 308 } | |
| 309 | |
| 310 V operator[](Object key) { | |
| 311 int hashCode = key.hashCode; | |
| 312 List buckets = _buckets; | |
| 313 int index = hashCode & (buckets.length - 1); | |
| 314 _HashMapEntry entry = buckets[index]; | |
| 315 while (entry != null) { | |
| 316 if (hashCode == entry.hashCode && identical(entry.key, key)) { | |
| 317 return entry.value; | |
| 318 } | |
| 319 entry = entry.next; | |
| 320 } | |
| 321 return null; | |
| 322 } | |
| 323 | |
| 324 void operator []=(K key, V value) { | |
| 325 int hashCode = key.hashCode; | |
| 326 List buckets = _buckets; | |
| 327 int length = buckets.length; | |
| 328 int index = hashCode & (length - 1); | |
| 329 _HashMapEntry entry = buckets[index]; | |
| 330 while (entry != null) { | |
| 331 if (hashCode == entry.hashCode && identical(entry.key, key)) { | |
| 332 entry.value = value; | |
| 333 return; | |
| 334 } | |
| 335 entry = entry.next; | |
| 336 } | |
| 337 _addEntry(buckets, index, length, key, value, hashCode); | |
| 338 } | |
| 339 | |
| 340 V putIfAbsent(K key, V ifAbsent()) { | |
| 341 int hashCode = key.hashCode; | |
| 342 List buckets = _buckets; | |
| 343 int length = buckets.length; | |
| 344 int index = hashCode & (length - 1); | |
| 345 _HashMapEntry entry = buckets[index]; | |
| 346 while (entry != null) { | |
| 347 if (hashCode == entry.hashCode && identical(entry.key, key)) { | |
| 348 return entry.value; | |
| 349 } | |
| 350 entry = entry.next; | |
| 351 } | |
| 352 int stamp = _modificationCount; | |
| 353 V value = ifAbsent(); | |
| 354 if (stamp == _modificationCount) { | |
| 355 _addEntry(buckets, index, length, key, value, hashCode); | |
| 356 } else { | |
| 357 this[key] = value; | |
| 358 } | |
| 359 return value; | |
| 360 } | |
| 361 | |
| 362 V remove(Object key) { | |
| 363 int hashCode = key.hashCode; | |
| 364 List buckets = _buckets; | |
| 365 int index = hashCode & (buckets.length - 1); | |
| 366 _HashMapEntry entry = buckets[index]; | |
| 367 _HashMapEntry previous = null; | |
| 368 while (entry != null) { | |
| 369 _HashMapEntry next = entry.next; | |
| 370 if (hashCode == entry.hashCode && identical(entry.key, key)) { | |
| 371 if (previous == null) { | |
| 372 buckets[index] = next; | |
| 373 } else { | |
| 374 previous.next = next; | |
| 375 } | |
| 376 _elementCount--; | |
| 377 _modificationCount = | |
| 378 (_modificationCount + 1) & _MODIFICATION_COUNT_MASK; | |
| 379 return entry.value; | |
| 380 } | |
| 381 previous = entry; | |
| 382 entry = next; | |
| 383 } | |
| 384 return null; | |
| 385 } | |
| 386 } | |
| 387 | |
| 388 | |
| 185 class _HashMapEntry { | 389 class _HashMapEntry { |
| 186 final key; | 390 final key; |
| 187 var value; | 391 var value; |
| 188 final int hashCode; | 392 final int hashCode; |
| 189 _HashMapEntry next; | 393 _HashMapEntry next; |
| 190 _HashMapEntry(this.key, this.value, this.hashCode, this.next); | 394 _HashMapEntry(this.key, this.value, this.hashCode, this.next); |
| 191 } | 395 } |
| 192 | 396 |
| 193 abstract class _HashMapIterable<E> extends IterableBase<E> { | 397 abstract class _HashMapIterable<E> extends IterableBase<E> { |
| 194 final HashMap _map; | 398 final HashMap _map; |
| (...skipping 1112 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1307 | 1511 |
| 1308 _LinkedHashMapTable() : super(_INITIAL_CAPACITY); | 1512 _LinkedHashMapTable() : super(_INITIAL_CAPACITY); |
| 1309 | 1513 |
| 1310 V _value(int offset) => _table[offset + _VALUE_INDEX]; | 1514 V _value(int offset) => _table[offset + _VALUE_INDEX]; |
| 1311 void _setValue(int offset, V value) { _table[offset + _VALUE_INDEX] = value; } | 1515 void _setValue(int offset, V value) { _table[offset + _VALUE_INDEX] = value; } |
| 1312 | 1516 |
| 1313 _copyEntry(List oldTable, int fromOffset, int toOffset) { | 1517 _copyEntry(List oldTable, int fromOffset, int toOffset) { |
| 1314 _table[toOffset + _VALUE_INDEX] = oldTable[fromOffset + _VALUE_INDEX]; | 1518 _table[toOffset + _VALUE_INDEX] = oldTable[fromOffset + _VALUE_INDEX]; |
| 1315 } | 1519 } |
| 1316 } | 1520 } |
| OLD | NEW |