| OLD | NEW |
| 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, 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 // Hash map implementation with open addressing and quadratic probing. | 5 // Hash map implementation with open addressing and quadratic probing. |
| 6 class HashMapImplementation<K extends Hashable, V> implements HashMap<K, V> { | 6 class HashMapImplementation<K extends Hashable, V> implements HashMap<K, V> { |
| 7 | 7 |
| 8 // The [_keys] list contains the keys inserted in the map. | 8 // The [_keys] list contains the keys inserted in the map. |
| 9 // The [_keys] list must be a raw list because it | 9 // The [_keys] list must be a raw list because it |
| 10 // will contain both elements of type K, and the [_DELETED_KEY] of type | 10 // will contain both elements of type K, and the [_DELETED_KEY] of type |
| (...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 62 | 62 |
| 63 static int _firstProbe(int hashCode, int length) { | 63 static int _firstProbe(int hashCode, int length) { |
| 64 return hashCode & (length - 1); | 64 return hashCode & (length - 1); |
| 65 } | 65 } |
| 66 | 66 |
| 67 static int _nextProbe(int currentProbe, int numberOfProbes, int length) { | 67 static int _nextProbe(int currentProbe, int numberOfProbes, int length) { |
| 68 return (currentProbe + numberOfProbes) & (length - 1); | 68 return (currentProbe + numberOfProbes) & (length - 1); |
| 69 } | 69 } |
| 70 | 70 |
| 71 int _probeForAdding(K key) { | 71 int _probeForAdding(K key) { |
| 72 if (key == null) throw const NullPointerException(); |
| 72 int hash = _firstProbe(key.hashCode(), _keys.length); | 73 int hash = _firstProbe(key.hashCode(), _keys.length); |
| 73 int numberOfProbes = 1; | 74 int numberOfProbes = 1; |
| 74 int initialHash = hash; | 75 int initialHash = hash; |
| 75 // insertionIndex points to a slot where a key was deleted. | 76 // insertionIndex points to a slot where a key was deleted. |
| 76 int insertionIndex = -1; | 77 int insertionIndex = -1; |
| 77 while (true) { | 78 while (true) { |
| 78 // [existingKey] can be either of type [K] or [_DeletedKeySentinel]. | 79 // [existingKey] can be either of type [K] or [_DeletedKeySentinel]. |
| 79 Object existingKey = _keys[hash]; | 80 Object existingKey = _keys[hash]; |
| 80 if (existingKey === null) { | 81 if (existingKey === null) { |
| 81 // We are sure the key is not already in the set. | 82 // We are sure the key is not already in the set. |
| (...skipping 13 matching lines...) Expand all Loading... |
| 95 } | 96 } |
| 96 | 97 |
| 97 // We did not find an insertion slot. Look at the next one. | 98 // We did not find an insertion slot. Look at the next one. |
| 98 hash = _nextProbe(hash, numberOfProbes++, _keys.length); | 99 hash = _nextProbe(hash, numberOfProbes++, _keys.length); |
| 99 // _ensureCapacity has guaranteed the following cannot happen. | 100 // _ensureCapacity has guaranteed the following cannot happen. |
| 100 // assert(hash != initialHash); | 101 // assert(hash != initialHash); |
| 101 } | 102 } |
| 102 } | 103 } |
| 103 | 104 |
| 104 int _probeForLookup(K key) { | 105 int _probeForLookup(K key) { |
| 106 if (key == null) throw const NullPointerException(); |
| 105 int hash = _firstProbe(key.hashCode(), _keys.length); | 107 int hash = _firstProbe(key.hashCode(), _keys.length); |
| 106 int numberOfProbes = 1; | 108 int numberOfProbes = 1; |
| 107 int initialHash = hash; | 109 int initialHash = hash; |
| 108 while (true) { | 110 while (true) { |
| 109 // [existingKey] can be either of type [K] or [_DeletedKeySentinel]. | 111 // [existingKey] can be either of type [K] or [_DeletedKeySentinel]. |
| 110 Object existingKey = _keys[hash]; | 112 Object existingKey = _keys[hash]; |
| 111 // If the slot does not contain anything (in particular, it does not | 113 // If the slot does not contain anything (in particular, it does not |
| 112 // contain a deleted key), we know the key is not in the map. | 114 // contain a deleted key), we know the key is not in the map. |
| 113 if (existingKey === null) return -1; | 115 if (existingKey === null) return -1; |
| 114 // The key is in the map, return its index. | 116 // The key is in the map, return its index. |
| (...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 189 } | 191 } |
| 190 | 192 |
| 191 V operator [](K key) { | 193 V operator [](K key) { |
| 192 int index = _probeForLookup(key); | 194 int index = _probeForLookup(key); |
| 193 if (index < 0) return null; | 195 if (index < 0) return null; |
| 194 return _values[index]; | 196 return _values[index]; |
| 195 } | 197 } |
| 196 | 198 |
| 197 V putIfAbsent(K key, V ifAbsent()) { | 199 V putIfAbsent(K key, V ifAbsent()) { |
| 198 int index = _probeForLookup(key); | 200 int index = _probeForLookup(key); |
| 199 if (index >=0) return _values[index]; | 201 if (index >= 0) return _values[index]; |
| 200 | 202 |
| 201 V value = ifAbsent(); | 203 V value = ifAbsent(); |
| 202 this[key] = value; | 204 this[key] = value; |
| 203 return value; | 205 return value; |
| 204 } | 206 } |
| 205 | 207 |
| 206 V remove(K key) { | 208 V remove(K key) { |
| 207 int index = _probeForLookup(key); | 209 int index = _probeForLookup(key); |
| 208 if (index >= 0) { | 210 if (index >= 0) { |
| 209 _numberOfEntries--; | 211 _numberOfEntries--; |
| (...skipping 235 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 445 | 447 |
| 446 /** | 448 /** |
| 447 * A singleton sentinel used to represent when a key is deleted from the map. | 449 * A singleton sentinel used to represent when a key is deleted from the map. |
| 448 * We can't use [: const Object() :] as a sentinel because it would end up | 450 * We can't use [: const Object() :] as a sentinel because it would end up |
| 449 * canonicalized and then we cannot distinguish the deleted key from the | 451 * canonicalized and then we cannot distinguish the deleted key from the |
| 450 * canonicalized [: Object() :]. | 452 * canonicalized [: Object() :]. |
| 451 */ | 453 */ |
| 452 class _DeletedKeySentinel { | 454 class _DeletedKeySentinel { |
| 453 const _DeletedKeySentinel(); | 455 const _DeletedKeySentinel(); |
| 454 } | 456 } |
| OLD | NEW |