Chromium Code Reviews| Index: runtime/lib/compact_hash.dart |
| =================================================================== |
| --- runtime/lib/compact_hash.dart (revision 44194) |
| +++ runtime/lib/compact_hash.dart (working copy) |
| @@ -68,10 +68,20 @@ |
| !identical(_data, oldData) || (_checkSum != oldCheckSum); |
| } |
| +abstract class _OperatorEqualsAndHashCode { |
|
Ivan Posva
2015/03/05 20:45:34
Why "abstract"?
|
| + int _hashCode(e) => e.hashCode; |
| + bool _equals(e1, e2) => e1 == e2; |
| +} |
| + |
| +abstract class _IdenticalAndIdentityHashCode { |
| + int _hashCode(e) => identityHashCode(e); |
| + bool _equals(e1, e2) => identical(e1, e2); |
| +} |
| + |
| // Map with iteration in insertion order (hence "Linked"). New keys are simply |
| // appended to _data. |
| class _CompactLinkedHashMap<K, V> |
| - extends MapBase<K, V> with _HashBase |
| + extends MapBase<K, V> with _HashBase, _OperatorEqualsAndHashCode |
| 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
|
| _CompactLinkedHashMap() { |
| @@ -152,7 +162,7 @@ |
| final int entry = hashPattern ^ pair; |
| if (entry < maxEntries) { |
| final int d = entry << 1; |
| - if (key == _data[d]) { |
| + if (_equals(key, _data[d])) { |
| return d + 1; |
| } |
| } |
| @@ -166,7 +176,7 @@ |
| void operator[]=(K key, V value) { |
| final int size = _index.length; |
| final int sizeMask = size - 1; |
| - final int fullHash = key.hashCode; |
| + final int fullHash = _hashCode(key); |
| final int hashPattern = _HashBase._hashPattern(fullHash, _hashMask, size); |
| final int d = _findValueOrInsertPoint(key, fullHash, hashPattern, size); |
| if (d > 0) { |
| @@ -181,7 +191,7 @@ |
| final int size = _index.length; |
| final int sizeMask = size - 1; |
| final int maxEntries = size >> 1; |
| - final int fullHash = key.hashCode; |
| + final int fullHash = _hashCode(key); |
| final int hashPattern = _HashBase._hashPattern(fullHash, _hashMask, size); |
| final int d = _findValueOrInsertPoint(key, fullHash, hashPattern, size); |
| if (d > 0) { |
| @@ -204,7 +214,7 @@ |
| final int size = _index.length; |
| final int sizeMask = size - 1; |
| final int maxEntries = size >> 1; |
| - final int fullHash = key.hashCode; |
| + final int fullHash = _hashCode(key); |
| final int hashPattern = _HashBase._hashPattern(fullHash, _hashMask, size); |
| int i = _HashBase._firstProbe(fullHash, sizeMask); |
| int pair = _index[i]; |
| @@ -213,7 +223,7 @@ |
| final int entry = hashPattern ^ pair; |
| if (entry < maxEntries) { |
| final int d = entry << 1; |
| - if (key == _data[d]) { |
| + if (_equals(key, _data[d])) { |
| _index[i] = _HashBase._DELETED_PAIR; |
| _HashBase._setDeletedAt(_data, d); |
| V value = _data[d + 1]; |
| @@ -234,7 +244,7 @@ |
| final int size = _index.length; |
| final int sizeMask = size - 1; |
| final int maxEntries = size >> 1; |
| - final int fullHash = key.hashCode; |
| + final int fullHash = _hashCode(key); |
| final int hashPattern = _HashBase._hashPattern(fullHash, _hashMask, size); |
| int i = _HashBase._firstProbe(fullHash, sizeMask); |
| int pair = _index[i]; |
| @@ -243,7 +253,7 @@ |
| final int entry = hashPattern ^ pair; |
| if (entry < maxEntries) { |
| final int d = entry << 1; |
| - if (key == _data[d]) { |
| + if (_equals(key, _data[d])) { |
| return _data[d + 1]; |
| } |
| } |
| @@ -263,6 +273,7 @@ |
| bool containsValue(Object value) { |
| for (var v in values) { |
| + // Spec. says this should always use "==", also for identity maps, etc. |
| if (v == value) { |
| return true; |
| } |
| @@ -285,6 +296,28 @@ |
| new _CompactIterable<V>(this, _data, _usedData, -1, 2); |
| } |
| +class _CompactLinkedIdentityHashMap<K, V> |
| + extends _CompactLinkedHashMap<K, V> with _IdenticalAndIdentityHashCode { |
| +} |
| + |
| +class _CompactLinkedCustomHashMap<K, V> |
| + extends _CompactLinkedHashMap<K, V> { |
| + final _equality; |
| + final _hasher; |
| + final _validKey; |
| + |
| + // TODO(koda): Ask gbracha why I cannot have fields _equals/_hashCode. |
| + int _hashCode(e) => _hasher(e); |
| + bool _equals(e1, e2) => _equality(e1, e2); |
| + |
| + bool containsKey(Object o) => _validKey(o) ? super.containsKey(o) : false; |
| + V operator[](Object o) => _validKey(o) ? super[o] : null; |
| + V remove(Object o) => _validKey(o) ? super.remove(o) : null; |
| + |
| + _CompactLinkedCustomHashMap(this._equality, this._hasher, validKey) |
| + : _validKey = (validKey != null) ? validKey : new _TypeTest<E>().test; |
| +} |
| + |
| // Iterates through _data[_offset + _step], _data[_offset + 2*_step], ... |
| // and checks for concurrent modification. |
| class _CompactIterable<E> extends IterableBase<E> { |
| @@ -335,9 +368,9 @@ |
| } |
| // Set implementation, analogous to _CompactLinkedHashMap. |
| -class _CompactLinkedHashSet<K> |
| - extends SetBase<K> with _HashBase |
| - implements LinkedHashSet<K> { |
| +class _CompactLinkedHashSet<E> |
| + extends SetBase<E> with _HashBase, _OperatorEqualsAndHashCode |
| + implements LinkedHashSet<E> { |
| _CompactLinkedHashSet() { |
| assert(_HashBase._UNUSED_PAIR == 0); |
| @@ -377,11 +410,11 @@ |
| } |
| } |
| - bool add(K key) { |
| + bool add(E key) { |
| final int size = _index.length; |
| final int sizeMask = size - 1; |
| final int maxEntries = size >> 1; |
| - final int fullHash = key.hashCode; |
| + final int fullHash = _hashCode(key); |
| final int hashPattern = _HashBase._hashPattern(fullHash, _hashMask, size); |
| int i = _HashBase._firstProbe(fullHash, sizeMask); |
| int firstDeleted = -1; |
| @@ -393,7 +426,7 @@ |
| } |
| } else { |
| final int d = hashPattern ^ pair; |
| - if (d < maxEntries && key == _data[d]) { |
| + if (d < maxEntries && _equals(key, _data[d])) { |
| return false; |
| } |
| } |
| @@ -418,7 +451,7 @@ |
| final int size = _index.length; |
| final int sizeMask = size - 1; |
| final int maxEntries = size >> 1; |
| - final int fullHash = key.hashCode; |
| + final int fullHash = _hashCode(key); |
| final int hashPattern = _HashBase._hashPattern(fullHash, _hashMask, size); |
| int i = _HashBase._firstProbe(fullHash, sizeMask); |
| int pair = _index[i]; |
| @@ -425,7 +458,7 @@ |
| while (pair != _HashBase._UNUSED_PAIR) { |
| if (pair != _HashBase._DELETED_PAIR) { |
| final int d = hashPattern ^ pair; |
| - if (d < maxEntries && key == _data[d]) { |
| + if (d < maxEntries && _equals(key, _data[d])) { |
| return _data[d]; // Note: Must return the existing key. |
| } |
| } |
| @@ -435,7 +468,7 @@ |
| return _data; |
| } |
| - K lookup(Object key) { |
| + E lookup(Object key) { |
| var k = _getKeyOrData(key); |
| return identical(_data, k) ? null : k; |
| } |
| @@ -446,7 +479,7 @@ |
| final int size = _index.length; |
| final int sizeMask = size - 1; |
| final int maxEntries = size >> 1; |
| - final int fullHash = key.hashCode; |
| + final int fullHash = _hashCode(key); |
| final int hashPattern = _HashBase._hashPattern(fullHash, _hashMask, size); |
| int i = _HashBase._firstProbe(fullHash, sizeMask); |
| int pair = _index[i]; |
| @@ -453,7 +486,7 @@ |
| while (pair != _HashBase._UNUSED_PAIR) { |
| if (pair != _HashBase._DELETED_PAIR) { |
| final int d = hashPattern ^ pair; |
| - if (d < maxEntries && key == _data[d]) { |
| + if (d < maxEntries && _equals(key, _data[d])) { |
| _index[i] = _HashBase._DELETED_PAIR; |
| _HashBase._setDeletedAt(_data, d); |
| ++_deletedKeys; |
| @@ -466,8 +499,37 @@ |
| return false; |
| } |
| - Iterator<K> get iterator => |
| - new _CompactIterator<K>(this, _data, _usedData, -1, 1); |
| + Iterator<E> get iterator => |
| + new _CompactIterator<E>(this, _data, _usedData, -1, 1); |
| - Set<K> toSet() => new Set<K>()..addAll(this); |
| + // Returns a set of the same type, although this |
| + // is not required by the spec. (For instance, always using an identity set |
| + // would be technically correct, albeit surprising.) |
| + Set<E> toSet() => new _CompactLinkedHashSet<E>()..addAll(this); |
| } |
| + |
| +class _CompactLinkedIdentityHashSet<E> |
| + extends _CompactLinkedHashSet<E> with _IdenticalAndIdentityHashCode { |
| + Set<E> toSet() => new _CompactLinkedIdentityHashSet<E>()..addAll(this); |
| +} |
| + |
| +class _CompactLinkedCustomHashSet<E> |
| + extends _CompactLinkedHashSet<E> { |
| + final _equality; |
| + final _hasher; |
| + final _validKey; |
| + |
| + int _hashCode(e) => _hasher(e); |
| + bool _equals(e1, e2) => _equality(e1, e2); |
| + |
| + bool contains(Object o) => _validKey(o) ? super.contains(o) : false; |
| + E lookup(Object o) => _validKey(o) ? super.lookup(o) : null; |
| + bool remove(Object o) => _validKey(o) ? super.remove(o) : false; |
| + |
| + _CompactLinkedCustomHashSet(this._equality, this._hasher, validKey) |
| + : _validKey = (validKey != null) ? validKey : new _TypeTest<E>().test; |
| + |
| + Set<E> toSet() => |
| + new _CompactLinkedCustomHashSet<E>(_equality, _hasher, _validKey) |
| + ..addAll(this); |
| +} |