| OLD | NEW |
| (Empty) | |
| 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
| 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. |
| 4 |
| 5 // TODO(alanknight): Replace with proper identity collection. Issue 4161 |
| 6 library identity_set; |
| 7 |
| 8 import 'dart:collection'; |
| 9 |
| 10 // Hash map implementation with open addressing and quadratic probing. |
| 11 class IdentityMap<K, V> implements HashMap<K, V> { |
| 12 |
| 13 // The [_keys] list contains the keys inserted in the map. |
| 14 // The [_keys] list must be a raw list because it |
| 15 // will contain both elements of type K, and the [_DELETED_KEY] of type |
| 16 // [_DeletedKeySentinel]. |
| 17 // The alternative of declaring the [_keys] list as of type Object |
| 18 // does not work, because the HashSetIterator constructor would fail: |
| 19 // HashSetIterator(HashSet<E> set) |
| 20 // : _nextValidIndex = -1, |
| 21 // _entries = set_._backingMap._keys { |
| 22 // _advance(); |
| 23 // } |
| 24 // With K being type int, for example, it would fail because |
| 25 // List<Object> is not assignable to type List<int> of entries. |
| 26 List _keys; |
| 27 |
| 28 // The values inserted in the map. For a filled entry index in this |
| 29 // list, there is always the corresponding key in the [keys_] list |
| 30 // at the same entry index. |
| 31 List<V> _values; |
| 32 |
| 33 // The load limit is the number of entries we allow until we double |
| 34 // the size of the lists. |
| 35 int _loadLimit; |
| 36 |
| 37 // The current number of entries in the map. Will never be greater |
| 38 // than [_loadLimit]. |
| 39 int _numberOfEntries; |
| 40 |
| 41 // The current number of deleted entries in the map. |
| 42 int _numberOfDeleted; |
| 43 |
| 44 // The sentinel when a key is deleted from the map. |
| 45 static const _DeletedKeySentinel _DELETED_KEY = const _DeletedKeySentinel(); |
| 46 |
| 47 // The initial capacity of a hash map. |
| 48 static const int _INITIAL_CAPACITY = 8; // must be power of 2 |
| 49 |
| 50 IdentityMap() { |
| 51 _numberOfEntries = 0; |
| 52 _numberOfDeleted = 0; |
| 53 _loadLimit = _computeLoadLimit(_INITIAL_CAPACITY); |
| 54 _keys = new List(_INITIAL_CAPACITY); |
| 55 _values = new List<V>(_INITIAL_CAPACITY); |
| 56 } |
| 57 |
| 58 factory IdentityMap.from(Map<K, V> other) { |
| 59 Map<K, V> result = new IdentityMap<K, V>(); |
| 60 other.forEach((K key, V value) { result[key] = value; }); |
| 61 return result; |
| 62 } |
| 63 |
| 64 static int _computeLoadLimit(int capacity) { |
| 65 return (capacity * 3) ~/ 4; |
| 66 } |
| 67 |
| 68 static int _firstProbe(int hashCode, int length) { |
| 69 return hashCode & (length - 1); |
| 70 } |
| 71 |
| 72 static int _nextProbe(int currentProbe, int numberOfProbes, int length) { |
| 73 return (currentProbe + numberOfProbes) & (length - 1); |
| 74 } |
| 75 |
| 76 int _probeForAdding(K key) { |
| 77 if (key == null) throw new ArgumentError(null); |
| 78 int hash = _firstProbe(key.hashCode, _keys.length); |
| 79 int numberOfProbes = 1; |
| 80 int initialHash = hash; |
| 81 // insertionIndex points to a slot where a key was deleted. |
| 82 int insertionIndex = -1; |
| 83 while (true) { |
| 84 // [existingKey] can be either of type [K] or [_DeletedKeySentinel]. |
| 85 Object existingKey = _keys[hash]; |
| 86 if (existingKey == null) { |
| 87 // We are sure the key is not already in the set. |
| 88 // If the current slot is empty and we didn't find any |
| 89 // insertion slot before, return this slot. |
| 90 if (insertionIndex < 0) return hash; |
| 91 // If we did find an insertion slot before, return it. |
| 92 return insertionIndex; |
| 93 } else if (identical(existingKey, key)) { |
| 94 // The key is already in the map. Return its slot. |
| 95 return hash; |
| 96 } else if ((insertionIndex < 0) && |
| 97 (identical(existingKey, _DELETED_KEY))) { |
| 98 // The slot contains a deleted element. Because previous calls to this |
| 99 // method may not have had this slot deleted, we must continue iterate |
| 100 // to find if there is a slot with the given key. |
| 101 insertionIndex = hash; |
| 102 } |
| 103 |
| 104 // We did not find an insertion slot. Look at the next one. |
| 105 hash = _nextProbe(hash, numberOfProbes++, _keys.length); |
| 106 // _ensureCapacity has guaranteed the following cannot happen. |
| 107 // assert(hash != initialHash); |
| 108 } |
| 109 } |
| 110 |
| 111 int _probeForLookup(K key) { |
| 112 if (key == null) throw new ArgumentError(null); |
| 113 int hash = _firstProbe(key.hashCode, _keys.length); |
| 114 int numberOfProbes = 1; |
| 115 int initialHash = hash; |
| 116 while (true) { |
| 117 // [existingKey] can be either of type [K] or [_DeletedKeySentinel]. |
| 118 Object existingKey = _keys[hash]; |
| 119 // If the slot does not contain anything (in particular, it does not |
| 120 // contain a deleted key), we know the key is not in the map. |
| 121 if (existingKey == null) return -1; |
| 122 // The key is in the map, return its index. |
| 123 if (identical(existingKey, key)) return hash; |
| 124 // Go to the next probe. |
| 125 hash = _nextProbe(hash, numberOfProbes++, _keys.length); |
| 126 // _ensureCapacity has guaranteed the following cannot happen. |
| 127 // assert(hash != initialHash); |
| 128 } |
| 129 } |
| 130 |
| 131 void _ensureCapacity() { |
| 132 int newNumberOfEntries = _numberOfEntries + 1; |
| 133 // Test if adding an element will reach the load limit. |
| 134 if (newNumberOfEntries >= _loadLimit) { |
| 135 _grow(_keys.length * 2); |
| 136 return; |
| 137 } |
| 138 |
| 139 // Make sure that we don't have poor performance when a map |
| 140 // contains lots of deleted entries: we _grow if |
| 141 // there are more deleted entried than free entries. |
| 142 int capacity = _keys.length; |
| 143 int numberOfFreeOrDeleted = capacity - newNumberOfEntries; |
| 144 int numberOfFree = numberOfFreeOrDeleted - _numberOfDeleted; |
| 145 // assert(numberOfFree > 0); |
| 146 if (_numberOfDeleted > numberOfFree) { |
| 147 _grow(_keys.length); |
| 148 } |
| 149 } |
| 150 |
| 151 static bool _isPowerOfTwo(int x) { |
| 152 return ((x & (x - 1)) == 0); |
| 153 } |
| 154 |
| 155 void _grow(int newCapacity) { |
| 156 assert(_isPowerOfTwo(newCapacity)); |
| 157 int capacity = _keys.length; |
| 158 _loadLimit = _computeLoadLimit(newCapacity); |
| 159 List oldKeys = _keys; |
| 160 List<V> oldValues = _values; |
| 161 _keys = new List(newCapacity); |
| 162 _values = new List<V>(newCapacity); |
| 163 for (int i = 0; i < capacity; i++) { |
| 164 // [key] can be either of type [K] or [_DeletedKeySentinel]. |
| 165 Object key = oldKeys[i]; |
| 166 // If there is no key, we don't need to deal with the current slot. |
| 167 if (key == null || identical(key, _DELETED_KEY)) { |
| 168 continue; |
| 169 } |
| 170 V value = oldValues[i]; |
| 171 // Insert the {key, value} pair in their new slot. |
| 172 int newIndex = _probeForAdding(key); |
| 173 _keys[newIndex] = key; |
| 174 _values[newIndex] = value; |
| 175 } |
| 176 _numberOfDeleted = 0; |
| 177 } |
| 178 |
| 179 void clear() { |
| 180 _numberOfEntries = 0; |
| 181 _numberOfDeleted = 0; |
| 182 int length = _keys.length; |
| 183 for (int i = 0; i < length; i++) { |
| 184 _keys[i] = null; |
| 185 _values[i] = null; |
| 186 } |
| 187 } |
| 188 |
| 189 void operator []=(K key, V value) { |
| 190 _ensureCapacity(); |
| 191 int index = _probeForAdding(key); |
| 192 if ((_keys[index] == null) || (identical(_keys[index], _DELETED_KEY))) { |
| 193 _numberOfEntries++; |
| 194 } |
| 195 _keys[index] = key; |
| 196 _values[index] = value; |
| 197 } |
| 198 |
| 199 V operator [](K key) { |
| 200 int index = _probeForLookup(key); |
| 201 if (index < 0) return null; |
| 202 return _values[index]; |
| 203 } |
| 204 |
| 205 V putIfAbsent(K key, V ifAbsent()) { |
| 206 int index = _probeForLookup(key); |
| 207 if (index >= 0) return _values[index]; |
| 208 |
| 209 V value = ifAbsent(); |
| 210 this[key] = value; |
| 211 return value; |
| 212 } |
| 213 |
| 214 V remove(K key) { |
| 215 int index = _probeForLookup(key); |
| 216 if (index >= 0) { |
| 217 _numberOfEntries--; |
| 218 V value = _values[index]; |
| 219 _values[index] = null; |
| 220 // Set the key to the sentinel to not break the probing chain. |
| 221 _keys[index] = _DELETED_KEY; |
| 222 _numberOfDeleted++; |
| 223 return value; |
| 224 } |
| 225 return null; |
| 226 } |
| 227 |
| 228 bool get isEmpty { |
| 229 return _numberOfEntries == 0; |
| 230 } |
| 231 |
| 232 int get length { |
| 233 return _numberOfEntries; |
| 234 } |
| 235 |
| 236 void forEach(void f(K key, V value)) { |
| 237 int length = _keys.length; |
| 238 for (int i = 0; i < length; i++) { |
| 239 var key = _keys[i]; |
| 240 if ((key != null) && (!identical(key, _DELETED_KEY))) { |
| 241 f(key, _values[i]); |
| 242 } |
| 243 } |
| 244 } |
| 245 |
| 246 |
| 247 Collection<K> get keys { |
| 248 List<K> list = new List<K>(length); |
| 249 int i = 0; |
| 250 forEach((K key, V value) { |
| 251 list[i++] = key; |
| 252 }); |
| 253 return list; |
| 254 } |
| 255 |
| 256 Collection<V> get values { |
| 257 List<V> list = new List<V>(length); |
| 258 int i = 0; |
| 259 forEach((K key, V value) { |
| 260 list[i++] = value; |
| 261 }); |
| 262 return list; |
| 263 } |
| 264 |
| 265 bool containsKey(K key) { |
| 266 return (_probeForLookup(key) != -1); |
| 267 } |
| 268 |
| 269 bool containsValue(V value) { |
| 270 int length = _values.length; |
| 271 for (int i = 0; i < length; i++) { |
| 272 var key = _keys[i]; |
| 273 if ((key != null) && (!identical(key, _DELETED_KEY))) { |
| 274 if (_values[i] == value) return true; |
| 275 } |
| 276 } |
| 277 return false; |
| 278 } |
| 279 |
| 280 String toString() { |
| 281 return Maps.mapToString(this); |
| 282 } |
| 283 } |
| 284 |
| 285 |
| 286 /** |
| 287 * A singleton sentinel used to represent when a key is deleted from the map. |
| 288 * We can't use [: const Object() :] as a sentinel because it would end up |
| 289 * canonicalized and then we cannot distinguish the deleted key from the |
| 290 * canonicalized [: Object() :]. |
| 291 */ |
| 292 class _DeletedKeySentinel { |
| 293 const _DeletedKeySentinel(); |
| 294 } |
| 295 |
| 296 |
| 297 /** |
| 298 * This class represents a pair of two objects, used by LinkedHashMap |
| 299 * to store a {key, value} in a list. |
| 300 */ |
| 301 class _KeyValuePair<K, V> { |
| 302 _KeyValuePair(this.key, this.value) {} |
| 303 |
| 304 final K key; |
| 305 V value; |
| 306 } |
| 307 |
| OLD | NEW |