OLD | NEW |
---|---|
1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2015, 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 import 'dart:typed_data'; | 5 import 'dart:typed_data'; |
6 | 6 |
7 // Hash table with open addressing that separates the index from keys/values. | 7 // Hash table with open addressing that separates the index from keys/values. |
8 abstract class _HashBase { | 8 abstract class _HashBase { |
9 // Each occupied entry in _index is a fixed-size integer that encodes a pair: | 9 // Each occupied entry in _index is a fixed-size integer that encodes a pair: |
10 // [ hash pattern for key | index of entry in _data ] | 10 // [ hash pattern for key | index of entry in _data ] |
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
61 data[d] = data; | 61 data[d] = data; |
62 } | 62 } |
63 | 63 |
64 // Concurrent modification detection relies on this checksum monotonically | 64 // Concurrent modification detection relies on this checksum monotonically |
65 // increasing between reallocations of _data. | 65 // increasing between reallocations of _data. |
66 int get _checkSum => _usedData + _deletedKeys; | 66 int get _checkSum => _usedData + _deletedKeys; |
67 bool _isModifiedSince(List oldData, int oldCheckSum) => | 67 bool _isModifiedSince(List oldData, int oldCheckSum) => |
68 !identical(_data, oldData) || (_checkSum != oldCheckSum); | 68 !identical(_data, oldData) || (_checkSum != oldCheckSum); |
69 } | 69 } |
70 | 70 |
71 abstract class _OperatorEqualsAndHashCode { | |
Ivan Posva
2015/03/05 20:45:34
Why "abstract"?
| |
72 int _hashCode(e) => e.hashCode; | |
73 bool _equals(e1, e2) => e1 == e2; | |
74 } | |
75 | |
76 abstract class _IdenticalAndIdentityHashCode { | |
77 int _hashCode(e) => identityHashCode(e); | |
78 bool _equals(e1, e2) => identical(e1, e2); | |
79 } | |
80 | |
71 // Map with iteration in insertion order (hence "Linked"). New keys are simply | 81 // Map with iteration in insertion order (hence "Linked"). New keys are simply |
72 // appended to _data. | 82 // appended to _data. |
73 class _CompactLinkedHashMap<K, V> | 83 class _CompactLinkedHashMap<K, V> |
74 extends MapBase<K, V> with _HashBase | 84 extends MapBase<K, V> with _HashBase, _OperatorEqualsAndHashCode |
75 implements HashMap<K, V>, LinkedHashMap<K, V> { | 85 implements HashMap<K, V>, LinkedHashMap<K, V> { |
Ivan Posva
2015/03/05 20:45:34
I think you can drop the "HashMap<K,V>" from the i
| |
76 | 86 |
77 _CompactLinkedHashMap() { | 87 _CompactLinkedHashMap() { |
78 assert(_HashBase._UNUSED_PAIR == 0); | 88 assert(_HashBase._UNUSED_PAIR == 0); |
79 _index = new Uint32List(_HashBase._INITIAL_INDEX_SIZE); | 89 _index = new Uint32List(_HashBase._INITIAL_INDEX_SIZE); |
80 _data = new List(_HashBase._INITIAL_INDEX_SIZE); | 90 _data = new List(_HashBase._INITIAL_INDEX_SIZE); |
81 } | 91 } |
82 | 92 |
83 int get length => (_usedData >> 1) - _deletedKeys; | 93 int get length => (_usedData >> 1) - _deletedKeys; |
84 bool get isEmpty => length == 0; | 94 bool get isEmpty => length == 0; |
85 bool get isNotEmpty => !isEmpty; | 95 bool get isNotEmpty => !isEmpty; |
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
145 int pair = _index[i]; | 155 int pair = _index[i]; |
146 while (pair != _HashBase._UNUSED_PAIR) { | 156 while (pair != _HashBase._UNUSED_PAIR) { |
147 if (pair == _HashBase._DELETED_PAIR) { | 157 if (pair == _HashBase._DELETED_PAIR) { |
148 if (firstDeleted < 0){ | 158 if (firstDeleted < 0){ |
149 firstDeleted = i; | 159 firstDeleted = i; |
150 } | 160 } |
151 } else { | 161 } else { |
152 final int entry = hashPattern ^ pair; | 162 final int entry = hashPattern ^ pair; |
153 if (entry < maxEntries) { | 163 if (entry < maxEntries) { |
154 final int d = entry << 1; | 164 final int d = entry << 1; |
155 if (key == _data[d]) { | 165 if (_equals(key, _data[d])) { |
156 return d + 1; | 166 return d + 1; |
157 } | 167 } |
158 } | 168 } |
159 } | 169 } |
160 i = _HashBase._nextProbe(i, sizeMask); | 170 i = _HashBase._nextProbe(i, sizeMask); |
161 pair = _index[i]; | 171 pair = _index[i]; |
162 } | 172 } |
163 return firstDeleted >= 0 ? -firstDeleted : -i; | 173 return firstDeleted >= 0 ? -firstDeleted : -i; |
164 } | 174 } |
165 | 175 |
166 void operator[]=(K key, V value) { | 176 void operator[]=(K key, V value) { |
167 final int size = _index.length; | 177 final int size = _index.length; |
168 final int sizeMask = size - 1; | 178 final int sizeMask = size - 1; |
169 final int fullHash = key.hashCode; | 179 final int fullHash = _hashCode(key); |
170 final int hashPattern = _HashBase._hashPattern(fullHash, _hashMask, size); | 180 final int hashPattern = _HashBase._hashPattern(fullHash, _hashMask, size); |
171 final int d = _findValueOrInsertPoint(key, fullHash, hashPattern, size); | 181 final int d = _findValueOrInsertPoint(key, fullHash, hashPattern, size); |
172 if (d > 0) { | 182 if (d > 0) { |
173 _data[d] = value; | 183 _data[d] = value; |
174 } else { | 184 } else { |
175 final int i = -d; | 185 final int i = -d; |
176 _insert(key, value, hashPattern, i); | 186 _insert(key, value, hashPattern, i); |
177 } | 187 } |
178 } | 188 } |
179 | 189 |
180 V putIfAbsent(K key, V ifAbsent()) { | 190 V putIfAbsent(K key, V ifAbsent()) { |
181 final int size = _index.length; | 191 final int size = _index.length; |
182 final int sizeMask = size - 1; | 192 final int sizeMask = size - 1; |
183 final int maxEntries = size >> 1; | 193 final int maxEntries = size >> 1; |
184 final int fullHash = key.hashCode; | 194 final int fullHash = _hashCode(key); |
185 final int hashPattern = _HashBase._hashPattern(fullHash, _hashMask, size); | 195 final int hashPattern = _HashBase._hashPattern(fullHash, _hashMask, size); |
186 final int d = _findValueOrInsertPoint(key, fullHash, hashPattern, size); | 196 final int d = _findValueOrInsertPoint(key, fullHash, hashPattern, size); |
187 if (d > 0) { | 197 if (d > 0) { |
188 return _data[d]; | 198 return _data[d]; |
189 } | 199 } |
190 // 'ifAbsent' is allowed to modify the map. | 200 // 'ifAbsent' is allowed to modify the map. |
191 List oldData = _data; | 201 List oldData = _data; |
192 int oldCheckSum = _checkSum; | 202 int oldCheckSum = _checkSum; |
193 V value = ifAbsent(); | 203 V value = ifAbsent(); |
194 if (_isModifiedSince(oldData, oldCheckSum)) { | 204 if (_isModifiedSince(oldData, oldCheckSum)) { |
195 this[key] = value; | 205 this[key] = value; |
196 } else { | 206 } else { |
197 final int i = -d; | 207 final int i = -d; |
198 _insert(key, value, hashPattern, i); | 208 _insert(key, value, hashPattern, i); |
199 } | 209 } |
200 return value; | 210 return value; |
201 } | 211 } |
202 | 212 |
203 V remove(Object key) { | 213 V remove(Object key) { |
204 final int size = _index.length; | 214 final int size = _index.length; |
205 final int sizeMask = size - 1; | 215 final int sizeMask = size - 1; |
206 final int maxEntries = size >> 1; | 216 final int maxEntries = size >> 1; |
207 final int fullHash = key.hashCode; | 217 final int fullHash = _hashCode(key); |
208 final int hashPattern = _HashBase._hashPattern(fullHash, _hashMask, size); | 218 final int hashPattern = _HashBase._hashPattern(fullHash, _hashMask, size); |
209 int i = _HashBase._firstProbe(fullHash, sizeMask); | 219 int i = _HashBase._firstProbe(fullHash, sizeMask); |
210 int pair = _index[i]; | 220 int pair = _index[i]; |
211 while (pair != _HashBase._UNUSED_PAIR) { | 221 while (pair != _HashBase._UNUSED_PAIR) { |
212 if (pair != _HashBase._DELETED_PAIR) { | 222 if (pair != _HashBase._DELETED_PAIR) { |
213 final int entry = hashPattern ^ pair; | 223 final int entry = hashPattern ^ pair; |
214 if (entry < maxEntries) { | 224 if (entry < maxEntries) { |
215 final int d = entry << 1; | 225 final int d = entry << 1; |
216 if (key == _data[d]) { | 226 if (_equals(key, _data[d])) { |
217 _index[i] = _HashBase._DELETED_PAIR; | 227 _index[i] = _HashBase._DELETED_PAIR; |
218 _HashBase._setDeletedAt(_data, d); | 228 _HashBase._setDeletedAt(_data, d); |
219 V value = _data[d + 1]; | 229 V value = _data[d + 1]; |
220 _HashBase._setDeletedAt(_data, d + 1); | 230 _HashBase._setDeletedAt(_data, d + 1); |
221 ++_deletedKeys; | 231 ++_deletedKeys; |
222 return value; | 232 return value; |
223 } | 233 } |
224 } | 234 } |
225 } | 235 } |
226 i = _HashBase._nextProbe(i, sizeMask); | 236 i = _HashBase._nextProbe(i, sizeMask); |
227 pair = _index[i]; | 237 pair = _index[i]; |
228 } | 238 } |
229 return null; | 239 return null; |
230 } | 240 } |
231 | 241 |
232 // If key is absent, return _data (which is never a value). | 242 // If key is absent, return _data (which is never a value). |
233 Object _getValueOrData(Object key) { | 243 Object _getValueOrData(Object key) { |
234 final int size = _index.length; | 244 final int size = _index.length; |
235 final int sizeMask = size - 1; | 245 final int sizeMask = size - 1; |
236 final int maxEntries = size >> 1; | 246 final int maxEntries = size >> 1; |
237 final int fullHash = key.hashCode; | 247 final int fullHash = _hashCode(key); |
238 final int hashPattern = _HashBase._hashPattern(fullHash, _hashMask, size); | 248 final int hashPattern = _HashBase._hashPattern(fullHash, _hashMask, size); |
239 int i = _HashBase._firstProbe(fullHash, sizeMask); | 249 int i = _HashBase._firstProbe(fullHash, sizeMask); |
240 int pair = _index[i]; | 250 int pair = _index[i]; |
241 while (pair != _HashBase._UNUSED_PAIR) { | 251 while (pair != _HashBase._UNUSED_PAIR) { |
242 if (pair != _HashBase._DELETED_PAIR) { | 252 if (pair != _HashBase._DELETED_PAIR) { |
243 final int entry = hashPattern ^ pair; | 253 final int entry = hashPattern ^ pair; |
244 if (entry < maxEntries) { | 254 if (entry < maxEntries) { |
245 final int d = entry << 1; | 255 final int d = entry << 1; |
246 if (key == _data[d]) { | 256 if (_equals(key, _data[d])) { |
247 return _data[d + 1]; | 257 return _data[d + 1]; |
248 } | 258 } |
249 } | 259 } |
250 } | 260 } |
251 i = _HashBase._nextProbe(i, sizeMask); | 261 i = _HashBase._nextProbe(i, sizeMask); |
252 pair = _index[i]; | 262 pair = _index[i]; |
253 } | 263 } |
254 return _data; | 264 return _data; |
255 } | 265 } |
256 | 266 |
257 bool containsKey(Object key) => !identical(_data, _getValueOrData(key)); | 267 bool containsKey(Object key) => !identical(_data, _getValueOrData(key)); |
258 | 268 |
259 V operator[](Object key) { | 269 V operator[](Object key) { |
260 var v = _getValueOrData(key); | 270 var v = _getValueOrData(key); |
261 return identical(_data, v) ? null : v; | 271 return identical(_data, v) ? null : v; |
262 } | 272 } |
263 | 273 |
264 bool containsValue(Object value) { | 274 bool containsValue(Object value) { |
265 for (var v in values) { | 275 for (var v in values) { |
276 // Spec. says this should always use "==", also for identity maps, etc. | |
266 if (v == value) { | 277 if (v == value) { |
267 return true; | 278 return true; |
268 } | 279 } |
269 } | 280 } |
270 return false; | 281 return false; |
271 } | 282 } |
272 | 283 |
273 void forEach(void f(K key, V value)) { | 284 void forEach(void f(K key, V value)) { |
274 var ki = keys.iterator; | 285 var ki = keys.iterator; |
275 var vi = values.iterator; | 286 var vi = values.iterator; |
276 while (ki.moveNext()) { | 287 while (ki.moveNext()) { |
277 vi.moveNext(); | 288 vi.moveNext(); |
278 f(ki.current, vi.current); | 289 f(ki.current, vi.current); |
279 } | 290 } |
280 } | 291 } |
281 | 292 |
282 Iterable<K> get keys => | 293 Iterable<K> get keys => |
283 new _CompactIterable<K>(this, _data, _usedData, -2, 2); | 294 new _CompactIterable<K>(this, _data, _usedData, -2, 2); |
284 Iterable<V> get values => | 295 Iterable<V> get values => |
285 new _CompactIterable<V>(this, _data, _usedData, -1, 2); | 296 new _CompactIterable<V>(this, _data, _usedData, -1, 2); |
286 } | 297 } |
287 | 298 |
299 class _CompactLinkedIdentityHashMap<K, V> | |
300 extends _CompactLinkedHashMap<K, V> with _IdenticalAndIdentityHashCode { | |
301 } | |
302 | |
303 class _CompactLinkedCustomHashMap<K, V> | |
304 extends _CompactLinkedHashMap<K, V> { | |
305 final _equality; | |
306 final _hasher; | |
307 final _validKey; | |
308 | |
309 // TODO(koda): Ask gbracha why I cannot have fields _equals/_hashCode. | |
310 int _hashCode(e) => _hasher(e); | |
311 bool _equals(e1, e2) => _equality(e1, e2); | |
312 | |
313 bool containsKey(Object o) => _validKey(o) ? super.containsKey(o) : false; | |
314 V operator[](Object o) => _validKey(o) ? super[o] : null; | |
315 V remove(Object o) => _validKey(o) ? super.remove(o) : null; | |
316 | |
317 _CompactLinkedCustomHashMap(this._equality, this._hasher, validKey) | |
318 : _validKey = (validKey != null) ? validKey : new _TypeTest<E>().test; | |
319 } | |
320 | |
288 // Iterates through _data[_offset + _step], _data[_offset + 2*_step], ... | 321 // Iterates through _data[_offset + _step], _data[_offset + 2*_step], ... |
289 // and checks for concurrent modification. | 322 // and checks for concurrent modification. |
290 class _CompactIterable<E> extends IterableBase<E> { | 323 class _CompactIterable<E> extends IterableBase<E> { |
291 final _table; | 324 final _table; |
292 final List _data; | 325 final List _data; |
293 final int _len; | 326 final int _len; |
294 final int _offset; | 327 final int _offset; |
295 final int _step; | 328 final int _step; |
296 | 329 |
297 _CompactIterable(this._table, this._data, this._len, | 330 _CompactIterable(this._table, this._data, this._len, |
(...skipping 30 matching lines...) Expand all Loading... | |
328 current = _data[_offset]; | 361 current = _data[_offset]; |
329 return true; | 362 return true; |
330 } else { | 363 } else { |
331 current = null; | 364 current = null; |
332 return false; | 365 return false; |
333 } | 366 } |
334 } | 367 } |
335 } | 368 } |
336 | 369 |
337 // Set implementation, analogous to _CompactLinkedHashMap. | 370 // Set implementation, analogous to _CompactLinkedHashMap. |
338 class _CompactLinkedHashSet<K> | 371 class _CompactLinkedHashSet<E> |
339 extends SetBase<K> with _HashBase | 372 extends SetBase<E> with _HashBase, _OperatorEqualsAndHashCode |
340 implements LinkedHashSet<K> { | 373 implements LinkedHashSet<E> { |
341 | 374 |
342 _CompactLinkedHashSet() { | 375 _CompactLinkedHashSet() { |
343 assert(_HashBase._UNUSED_PAIR == 0); | 376 assert(_HashBase._UNUSED_PAIR == 0); |
344 _index = new Uint32List(_HashBase._INITIAL_INDEX_SIZE); | 377 _index = new Uint32List(_HashBase._INITIAL_INDEX_SIZE); |
345 _data = new List(_HashBase._INITIAL_INDEX_SIZE >> 1); | 378 _data = new List(_HashBase._INITIAL_INDEX_SIZE >> 1); |
346 } | 379 } |
347 | 380 |
348 int get length => _usedData - _deletedKeys; | 381 int get length => _usedData - _deletedKeys; |
349 | 382 |
350 void _rehash() { | 383 void _rehash() { |
(...skipping 19 matching lines...) Expand all Loading... | |
370 if (oldData != null) { | 403 if (oldData != null) { |
371 for (int i = 0; i < oldUsed; i += 1) { | 404 for (int i = 0; i < oldUsed; i += 1) { |
372 var key = oldData[i]; | 405 var key = oldData[i]; |
373 if (!_HashBase._isDeleted(oldData, key)) { | 406 if (!_HashBase._isDeleted(oldData, key)) { |
374 add(key); | 407 add(key); |
375 } | 408 } |
376 } | 409 } |
377 } | 410 } |
378 } | 411 } |
379 | 412 |
380 bool add(K key) { | 413 bool add(E key) { |
381 final int size = _index.length; | 414 final int size = _index.length; |
382 final int sizeMask = size - 1; | 415 final int sizeMask = size - 1; |
383 final int maxEntries = size >> 1; | 416 final int maxEntries = size >> 1; |
384 final int fullHash = key.hashCode; | 417 final int fullHash = _hashCode(key); |
385 final int hashPattern = _HashBase._hashPattern(fullHash, _hashMask, size); | 418 final int hashPattern = _HashBase._hashPattern(fullHash, _hashMask, size); |
386 int i = _HashBase._firstProbe(fullHash, sizeMask); | 419 int i = _HashBase._firstProbe(fullHash, sizeMask); |
387 int firstDeleted = -1; | 420 int firstDeleted = -1; |
388 int pair = _index[i]; | 421 int pair = _index[i]; |
389 while (pair != _HashBase._UNUSED_PAIR) { | 422 while (pair != _HashBase._UNUSED_PAIR) { |
390 if (pair == _HashBase._DELETED_PAIR) { | 423 if (pair == _HashBase._DELETED_PAIR) { |
391 if (firstDeleted < 0){ | 424 if (firstDeleted < 0){ |
392 firstDeleted = i; | 425 firstDeleted = i; |
393 } | 426 } |
394 } else { | 427 } else { |
395 final int d = hashPattern ^ pair; | 428 final int d = hashPattern ^ pair; |
396 if (d < maxEntries && key == _data[d]) { | 429 if (d < maxEntries && _equals(key, _data[d])) { |
397 return false; | 430 return false; |
398 } | 431 } |
399 } | 432 } |
400 i = _HashBase._nextProbe(i, sizeMask); | 433 i = _HashBase._nextProbe(i, sizeMask); |
401 pair = _index[i]; | 434 pair = _index[i]; |
402 } | 435 } |
403 if (_usedData == _data.length) { | 436 if (_usedData == _data.length) { |
404 _rehash(); | 437 _rehash(); |
405 add(key); | 438 add(key); |
406 } else { | 439 } else { |
407 final int insertionPoint = (firstDeleted >= 0) ? firstDeleted : i; | 440 final int insertionPoint = (firstDeleted >= 0) ? firstDeleted : i; |
408 assert(1 <= hashPattern && hashPattern < (1 << 32)); | 441 assert(1 <= hashPattern && hashPattern < (1 << 32)); |
409 assert((hashPattern & _usedData) == 0); | 442 assert((hashPattern & _usedData) == 0); |
410 _index[insertionPoint] = hashPattern | _usedData; | 443 _index[insertionPoint] = hashPattern | _usedData; |
411 _data[_usedData++] = key; | 444 _data[_usedData++] = key; |
412 } | 445 } |
413 return true; | 446 return true; |
414 } | 447 } |
415 | 448 |
416 // If key is absent, return _data (which is never a value). | 449 // If key is absent, return _data (which is never a value). |
417 Object _getKeyOrData(Object key) { | 450 Object _getKeyOrData(Object key) { |
418 final int size = _index.length; | 451 final int size = _index.length; |
419 final int sizeMask = size - 1; | 452 final int sizeMask = size - 1; |
420 final int maxEntries = size >> 1; | 453 final int maxEntries = size >> 1; |
421 final int fullHash = key.hashCode; | 454 final int fullHash = _hashCode(key); |
422 final int hashPattern = _HashBase._hashPattern(fullHash, _hashMask, size); | 455 final int hashPattern = _HashBase._hashPattern(fullHash, _hashMask, size); |
423 int i = _HashBase._firstProbe(fullHash, sizeMask); | 456 int i = _HashBase._firstProbe(fullHash, sizeMask); |
424 int pair = _index[i]; | 457 int pair = _index[i]; |
425 while (pair != _HashBase._UNUSED_PAIR) { | 458 while (pair != _HashBase._UNUSED_PAIR) { |
426 if (pair != _HashBase._DELETED_PAIR) { | 459 if (pair != _HashBase._DELETED_PAIR) { |
427 final int d = hashPattern ^ pair; | 460 final int d = hashPattern ^ pair; |
428 if (d < maxEntries && key == _data[d]) { | 461 if (d < maxEntries && _equals(key, _data[d])) { |
429 return _data[d]; // Note: Must return the existing key. | 462 return _data[d]; // Note: Must return the existing key. |
430 } | 463 } |
431 } | 464 } |
432 i = _HashBase._nextProbe(i, sizeMask); | 465 i = _HashBase._nextProbe(i, sizeMask); |
433 pair = _index[i]; | 466 pair = _index[i]; |
434 } | 467 } |
435 return _data; | 468 return _data; |
436 } | 469 } |
437 | 470 |
438 K lookup(Object key) { | 471 E lookup(Object key) { |
439 var k = _getKeyOrData(key); | 472 var k = _getKeyOrData(key); |
440 return identical(_data, k) ? null : k; | 473 return identical(_data, k) ? null : k; |
441 } | 474 } |
442 | 475 |
443 bool contains(Object key) => !identical(_data, _getKeyOrData(key)); | 476 bool contains(Object key) => !identical(_data, _getKeyOrData(key)); |
444 | 477 |
445 bool remove(Object key) { | 478 bool remove(Object key) { |
446 final int size = _index.length; | 479 final int size = _index.length; |
447 final int sizeMask = size - 1; | 480 final int sizeMask = size - 1; |
448 final int maxEntries = size >> 1; | 481 final int maxEntries = size >> 1; |
449 final int fullHash = key.hashCode; | 482 final int fullHash = _hashCode(key); |
450 final int hashPattern = _HashBase._hashPattern(fullHash, _hashMask, size); | 483 final int hashPattern = _HashBase._hashPattern(fullHash, _hashMask, size); |
451 int i = _HashBase._firstProbe(fullHash, sizeMask); | 484 int i = _HashBase._firstProbe(fullHash, sizeMask); |
452 int pair = _index[i]; | 485 int pair = _index[i]; |
453 while (pair != _HashBase._UNUSED_PAIR) { | 486 while (pair != _HashBase._UNUSED_PAIR) { |
454 if (pair != _HashBase._DELETED_PAIR) { | 487 if (pair != _HashBase._DELETED_PAIR) { |
455 final int d = hashPattern ^ pair; | 488 final int d = hashPattern ^ pair; |
456 if (d < maxEntries && key == _data[d]) { | 489 if (d < maxEntries && _equals(key, _data[d])) { |
457 _index[i] = _HashBase._DELETED_PAIR; | 490 _index[i] = _HashBase._DELETED_PAIR; |
458 _HashBase._setDeletedAt(_data, d); | 491 _HashBase._setDeletedAt(_data, d); |
459 ++_deletedKeys; | 492 ++_deletedKeys; |
460 return true; | 493 return true; |
461 } | 494 } |
462 } | 495 } |
463 i = _HashBase._nextProbe(i, sizeMask); | 496 i = _HashBase._nextProbe(i, sizeMask); |
464 pair = _index[i]; | 497 pair = _index[i]; |
465 } | 498 } |
466 return false; | 499 return false; |
467 } | 500 } |
468 | 501 |
469 Iterator<K> get iterator => | 502 Iterator<E> get iterator => |
470 new _CompactIterator<K>(this, _data, _usedData, -1, 1); | 503 new _CompactIterator<E>(this, _data, _usedData, -1, 1); |
471 | 504 |
472 Set<K> toSet() => new Set<K>()..addAll(this); | 505 // Returns a set of the same type, although this |
506 // is not required by the spec. (For instance, always using an identity set | |
507 // would be technically correct, albeit surprising.) | |
508 Set<E> toSet() => new _CompactLinkedHashSet<E>()..addAll(this); | |
473 } | 509 } |
510 | |
511 class _CompactLinkedIdentityHashSet<E> | |
512 extends _CompactLinkedHashSet<E> with _IdenticalAndIdentityHashCode { | |
513 Set<E> toSet() => new _CompactLinkedIdentityHashSet<E>()..addAll(this); | |
514 } | |
515 | |
516 class _CompactLinkedCustomHashSet<E> | |
517 extends _CompactLinkedHashSet<E> { | |
518 final _equality; | |
519 final _hasher; | |
520 final _validKey; | |
521 | |
522 int _hashCode(e) => _hasher(e); | |
523 bool _equals(e1, e2) => _equality(e1, e2); | |
524 | |
525 bool contains(Object o) => _validKey(o) ? super.contains(o) : false; | |
526 E lookup(Object o) => _validKey(o) ? super.lookup(o) : null; | |
527 bool remove(Object o) => _validKey(o) ? super.remove(o) : false; | |
528 | |
529 _CompactLinkedCustomHashSet(this._equality, this._hasher, validKey) | |
530 : _validKey = (validKey != null) ? validKey : new _TypeTest<E>().test; | |
531 | |
532 Set<E> toSet() => | |
533 new _CompactLinkedCustomHashSet<E>(_equality, _hasher, _validKey) | |
534 ..addAll(this); | |
535 } | |
OLD | NEW |