| 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 |