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

Side by Side Diff: runtime/lib/compact_hash.dart

Issue 983703003: Replace Linked{Identity,Custom}Hash{Map,Set} with compact implementation; remove old code and flag. (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: Created 5 years, 9 months 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 | « runtime/lib/collection_patch.dart ('k') | runtime/lib/linked_hash_map.cc » ('j') | 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) 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
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
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
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
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 }
OLDNEW
« no previous file with comments | « runtime/lib/collection_patch.dart ('k') | runtime/lib/linked_hash_map.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698