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 |