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 import 'dart:_internal' as internal; | 6 import 'dart:_internal' as internal; |
7 | 7 |
8 // Hash table with open addressing that separates the index from keys/values. | 8 // Hash table with open addressing that separates the index from keys/values. |
9 | 9 |
10 abstract class _HashFieldBase { | 10 abstract class _HashFieldBase { |
11 // Each occupied entry in _index is a fixed-size integer that encodes a pair: | 11 // Each occupied entry in _index is a fixed-size integer that encodes a pair: |
12 // [ hash pattern for key | index of entry in _data ] | 12 // [ hash pattern for key | index of entry in _data ] |
13 // The hash pattern is based on hashCode, but is guaranteed to be non-zero. | 13 // The hash pattern is based on hashCode, but is guaranteed to be non-zero. |
14 // The length of _index is always a power of two, and there is always at | 14 // The length of _index is always a power of two, and there is always at |
15 // least one unoccupied entry. | 15 // least one unoccupied entry. |
16 // NOTE: When maps are deserialized, their _index and _hashMask is regenerated | 16 // NOTE: When maps are deserialized, their _index and _hashMask is regenerated |
17 // lazily by _regenerateIndex. | 17 // lazily by _regenerateIndex. |
18 // TODO(koda): Consider also using null _index for tiny, linear-search tables. | 18 // TODO(koda): Consider also using null _index for tiny, linear-search tables. |
19 Uint32List _index; | 19 Uint32List _index = new Uint32List(_HashBase._INITIAL_INDEX_SIZE); |
20 | 20 |
21 // Cached in-place mask for the hash pattern component. | 21 // Cached in-place mask for the hash pattern component. |
22 int _hashMask; | 22 int _hashMask = _HashBase._indexSizeToHashMask(_HashBase._INITIAL_INDEX_SIZE); |
23 | 23 |
24 // Fixed-length list of keys (set) or key/value at even/odd indices (map). | 24 // Fixed-length list of keys (set) or key/value at even/odd indices (map). |
25 List _data; | 25 List _data; |
26 | 26 |
27 // Length of _data that is used (i.e., keys + values for a map). | 27 // Length of _data that is used (i.e., keys + values for a map). |
28 int _usedData = 0; | 28 int _usedData = 0; |
29 | 29 |
30 // Number of deleted keys. | 30 // Number of deleted keys. |
31 int _deletedKeys = 0; | 31 int _deletedKeys = 0; |
| 32 |
| 33 // Note: All fields are initialized in a single constructor so that the VM |
| 34 // recognizes they cannot hold null values. This makes a big (20%) performance |
| 35 // difference on some operations. |
| 36 _HashFieldBase(int dataSize) : this._data = new List(dataSize); |
32 } | 37 } |
33 | 38 |
34 // Base class for VM-internal classes; keep in sync with _HashFieldBase. | 39 // Base class for VM-internal classes; keep in sync with _HashFieldBase. |
35 abstract class _HashVMBase { | 40 abstract class _HashVMBase { |
36 Uint32List get _index native "LinkedHashMap_getIndex"; | 41 Uint32List get _index native "LinkedHashMap_getIndex"; |
37 void set _index(Uint32List value) native "LinkedHashMap_setIndex"; | 42 void set _index(Uint32List value) native "LinkedHashMap_setIndex"; |
38 | 43 |
39 int get _hashMask native "LinkedHashMap_getHashMask"; | 44 int get _hashMask native "LinkedHashMap_getHashMask"; |
40 void set _hashMask(int value) native "LinkedHashMap_setHashMask"; | 45 void set _hashMask(int value) native "LinkedHashMap_setHashMask"; |
41 | 46 |
(...skipping 303 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
345 new _CompactIterable<K>(this, _data, _usedData, -2, 2); | 350 new _CompactIterable<K>(this, _data, _usedData, -2, 2); |
346 Iterable<V> get values => | 351 Iterable<V> get values => |
347 new _CompactIterable<V>(this, _data, _usedData, -1, 2); | 352 new _CompactIterable<V>(this, _data, _usedData, -1, 2); |
348 } | 353 } |
349 | 354 |
350 class _CompactLinkedIdentityHashMap<K, V> extends _HashFieldBase | 355 class _CompactLinkedIdentityHashMap<K, V> extends _HashFieldBase |
351 with MapMixin<K, V>, _LinkedHashMapMixin<K, V>, _HashBase, | 356 with MapMixin<K, V>, _LinkedHashMapMixin<K, V>, _HashBase, |
352 _IdenticalAndIdentityHashCode | 357 _IdenticalAndIdentityHashCode |
353 implements LinkedHashMap<K, V> { | 358 implements LinkedHashMap<K, V> { |
354 | 359 |
355 _CompactLinkedIdentityHashMap() { | 360 _CompactLinkedIdentityHashMap() : super(_HashBase._INITIAL_INDEX_SIZE); |
356 _index = new Uint32List(_HashBase._INITIAL_INDEX_SIZE); | |
357 _hashMask = _HashBase._indexSizeToHashMask(_HashBase._INITIAL_INDEX_SIZE); | |
358 _data = new List(_HashBase._INITIAL_INDEX_SIZE); | |
359 } | |
360 } | 361 } |
361 | 362 |
362 class _CompactLinkedCustomHashMap<K, V> extends _HashFieldBase | 363 class _CompactLinkedCustomHashMap<K, V> extends _HashFieldBase |
363 with MapMixin<K, V>, _LinkedHashMapMixin<K, V>, _HashBase | 364 with MapMixin<K, V>, _LinkedHashMapMixin<K, V>, _HashBase |
364 implements LinkedHashMap<K, V> { | 365 implements LinkedHashMap<K, V> { |
365 final _equality; | 366 final _equality; |
366 final _hasher; | 367 final _hasher; |
367 final _validKey; | 368 final _validKey; |
368 | 369 |
369 // TODO(koda): Ask gbracha why I cannot have fields _equals/_hashCode. | 370 // TODO(koda): Ask gbracha why I cannot have fields _equals/_hashCode. |
370 int _hashCode(e) => _hasher(e); | 371 int _hashCode(e) => _hasher(e); |
371 bool _equals(e1, e2) => _equality(e1, e2); | 372 bool _equals(e1, e2) => _equality(e1, e2); |
372 | 373 |
373 bool containsKey(Object o) => _validKey(o) ? super.containsKey(o) : false; | 374 bool containsKey(Object o) => _validKey(o) ? super.containsKey(o) : false; |
374 V operator[](Object o) => _validKey(o) ? super[o] : null; | 375 V operator[](Object o) => _validKey(o) ? super[o] : null; |
375 V remove(Object o) => _validKey(o) ? super.remove(o) : null; | 376 V remove(Object o) => _validKey(o) ? super.remove(o) : null; |
376 | 377 |
377 _CompactLinkedCustomHashMap(this._equality, this._hasher, validKey) | 378 _CompactLinkedCustomHashMap(this._equality, this._hasher, validKey) |
378 : _validKey = (validKey != null) ? validKey : new _TypeTest<K>().test { | 379 : _validKey = (validKey != null) ? validKey : new _TypeTest<K>().test, |
379 _index = new Uint32List(_HashBase._INITIAL_INDEX_SIZE); | 380 super(_HashBase._INITIAL_INDEX_SIZE); |
380 _hashMask = _HashBase._indexSizeToHashMask(_HashBase._INITIAL_INDEX_SIZE); | |
381 _data = new List(_HashBase._INITIAL_INDEX_SIZE); | |
382 } | |
383 } | 381 } |
384 | 382 |
385 // Iterates through _data[_offset + _step], _data[_offset + 2*_step], ... | 383 // Iterates through _data[_offset + _step], _data[_offset + 2*_step], ... |
386 // and checks for concurrent modification. | 384 // and checks for concurrent modification. |
387 class _CompactIterable<E> extends IterableBase<E> { | 385 class _CompactIterable<E> extends IterableBase<E> { |
388 final _table; | 386 final _table; |
389 final List _data; | 387 final List _data; |
390 final int _len; | 388 final int _len; |
391 final int _offset; | 389 final int _offset; |
392 final int _step; | 390 final int _step; |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
429 return false; | 427 return false; |
430 } | 428 } |
431 } | 429 } |
432 } | 430 } |
433 | 431 |
434 // Set implementation, analogous to _CompactLinkedHashMap. | 432 // Set implementation, analogous to _CompactLinkedHashMap. |
435 class _CompactLinkedHashSet<E> extends _HashFieldBase | 433 class _CompactLinkedHashSet<E> extends _HashFieldBase |
436 with _HashBase, _OperatorEqualsAndHashCode, SetMixin<E> | 434 with _HashBase, _OperatorEqualsAndHashCode, SetMixin<E> |
437 implements LinkedHashSet<E> { | 435 implements LinkedHashSet<E> { |
438 | 436 |
439 _CompactLinkedHashSet() { | 437 _CompactLinkedHashSet() : super(_HashBase._INITIAL_INDEX_SIZE >> 1) { |
440 assert(_HashBase._UNUSED_PAIR == 0); | 438 assert(_HashBase._UNUSED_PAIR == 0); |
441 _index = new Uint32List(_HashBase._INITIAL_INDEX_SIZE); | |
442 _hashMask = _HashBase._indexSizeToHashMask(_HashBase._INITIAL_INDEX_SIZE); | |
443 _data = new List(_HashBase._INITIAL_INDEX_SIZE >> 1); | |
444 } | 439 } |
445 | 440 |
446 int get length => _usedData - _deletedKeys; | 441 int get length => _usedData - _deletedKeys; |
447 | 442 |
448 void _rehash() { | 443 void _rehash() { |
449 if ((_deletedKeys << 1) > _usedData) { | 444 if ((_deletedKeys << 1) > _usedData) { |
450 _init(_index.length, _hashMask, _data, _usedData); | 445 _init(_index.length, _hashMask, _data, _usedData); |
451 } else { | 446 } else { |
452 _init(_index.length << 1, _hashMask >> 1, _data, _usedData); | 447 _init(_index.length << 1, _hashMask >> 1, _data, _usedData); |
453 } | 448 } |
(...skipping 137 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
591 E lookup(Object o) => _validKey(o) ? super.lookup(o) : null; | 586 E lookup(Object o) => _validKey(o) ? super.lookup(o) : null; |
592 bool remove(Object o) => _validKey(o) ? super.remove(o) : false; | 587 bool remove(Object o) => _validKey(o) ? super.remove(o) : false; |
593 | 588 |
594 _CompactLinkedCustomHashSet(this._equality, this._hasher, validKey) | 589 _CompactLinkedCustomHashSet(this._equality, this._hasher, validKey) |
595 : _validKey = (validKey != null) ? validKey : new _TypeTest<E>().test; | 590 : _validKey = (validKey != null) ? validKey : new _TypeTest<E>().test; |
596 | 591 |
597 Set<E> toSet() => | 592 Set<E> toSet() => |
598 new _CompactLinkedCustomHashSet<E>(_equality, _hasher, _validKey) | 593 new _CompactLinkedCustomHashSet<E>(_equality, _hasher, _validKey) |
599 ..addAll(this); | 594 ..addAll(this); |
600 } | 595 } |
OLD | NEW |