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 14 matching lines...) Expand all Loading... |
25 static const int _UNUSED_PAIR = 0; | 25 static const int _UNUSED_PAIR = 0; |
26 static const int _DELETED_PAIR = 1; | 26 static const int _DELETED_PAIR = 1; |
27 | 27 |
28 // Cached in-place mask for the hash pattern component. On 32-bit, the top | 28 // Cached in-place mask for the hash pattern component. On 32-bit, the top |
29 // bits are wasted to avoid Mint allocation. | 29 // bits are wasted to avoid Mint allocation. |
30 // TODO(koda): Reclaim the bits by making the compiler treat hash patterns | 30 // TODO(koda): Reclaim the bits by making the compiler treat hash patterns |
31 // as unsigned words. | 31 // as unsigned words. |
32 int _hashMask = int.is64Bit() ? | 32 int _hashMask = int.is64Bit() ? |
33 (1 << (32 - _INITIAL_INDEX_BITS)) - 1 : | 33 (1 << (32 - _INITIAL_INDEX_BITS)) - 1 : |
34 (1 << (30 - _INITIAL_INDEX_BITS)) - 1; | 34 (1 << (30 - _INITIAL_INDEX_BITS)) - 1; |
35 | 35 |
36 static int _hashPattern(int fullHash, int hashMask, int size) => | 36 static int _hashPattern(int fullHash, int hashMask, int size) { |
37 // TODO(koda): Consider keeping bit length and use left shift. | 37 final int maskedHash = fullHash & hashMask; |
38 (fullHash == 0) ? (size >> 1) : (fullHash & hashMask) * (size >> 1); | 38 // TODO(koda): Consider keeping bit length and use left shift. |
| 39 return (maskedHash == 0) ? (size >> 1) : maskedHash * (size >> 1); |
| 40 } |
39 | 41 |
40 // Linear probing. | 42 // Linear probing. |
41 static int _firstProbe(int fullHash, int sizeMask) { | 43 static int _firstProbe(int fullHash, int sizeMask) { |
42 final int i = fullHash & sizeMask; | 44 final int i = fullHash & sizeMask; |
43 // Light, fast shuffle to mitigate bad hashCode (e.g., sequential). | 45 // Light, fast shuffle to mitigate bad hashCode (e.g., sequential). |
44 return ((i << 1) + i) & sizeMask; | 46 return ((i << 1) + i) & sizeMask; |
45 } | 47 } |
46 static int _nextProbe(int i, int sizeMask) => (i + 1) & sizeMask; | 48 static int _nextProbe(int i, int sizeMask) => (i + 1) & sizeMask; |
47 | 49 |
48 // Fixed-length list of keys (set) or key/value at even/odd indices (map). | 50 // Fixed-length list of keys (set) or key/value at even/odd indices (map). |
(...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
117 } | 119 } |
118 } | 120 } |
119 } | 121 } |
120 } | 122 } |
121 | 123 |
122 void _insert(K key, V value, int hashPattern, int i) { | 124 void _insert(K key, V value, int hashPattern, int i) { |
123 if (_usedData == _data.length) { | 125 if (_usedData == _data.length) { |
124 _rehash(); | 126 _rehash(); |
125 this[key] = value; | 127 this[key] = value; |
126 } else { | 128 } else { |
127 assert(0 <= hashPattern && hashPattern < (1 << 32)); | 129 assert(1 <= hashPattern && hashPattern < (1 << 32)); |
128 final int index = _usedData >> 1; | 130 final int index = _usedData >> 1; |
129 assert((index & hashPattern) == 0); | 131 assert((index & hashPattern) == 0); |
130 _index[i] = hashPattern | index; | 132 _index[i] = hashPattern | index; |
131 _data[_usedData++] = key; | 133 _data[_usedData++] = key; |
132 _data[_usedData++] = value; | 134 _data[_usedData++] = value; |
133 } | 135 } |
134 } | 136 } |
135 | 137 |
136 // If key is present, returns the index of the value in _data, else returns | 138 // If key is present, returns the index of the value in _data, else returns |
137 // the negated insertion point in _index. | 139 // the negated insertion point in _index. |
(...skipping 258 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
396 } | 398 } |
397 } | 399 } |
398 i = _HashBase._nextProbe(i, sizeMask); | 400 i = _HashBase._nextProbe(i, sizeMask); |
399 pair = _index[i]; | 401 pair = _index[i]; |
400 } | 402 } |
401 if (_usedData == _data.length) { | 403 if (_usedData == _data.length) { |
402 _rehash(); | 404 _rehash(); |
403 add(key); | 405 add(key); |
404 } else { | 406 } else { |
405 final int insertionPoint = (firstDeleted >= 0) ? firstDeleted : i; | 407 final int insertionPoint = (firstDeleted >= 0) ? firstDeleted : i; |
406 assert(0 <= hashPattern && hashPattern < (1 << 32)); | 408 assert(1 <= hashPattern && hashPattern < (1 << 32)); |
407 assert((hashPattern & _usedData) == 0); | 409 assert((hashPattern & _usedData) == 0); |
408 _index[insertionPoint] = hashPattern | _usedData; | 410 _index[insertionPoint] = hashPattern | _usedData; |
409 _data[_usedData++] = key; | 411 _data[_usedData++] = key; |
410 } | 412 } |
411 return true; | 413 return true; |
412 } | 414 } |
413 | 415 |
414 // If key is absent, return _data (which is never a value). | 416 // If key is absent, return _data (which is never a value). |
415 Object _getKeyOrData(Object key) { | 417 Object _getKeyOrData(Object key) { |
416 final int size = _index.length; | 418 final int size = _index.length; |
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
462 pair = _index[i]; | 464 pair = _index[i]; |
463 } | 465 } |
464 return false; | 466 return false; |
465 } | 467 } |
466 | 468 |
467 Iterator<K> get iterator => | 469 Iterator<K> get iterator => |
468 new _CompactIterator<K>(this, _data, _usedData, -1, 1); | 470 new _CompactIterator<K>(this, _data, _usedData, -1, 1); |
469 | 471 |
470 Set<K> toSet() => new Set<K>()..addAll(this); | 472 Set<K> toSet() => new Set<K>()..addAll(this); |
471 } | 473 } |
OLD | NEW |