Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(253)

Side by Side Diff: corelib/src/implementation/hash_map_set.dart

Issue 8591022: Make HashMap's delete key a const expression. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: r Created 9 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2011, 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 [_deletedKey] of type 10 // will contain both elements of type K, and the [_DELETED_KEY] of type
11 // Object. 11 // [_DeleteKeySentinel].
Ivan Posva 2011/11/17 18:57:47 DeletedKeySentinel
Siggi Cherem (dart-lang) 2011/11/17 20:00:21 Done (I expect you meant here to remove the _ from
Ivan Posva 2011/11/17 21:06:51 You really, really want to keep this type private
Siggi Cherem (dart-lang) 2011/11/17 21:13:27 Fixed - I was assuming that because this type is w
12 // The alternative of declaring the [_keys] list as of type Object 12 // The alternative of declaring the [_keys] list as of type Object
13 // does not work, because the HashSetIterator constructor would fail: 13 // does not work, because the HashSetIterator constructor would fail:
14 // HashSetIterator(HashSet<E> set) 14 // HashSetIterator(HashSet<E> set)
15 // : _nextValidIndex = -1, 15 // : _nextValidIndex = -1,
16 // _entries = set_._backingMap._keys { 16 // _entries = set_._backingMap._keys {
17 // _advance(); 17 // _advance();
18 // } 18 // }
19 // With K being type int, for example, it would fail because 19 // With K being type int, for example, it would fail because
20 // List<Object> is not assignable to type List<int> of entries. 20 // List<Object> is not assignable to type List<int> of entries.
21 List _keys; 21 List _keys;
22 22
23 // The values inserted in the map. For a filled entry index in this 23 // The values inserted in the map. For a filled entry index in this
24 // list, there is always the corresponding key in the [keys_] list 24 // list, there is always the corresponding key in the [keys_] list
25 // at the same entry index. 25 // at the same entry index.
26 List<V> _values; 26 List<V> _values;
27 27
28 // The load limit is the number of entries we allow until we double 28 // The load limit is the number of entries we allow until we double
29 // the size of the lists. 29 // the size of the lists.
30 int _loadLimit; 30 int _loadLimit;
31 31
32 // The current number of entries in the map. Will never be greater 32 // The current number of entries in the map. Will never be greater
33 // than [_loadLimit]. 33 // than [_loadLimit].
34 int _numberOfEntries; 34 int _numberOfEntries;
35 35
36 // The current number of deleted entries in the map. 36 // The current number of deleted entries in the map.
37 int _numberOfDeleted; 37 int _numberOfDeleted;
38 38
39 // The sentinel when a key is deleted from the map. We cannot use static 39 // The sentinel when a key is deleted from the map.
40 // const here because we would need to allocate a "const Object()" which 40 static final Object _DELETED_KEY = const _DeleteKeySentinel();
Siggi Cherem (dart-lang) 2011/11/17 18:40:32 Is there an issue in using an instance that is not
Ivan Posva 2011/11/17 18:57:47 Why is there even a type on this value? I don't th
Siggi Cherem (dart-lang) 2011/11/17 20:00:21 Done.
41 // would end up canonicalized and then we cannot distinguish the deleted
42 // key from the canonicalized Object().
43 static Object _deletedKey;
44 41
45 // The initial capacity of a hash map. 42 // The initial capacity of a hash map.
46 static final int _INITIAL_CAPACITY = 8; // must be power of 2 43 static final int _INITIAL_CAPACITY = 8; // must be power of 2
47 44
48 HashMapImplementation() { 45 HashMapImplementation() {
49 if (_deletedKey === null) {
50 _deletedKey = new Object();
51 }
52 _numberOfEntries = 0; 46 _numberOfEntries = 0;
53 _numberOfDeleted = 0; 47 _numberOfDeleted = 0;
54 _loadLimit = _computeLoadLimit(_INITIAL_CAPACITY); 48 _loadLimit = _computeLoadLimit(_INITIAL_CAPACITY);
55 _keys = new List(_INITIAL_CAPACITY); 49 _keys = new List(_INITIAL_CAPACITY);
56 _values = new List<V>(_INITIAL_CAPACITY); 50 _values = new List<V>(_INITIAL_CAPACITY);
57 } 51 }
58 52
59 // See bug 5257789. 53 // See bug 5257789.
Ivan Posva 2011/11/17 18:57:47 This bug is claiming to be fixed?
Siggi Cherem (dart-lang) 2011/11/17 20:00:21 Tried - works in the VM, but I still get some fail
60 factory HashMapImplementation/* <K, V> */.from(Map/* <K, V> */other) { 54 factory HashMapImplementation/* <K, V> */.from(Map/* <K, V> */other) {
61 Map/* <K, V> */ result = new HashMapImplementation/* <K, V> */(); 55 Map/* <K, V> */ result = new HashMapImplementation/* <K, V> */();
62 other.forEach((/* K */ key, /* V */ value) { result[key] = value; }); 56 other.forEach((/* K */ key, /* V */ value) { result[key] = value; });
63 return result; 57 return result;
64 } 58 }
65 59
66 static int _computeLoadLimit(int capacity) { 60 static int _computeLoadLimit(int capacity) {
67 return (capacity * 3) ~/ 4; 61 return (capacity * 3) ~/ 4;
68 } 62 }
69 63
70 static int _firstProbe(int hashCode, int length) { 64 static int _firstProbe(int hashCode, int length) {
71 return hashCode & (length - 1); 65 return hashCode & (length - 1);
72 } 66 }
73 67
74 static int _nextProbe(int currentProbe, int numberOfProbes, int length) { 68 static int _nextProbe(int currentProbe, int numberOfProbes, int length) {
75 return (currentProbe + numberOfProbes) & (length - 1); 69 return (currentProbe + numberOfProbes) & (length - 1);
76 } 70 }
77 71
78 int _probeForAdding(K key) { 72 int _probeForAdding(K key) {
79 int hash = _firstProbe(key.hashCode(), _keys.length); 73 int hash = _firstProbe(key.hashCode(), _keys.length);
80 int numberOfProbes = 1; 74 int numberOfProbes = 1;
81 int initialHash = hash; 75 int initialHash = hash;
82 // insertionIndex points to a slot where a key was deleted. 76 // insertionIndex points to a slot where a key was deleted.
83 int insertionIndex = -1; 77 int insertionIndex = -1;
84 while (true) { 78 while (true) {
85 Object existingKey = _keys[hash]; 79 Object existingKey = _keys[hash];
Ivan Posva 2011/11/17 18:57:47 How about change Object here to var and adding a c
Siggi Cherem (dart-lang) 2011/11/17 20:00:21 I added the comment, but left it as [Object] rathe
86 if (existingKey === null) { 80 if (existingKey === null) {
87 // We are sure the key is not already in the set. 81 // We are sure the key is not already in the set.
88 // If the current slot is empty and we didn't find any 82 // If the current slot is empty and we didn't find any
89 // insertion slot before, return this slot. 83 // insertion slot before, return this slot.
90 if (insertionIndex < 0) return hash; 84 if (insertionIndex < 0) return hash;
91 // If we did find an insertion slot before, return it. 85 // If we did find an insertion slot before, return it.
92 return insertionIndex; 86 return insertionIndex;
93 } else if (existingKey == key) { 87 } else if (existingKey == key) {
94 // The key is already in the map. Return its slot. 88 // The key is already in the map. Return its slot.
95 return hash; 89 return hash;
96 } else if ((insertionIndex < 0) && (_deletedKey === existingKey)) { 90 } else if ((insertionIndex < 0) && (_DELETED_KEY === existingKey)) {
97 // The slot contains a deleted element. Because previous calls to this 91 // The slot contains a deleted element. Because previous calls to this
98 // method may not have had this slot deleted, we must continue iterate 92 // method may not have had this slot deleted, we must continue iterate
99 // to find if there is a slot with the given key. 93 // to find if there is a slot with the given key.
100 insertionIndex = hash; 94 insertionIndex = hash;
101 } 95 }
102 96
103 // We did not find an insertion slot. Look at the next one. 97 // We did not find an insertion slot. Look at the next one.
104 hash = _nextProbe(hash, numberOfProbes++, _keys.length); 98 hash = _nextProbe(hash, numberOfProbes++, _keys.length);
105 // _ensureCapacity has guaranteed the following cannot happen. 99 // _ensureCapacity has guaranteed the following cannot happen.
106 // assert(hash != initialHash); 100 // assert(hash != initialHash);
107 } 101 }
108 } 102 }
109 103
110 int _probeForLookup(K key) { 104 int _probeForLookup(K key) {
111 int hash = _firstProbe(key.hashCode(), _keys.length); 105 int hash = _firstProbe(key.hashCode(), _keys.length);
112 int numberOfProbes = 1; 106 int numberOfProbes = 1;
113 int initialHash = hash; 107 int initialHash = hash;
114 while (true) { 108 while (true) {
115 Object existingKey = _keys[hash]; 109 Object existingKey = _keys[hash];
Ivan Posva 2011/11/17 18:57:47 ditto.
Siggi Cherem (dart-lang) 2011/11/17 20:00:21 Done.
116 // If the slot does not contain anything (in particular, it does not 110 // If the slot does not contain anything (in particular, it does not
117 // contain a deleted key), we know the key is not in the map. 111 // contain a deleted key), we know the key is not in the map.
118 if (existingKey === null) return -1; 112 if (existingKey === null) return -1;
119 // The key is in the map, return its index. 113 // The key is in the map, return its index.
120 if (existingKey == key) return hash; 114 if (existingKey == key) return hash;
121 // Go to the next probe. 115 // Go to the next probe.
122 hash = _nextProbe(hash, numberOfProbes++, _keys.length); 116 hash = _nextProbe(hash, numberOfProbes++, _keys.length);
123 // _ensureCapacity has guaranteed the following cannot happen. 117 // _ensureCapacity has guaranteed the following cannot happen.
124 // assert(hash != initialHash); 118 // assert(hash != initialHash);
125 } 119 }
(...skipping 25 matching lines...) Expand all
151 145
152 void _grow(int newCapacity) { 146 void _grow(int newCapacity) {
153 assert(_isPowerOfTwo(newCapacity)); 147 assert(_isPowerOfTwo(newCapacity));
154 int capacity = _keys.length; 148 int capacity = _keys.length;
155 _loadLimit = _computeLoadLimit(newCapacity); 149 _loadLimit = _computeLoadLimit(newCapacity);
156 List oldKeys = _keys; 150 List oldKeys = _keys;
157 List<V> oldValues = _values; 151 List<V> oldValues = _values;
158 _keys = new List(newCapacity); 152 _keys = new List(newCapacity);
159 _values = new List<V>(newCapacity); 153 _values = new List<V>(newCapacity);
160 for (int i = 0; i < capacity; i++) { 154 for (int i = 0; i < capacity; i++) {
161 Object key = oldKeys[i]; 155 Object key = oldKeys[i];
Ivan Posva 2011/11/17 18:57:47 ditto.
Siggi Cherem (dart-lang) 2011/11/17 20:00:21 Done.
162 // If there is no key, we don't need to deal with the current slot. 156 // If there is no key, we don't need to deal with the current slot.
163 if (key === null || key === _deletedKey) { 157 if (key === null || key === _DELETED_KEY) {
164 continue; 158 continue;
165 } 159 }
166 V value = oldValues[i]; 160 V value = oldValues[i];
167 // Insert the {key, value} pair in their new slot. 161 // Insert the {key, value} pair in their new slot.
168 int newIndex = _probeForAdding(key); 162 int newIndex = _probeForAdding(key);
169 _keys[newIndex] = key; 163 _keys[newIndex] = key;
170 _values[newIndex] = value; 164 _values[newIndex] = value;
171 } 165 }
172 _numberOfDeleted = 0; 166 _numberOfDeleted = 0;
173 } 167 }
174 168
175 void clear() { 169 void clear() {
176 _numberOfEntries = 0; 170 _numberOfEntries = 0;
177 _numberOfDeleted = 0; 171 _numberOfDeleted = 0;
178 int length = _keys.length; 172 int length = _keys.length;
179 for (int i = 0; i < length; i++) { 173 for (int i = 0; i < length; i++) {
180 _keys[i] = null; 174 _keys[i] = null;
181 _values[i] = null; 175 _values[i] = null;
182 } 176 }
183 } 177 }
184 178
185 void operator []=(K key, V value) { 179 void operator []=(K key, V value) {
186 _ensureCapacity(); 180 _ensureCapacity();
187 int index = _probeForAdding(key); 181 int index = _probeForAdding(key);
188 if ((_keys[index] === null) || (_keys[index] === _deletedKey)) { 182 if ((_keys[index] === null) || (_keys[index] === _DELETED_KEY)) {
189 _numberOfEntries++; 183 _numberOfEntries++;
190 } 184 }
191 _keys[index] = key; 185 _keys[index] = key;
192 _values[index] = value; 186 _values[index] = value;
193 } 187 }
194 188
195 V operator [](K key) { 189 V operator [](K key) {
196 int index = _probeForLookup(key); 190 int index = _probeForLookup(key);
197 if (index < 0) return null; 191 if (index < 0) return null;
198 return _values[index]; 192 return _values[index];
199 } 193 }
200 194
201 V putIfAbsent(K key, V ifAbsent()) { 195 V putIfAbsent(K key, V ifAbsent()) {
202 int index = _probeForLookup(key); 196 int index = _probeForLookup(key);
203 if (index >=0) return _values[index]; 197 if (index >=0) return _values[index];
204 198
205 V value = ifAbsent(); 199 V value = ifAbsent();
206 this[key] = value; 200 this[key] = value;
207 return value; 201 return value;
208 } 202 }
209 203
210 V remove(K key) { 204 V remove(K key) {
211 int index = _probeForLookup(key); 205 int index = _probeForLookup(key);
212 if (index >= 0) { 206 if (index >= 0) {
213 _numberOfEntries--; 207 _numberOfEntries--;
214 V value = _values[index]; 208 V value = _values[index];
215 _values[index] = null; 209 _values[index] = null;
216 // Set the key to the sentinel to not break the probing chain. 210 // Set the key to the sentinel to not break the probing chain.
217 _keys[index] = _deletedKey; 211 _keys[index] = _DELETED_KEY;
218 _numberOfDeleted++; 212 _numberOfDeleted++;
219 return value; 213 return value;
220 } 214 }
221 return null; 215 return null;
222 } 216 }
223 217
224 bool isEmpty() { 218 bool isEmpty() {
225 return _numberOfEntries == 0; 219 return _numberOfEntries == 0;
226 } 220 }
227 221
228 int get length() { 222 int get length() {
229 return _numberOfEntries; 223 return _numberOfEntries;
230 } 224 }
231 225
232 void forEach(void f(K key, V value)) { 226 void forEach(void f(K key, V value)) {
233 int length = _keys.length; 227 int length = _keys.length;
234 for (int i = 0; i < length; i++) { 228 for (int i = 0; i < length; i++) {
235 if ((_keys[i] !== null) && (_keys[i] !== _deletedKey)) { 229 if ((_keys[i] !== null) && (_keys[i] !== _DELETED_KEY)) {
236 f(_keys[i], _values[i]); 230 f(_keys[i], _values[i]);
237 } 231 }
238 } 232 }
239 } 233 }
240 234
241 235
242 Collection<K> getKeys() { 236 Collection<K> getKeys() {
243 List<K> list = new List<K>(length); 237 List<K> list = new List<K>(length);
244 int i = 0; 238 int i = 0;
245 forEach(void _(K key, V value) { 239 forEach(void _(K key, V value) {
(...skipping 11 matching lines...) Expand all
257 return list; 251 return list;
258 } 252 }
259 253
260 bool containsKey(K key) { 254 bool containsKey(K key) {
261 return (_probeForLookup(key) != -1); 255 return (_probeForLookup(key) != -1);
262 } 256 }
263 257
264 bool containsValue(V value) { 258 bool containsValue(V value) {
265 int length = _values.length; 259 int length = _values.length;
266 for (int i = 0; i < length; i++) { 260 for (int i = 0; i < length; i++) {
267 if ((_keys[i] !== null) && (_keys[i] !== _deletedKey)) { 261 if ((_keys[i] !== null) && (_keys[i] !== _DELETED_KEY)) {
268 if (_values[i] == value) return true; 262 if (_values[i] == value) return true;
269 } 263 }
270 } 264 }
271 return false; 265 return false;
272 } 266 }
273 } 267 }
274 268
275 class HashSetImplementation<E extends Hashable> implements HashSet<E> { 269 class HashSetImplementation<E extends Hashable> implements HashSet<E> {
276 270
277 HashSetImplementation() { 271 HashSetImplementation() {
(...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after
381 375
382 // TODO(4504458): Replace set_ with set. 376 // TODO(4504458): Replace set_ with set.
383 HashSetIterator(HashSetImplementation<E> set_) 377 HashSetIterator(HashSetImplementation<E> set_)
384 : _nextValidIndex = -1, 378 : _nextValidIndex = -1,
385 _entries = set_._backingMap._keys { 379 _entries = set_._backingMap._keys {
386 _advance(); 380 _advance();
387 } 381 }
388 382
389 bool hasNext() { 383 bool hasNext() {
390 if (_nextValidIndex >= _entries.length) return false; 384 if (_nextValidIndex >= _entries.length) return false;
391 if (_entries[_nextValidIndex] === HashMapImplementation._deletedKey) { 385 if (_entries[_nextValidIndex] === HashMapImplementation._DELETED_KEY) {
392 // This happens in case the set was modified in the meantime. 386 // This happens in case the set was modified in the meantime.
393 // A modification on the set may make this iterator misbehave, 387 // A modification on the set may make this iterator misbehave,
394 // but we should never return the sentinel. 388 // but we should never return the sentinel.
395 _advance(); 389 _advance();
396 } 390 }
397 return _nextValidIndex < _entries.length; 391 return _nextValidIndex < _entries.length;
398 } 392 }
399 393
400 E next() { 394 E next() {
401 if (!hasNext()) { 395 if (!hasNext()) {
402 throw const NoMoreElementsException(); 396 throw const NoMoreElementsException();
403 } 397 }
404 E res = _entries[_nextValidIndex]; 398 E res = _entries[_nextValidIndex];
405 _advance(); 399 _advance();
406 return res; 400 return res;
407 } 401 }
408 402
409 void _advance() { 403 void _advance() {
410 int length = _entries.length; 404 int length = _entries.length;
411 var entry; 405 var entry;
412 Object deletedKey = HashMapImplementation._deletedKey; 406 Object deletedKey = HashMapImplementation._DELETED_KEY;
Ivan Posva 2011/11/17 18:57:47 ditto: var or _DeletedKeySentinel
Siggi Cherem (dart-lang) 2011/11/17 20:00:21 Done.
413 do { 407 do {
414 if (++_nextValidIndex >= length) break; 408 if (++_nextValidIndex >= length) break;
415 entry = _entries[_nextValidIndex]; 409 entry = _entries[_nextValidIndex];
416 } while ((entry === null) || (entry === deletedKey)); 410 } while ((entry === null) || (entry === deletedKey));
417 } 411 }
418 412
419 // The entries in the set. May contain null or the sentinel value. 413 // The entries in the set. May contain null or the sentinel value.
420 List<E> _entries; 414 List<E> _entries;
421 415
422 // The next valid index in [_entries] or the length of [entries_]. 416 // The next valid index in [_entries] or the length of [entries_].
423 // If it is the length of [_entries], calling [hasNext] on the 417 // If it is the length of [_entries], calling [hasNext] on the
424 // iterator will return false. 418 // iterator will return false.
425 int _nextValidIndex; 419 int _nextValidIndex;
426 } 420 }
421
422 /**
423 * A singleton sentinel used to represent when a key is deleted from the map.
424 * We can't use [: const Object() :] as a sentinel because it would end up
425 * canonicalized and then we cannot distinguish the deleted key from the
426 * canonicalized Object().
427 */
428 class _DeleteKeySentinel implements Hashable {
429 const _DeleteKeySentinel();
430 int hashCode() => 1;
Ivan Posva 2011/11/17 18:57:47 Why do you need the hashCode() method here at all?
Siggi Cherem (dart-lang) 2011/11/17 20:00:21 removed. I had some failing tests while implementi
431 }
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698