OLD | NEW |
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, 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 // TODO(alanknight): Replace with proper identity collection. Issue 4161 | 5 part of dart.collection; |
6 library identity_set; | |
7 | 6 |
8 import 'dart:collection'; | 7 |
| 8 /** |
| 9 * Hash map version of the [Map] interface. A [HashMap] does not |
| 10 * provide any guarantees on the order of keys and values in [keys] |
| 11 * and [values]. |
| 12 */ |
| 13 abstract class HashMap<K, V> extends Map<K, V> { |
| 14 /** |
| 15 * Creates a map with the default implementation. |
| 16 */ |
| 17 factory HashMap() => new _HashMapImpl<K, V>(); |
| 18 |
| 19 /** |
| 20 * Creates a [HashMap] that contains all key value pairs of [other]. |
| 21 */ |
| 22 factory HashMap.from(Map<K, V> other) => new _HashMapImpl<K, V>.from(other); |
| 23 } |
| 24 |
| 25 /** |
| 26 * Hash map version of the [Map] interface that preserves insertion |
| 27 * order. |
| 28 */ |
| 29 abstract class LinkedHashMap<K, V> extends HashMap<K, V> { |
| 30 /** |
| 31 * Creates a map with the default implementation. |
| 32 */ |
| 33 factory LinkedHashMap() => new _LinkedHashMapImpl<K, V>(); |
| 34 |
| 35 /** |
| 36 * Creates a [LinkedHashMap] that contains all key value pairs of [other]. |
| 37 */ |
| 38 factory LinkedHashMap.from(Map<K, V> other) |
| 39 => new _LinkedHashMapImpl<K, V>.from(other); |
| 40 } |
| 41 |
9 | 42 |
10 // Hash map implementation with open addressing and quadratic probing. | 43 // Hash map implementation with open addressing and quadratic probing. |
11 class IdentityMap<K, V> implements HashMap<K, V> { | 44 class _HashMapImpl<K, V> implements HashMap<K, V> { |
12 | 45 |
13 // The [_keys] list contains the keys inserted in the map. | 46 // The [_keys] list contains the keys inserted in the map. |
14 // The [_keys] list must be a raw list because it | 47 // The [_keys] list must be a raw list because it |
15 // will contain both elements of type K, and the [_DELETED_KEY] of type | 48 // will contain both elements of type K, and the [_DELETED_KEY] of type |
16 // [_DeletedKeySentinel]. | 49 // [_DeletedKeySentinel]. |
17 // The alternative of declaring the [_keys] list as of type Object | 50 // The alternative of declaring the [_keys] list as of type Object |
18 // does not work, because the HashSetIterator constructor would fail: | 51 // does not work, because the HashSetIterator constructor would fail: |
19 // HashSetIterator(HashSet<E> set) | 52 // HashSetIterator(HashSet<E> set) |
20 // : _nextValidIndex = -1, | 53 // : _nextValidIndex = -1, |
21 // _entries = set_._backingMap._keys { | 54 // _entries = set_._backingMap._keys { |
(...skipping 18 matching lines...) Expand all Loading... |
40 | 73 |
41 // The current number of deleted entries in the map. | 74 // The current number of deleted entries in the map. |
42 int _numberOfDeleted; | 75 int _numberOfDeleted; |
43 | 76 |
44 // The sentinel when a key is deleted from the map. | 77 // The sentinel when a key is deleted from the map. |
45 static const _DeletedKeySentinel _DELETED_KEY = const _DeletedKeySentinel(); | 78 static const _DeletedKeySentinel _DELETED_KEY = const _DeletedKeySentinel(); |
46 | 79 |
47 // The initial capacity of a hash map. | 80 // The initial capacity of a hash map. |
48 static const int _INITIAL_CAPACITY = 8; // must be power of 2 | 81 static const int _INITIAL_CAPACITY = 8; // must be power of 2 |
49 | 82 |
50 IdentityMap() { | 83 _HashMapImpl() { |
51 _numberOfEntries = 0; | 84 _numberOfEntries = 0; |
52 _numberOfDeleted = 0; | 85 _numberOfDeleted = 0; |
53 _loadLimit = _computeLoadLimit(_INITIAL_CAPACITY); | 86 _loadLimit = _computeLoadLimit(_INITIAL_CAPACITY); |
54 _keys = new List(_INITIAL_CAPACITY); | 87 _keys = new List.fixedLength(_INITIAL_CAPACITY); |
55 _values = new List<V>(_INITIAL_CAPACITY); | 88 _values = new List<V>.fixedLength(_INITIAL_CAPACITY); |
56 } | 89 } |
57 | 90 |
58 factory IdentityMap.from(Map<K, V> other) { | 91 factory _HashMapImpl.from(Map<K, V> other) { |
59 Map<K, V> result = new IdentityMap<K, V>(); | 92 Map<K, V> result = new _HashMapImpl<K, V>(); |
60 other.forEach((K key, V value) { result[key] = value; }); | 93 other.forEach((K key, V value) { result[key] = value; }); |
61 return result; | 94 return result; |
62 } | 95 } |
63 | 96 |
64 static int _computeLoadLimit(int capacity) { | 97 static int _computeLoadLimit(int capacity) { |
65 return (capacity * 3) ~/ 4; | 98 return (capacity * 3) ~/ 4; |
66 } | 99 } |
67 | 100 |
68 static int _firstProbe(int hashCode, int length) { | 101 static int _firstProbe(int hashCode, int length) { |
69 return hashCode & (length - 1); | 102 return hashCode & (length - 1); |
(...skipping 13 matching lines...) Expand all Loading... |
83 while (true) { | 116 while (true) { |
84 // [existingKey] can be either of type [K] or [_DeletedKeySentinel]. | 117 // [existingKey] can be either of type [K] or [_DeletedKeySentinel]. |
85 Object existingKey = _keys[hash]; | 118 Object existingKey = _keys[hash]; |
86 if (existingKey == null) { | 119 if (existingKey == null) { |
87 // We are sure the key is not already in the set. | 120 // We are sure the key is not already in the set. |
88 // If the current slot is empty and we didn't find any | 121 // If the current slot is empty and we didn't find any |
89 // insertion slot before, return this slot. | 122 // insertion slot before, return this slot. |
90 if (insertionIndex < 0) return hash; | 123 if (insertionIndex < 0) return hash; |
91 // If we did find an insertion slot before, return it. | 124 // If we did find an insertion slot before, return it. |
92 return insertionIndex; | 125 return insertionIndex; |
93 } else if (identical(existingKey, key)) { | 126 } else if (existingKey == key) { |
94 // The key is already in the map. Return its slot. | 127 // The key is already in the map. Return its slot. |
95 return hash; | 128 return hash; |
96 } else if ((insertionIndex < 0) && | 129 } else if ((insertionIndex < 0) && |
97 (identical(existingKey, _DELETED_KEY))) { | 130 (identical(existingKey, _DELETED_KEY))) { |
98 // The slot contains a deleted element. Because previous calls to this | 131 // The slot contains a deleted element. Because previous calls to this |
99 // method may not have had this slot deleted, we must continue iterate | 132 // method may not have had this slot deleted, we must continue iterate |
100 // to find if there is a slot with the given key. | 133 // to find if there is a slot with the given key. |
101 insertionIndex = hash; | 134 insertionIndex = hash; |
102 } | 135 } |
103 | 136 |
104 // We did not find an insertion slot. Look at the next one. | 137 // We did not find an insertion slot. Look at the next one. |
105 hash = _nextProbe(hash, numberOfProbes++, _keys.length); | 138 hash = _nextProbe(hash, numberOfProbes++, _keys.length); |
106 // _ensureCapacity has guaranteed the following cannot happen. | 139 // _ensureCapacity has guaranteed the following cannot happen. |
107 // assert(hash != initialHash); | 140 // assert(hash != initialHash); |
108 } | 141 } |
109 } | 142 } |
110 | 143 |
111 int _probeForLookup(K key) { | 144 int _probeForLookup(K key) { |
112 if (key == null) throw new ArgumentError(null); | 145 if (key == null) throw new ArgumentError(null); |
113 int hash = _firstProbe(key.hashCode, _keys.length); | 146 int hash = _firstProbe(key.hashCode, _keys.length); |
114 int numberOfProbes = 1; | 147 int numberOfProbes = 1; |
115 int initialHash = hash; | 148 int initialHash = hash; |
116 while (true) { | 149 while (true) { |
117 // [existingKey] can be either of type [K] or [_DeletedKeySentinel]. | 150 // [existingKey] can be either of type [K] or [_DeletedKeySentinel]. |
118 Object existingKey = _keys[hash]; | 151 Object existingKey = _keys[hash]; |
119 // If the slot does not contain anything (in particular, it does not | 152 // 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. | 153 // contain a deleted key), we know the key is not in the map. |
121 if (existingKey == null) return -1; | 154 if (existingKey == null) return -1; |
122 // The key is in the map, return its index. | 155 // The key is in the map, return its index. |
123 if (identical(existingKey, key)) return hash; | 156 if (existingKey == key) return hash; |
124 // Go to the next probe. | 157 // Go to the next probe. |
125 hash = _nextProbe(hash, numberOfProbes++, _keys.length); | 158 hash = _nextProbe(hash, numberOfProbes++, _keys.length); |
126 // _ensureCapacity has guaranteed the following cannot happen. | 159 // _ensureCapacity has guaranteed the following cannot happen. |
127 // assert(hash != initialHash); | 160 // assert(hash != initialHash); |
128 } | 161 } |
129 } | 162 } |
130 | 163 |
131 void _ensureCapacity() { | 164 void _ensureCapacity() { |
132 int newNumberOfEntries = _numberOfEntries + 1; | 165 int newNumberOfEntries = _numberOfEntries + 1; |
133 // Test if adding an element will reach the load limit. | 166 // Test if adding an element will reach the load limit. |
(...skipping 17 matching lines...) Expand all Loading... |
151 static bool _isPowerOfTwo(int x) { | 184 static bool _isPowerOfTwo(int x) { |
152 return ((x & (x - 1)) == 0); | 185 return ((x & (x - 1)) == 0); |
153 } | 186 } |
154 | 187 |
155 void _grow(int newCapacity) { | 188 void _grow(int newCapacity) { |
156 assert(_isPowerOfTwo(newCapacity)); | 189 assert(_isPowerOfTwo(newCapacity)); |
157 int capacity = _keys.length; | 190 int capacity = _keys.length; |
158 _loadLimit = _computeLoadLimit(newCapacity); | 191 _loadLimit = _computeLoadLimit(newCapacity); |
159 List oldKeys = _keys; | 192 List oldKeys = _keys; |
160 List<V> oldValues = _values; | 193 List<V> oldValues = _values; |
161 _keys = new List(newCapacity); | 194 _keys = new List.fixedLength(newCapacity); |
162 _values = new List<V>(newCapacity); | 195 _values = new List<V>.fixedLength(newCapacity); |
163 for (int i = 0; i < capacity; i++) { | 196 for (int i = 0; i < capacity; i++) { |
164 // [key] can be either of type [K] or [_DeletedKeySentinel]. | 197 // [key] can be either of type [K] or [_DeletedKeySentinel]. |
165 Object key = oldKeys[i]; | 198 Object key = oldKeys[i]; |
166 // If there is no key, we don't need to deal with the current slot. | 199 // If there is no key, we don't need to deal with the current slot. |
167 if (key == null || identical(key, _DELETED_KEY)) { | 200 if (key == null || identical(key, _DELETED_KEY)) { |
168 continue; | 201 continue; |
169 } | 202 } |
170 V value = oldValues[i]; | 203 V value = oldValues[i]; |
171 // Insert the {key, value} pair in their new slot. | 204 // Insert the {key, value} pair in their new slot. |
172 int newIndex = _probeForAdding(key); | 205 int newIndex = _probeForAdding(key); |
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
227 | 260 |
228 bool get isEmpty { | 261 bool get isEmpty { |
229 return _numberOfEntries == 0; | 262 return _numberOfEntries == 0; |
230 } | 263 } |
231 | 264 |
232 int get length { | 265 int get length { |
233 return _numberOfEntries; | 266 return _numberOfEntries; |
234 } | 267 } |
235 | 268 |
236 void forEach(void f(K key, V value)) { | 269 void forEach(void f(K key, V value)) { |
237 int length = _keys.length; | 270 Iterator<int> it = new _HashMapImplIndexIterator(this); |
238 for (int i = 0; i < length; i++) { | 271 while (it.moveNext()) { |
239 var key = _keys[i]; | 272 f(_keys[it.current], _values[it.current]); |
240 if ((key != null) && (!identical(key, _DELETED_KEY))) { | |
241 f(key, _values[i]); | |
242 } | |
243 } | 273 } |
244 } | 274 } |
245 | 275 |
| 276 Iterable<K> get keys => new _HashMapImplKeyIterable<K>(this); |
246 | 277 |
247 Collection<K> get keys { | 278 Iterable<V> get values => new _HashMapImplValueIterable<V>(this); |
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 | 279 |
265 bool containsKey(K key) { | 280 bool containsKey(K key) { |
266 return (_probeForLookup(key) != -1); | 281 return (_probeForLookup(key) != -1); |
267 } | 282 } |
268 | 283 |
269 bool containsValue(V value) { | 284 bool containsValue(V value) => values.contains(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 | 285 |
280 String toString() { | 286 String toString() { |
281 return Maps.mapToString(this); | 287 return Maps.mapToString(this); |
282 } | 288 } |
283 } | 289 } |
284 | 290 |
| 291 class _HashMapImplKeyIterable<E> extends Iterable<E> { |
| 292 final _HashMapImpl _map; |
| 293 _HashMapImplKeyIterable(this._map); |
| 294 |
| 295 Iterator<E> get iterator => new _HashMapImplKeyIterator<E>(_map); |
| 296 } |
| 297 |
| 298 class _HashMapImplValueIterable<E> extends Iterable<E> { |
| 299 final _HashMapImpl _map; |
| 300 _HashMapImplValueIterable(this._map); |
| 301 |
| 302 Iterator<E> get iterator => new _HashMapImplValueIterator<E>(_map); |
| 303 } |
| 304 |
| 305 abstract class _HashMapImplIterator<E> implements Iterator<E> { |
| 306 final _HashMapImpl _map; |
| 307 int _index = -1; |
| 308 E _current; |
| 309 |
| 310 _HashMapImplIterator(this._map); |
| 311 |
| 312 E _computeCurrentFromIndex(int index, List keys, List values); |
| 313 |
| 314 bool moveNext() { |
| 315 int length = _map._keys.length; |
| 316 int newIndex = _index + 1; |
| 317 while (newIndex < length) { |
| 318 var key = _map._keys[newIndex]; |
| 319 if ((key != null) && (!identical(key, _HashMapImpl._DELETED_KEY))) { |
| 320 _current = _computeCurrentFromIndex(newIndex, _map._keys, _map._values); |
| 321 _index = newIndex; |
| 322 return true; |
| 323 } |
| 324 newIndex++; |
| 325 } |
| 326 _index = length; |
| 327 _current = null; |
| 328 return false; |
| 329 } |
| 330 |
| 331 E get current => _current; |
| 332 } |
| 333 |
| 334 class _HashMapImplKeyIterator<E> extends _HashMapImplIterator<E> { |
| 335 _HashMapImplKeyIterator(_HashMapImpl map) : super(map); |
| 336 |
| 337 E _computeCurrentFromIndex(int index, List keys, List values) { |
| 338 return keys[index]; |
| 339 } |
| 340 } |
| 341 |
| 342 class _HashMapImplValueIterator<E> extends _HashMapImplIterator<E> { |
| 343 _HashMapImplValueIterator(_HashMapImpl map) : super(map); |
| 344 |
| 345 E _computeCurrentFromIndex(int index, List keys, List values) { |
| 346 return values[index]; |
| 347 } |
| 348 } |
| 349 |
| 350 class _HashMapImplIndexIterator extends _HashMapImplIterator<int> { |
| 351 _HashMapImplIndexIterator(_HashMapImpl map) : super(map); |
| 352 |
| 353 int _computeCurrentFromIndex(int index, List keys, List values) { |
| 354 return index; |
| 355 } |
| 356 } |
285 | 357 |
286 /** | 358 /** |
287 * A singleton sentinel used to represent when a key is deleted from the map. | 359 * 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 | 360 * 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 | 361 * canonicalized and then we cannot distinguish the deleted key from the |
290 * canonicalized [: Object() :]. | 362 * canonicalized [: Object() :]. |
291 */ | 363 */ |
292 class _DeletedKeySentinel { | 364 class _DeletedKeySentinel { |
293 const _DeletedKeySentinel(); | 365 const _DeletedKeySentinel(); |
294 } | 366 } |
295 | 367 |
296 | 368 |
297 /** | 369 /** |
298 * This class represents a pair of two objects, used by LinkedHashMap | 370 * This class represents a pair of two objects, used by LinkedHashMap |
299 * to store a {key, value} in a list. | 371 * to store a {key, value} in a list. |
300 */ | 372 */ |
301 class _KeyValuePair<K, V> { | 373 class _KeyValuePair<K, V> { |
302 _KeyValuePair(this.key, this.value) {} | 374 _KeyValuePair(this.key, this.value) {} |
303 | 375 |
304 final K key; | 376 final K key; |
305 V value; | 377 V value; |
306 } | 378 } |
| 379 |
| 380 /** |
| 381 * A LinkedHashMap is a hash map that preserves the insertion order |
| 382 * when iterating over the keys or the values. Updating the value of a |
| 383 * key does not change the order. |
| 384 */ |
| 385 class _LinkedHashMapImpl<K, V> implements LinkedHashMap<K, V> { |
| 386 DoubleLinkedQueue<_KeyValuePair<K, V>> _list; |
| 387 HashMap<K, DoubleLinkedQueueEntry<_KeyValuePair<K, V>>> _map; |
| 388 |
| 389 _LinkedHashMapImpl() { |
| 390 _map = new HashMap<K, DoubleLinkedQueueEntry<_KeyValuePair<K, V>>>(); |
| 391 _list = new DoubleLinkedQueue<_KeyValuePair<K, V>>(); |
| 392 } |
| 393 |
| 394 factory _LinkedHashMapImpl.from(Map<K, V> other) { |
| 395 Map<K, V> result = new _LinkedHashMapImpl<K, V>(); |
| 396 other.forEach((K key, V value) { result[key] = value; }); |
| 397 return result; |
| 398 } |
| 399 |
| 400 void operator []=(K key, V value) { |
| 401 if (_map.containsKey(key)) { |
| 402 _map[key].element.value = value; |
| 403 } else { |
| 404 _list.addLast(new _KeyValuePair<K, V>(key, value)); |
| 405 _map[key] = _list.lastEntry(); |
| 406 } |
| 407 } |
| 408 |
| 409 V operator [](K key) { |
| 410 DoubleLinkedQueueEntry<_KeyValuePair<K, V>> entry = _map[key]; |
| 411 if (entry == null) return null; |
| 412 return entry.element.value; |
| 413 } |
| 414 |
| 415 V remove(K key) { |
| 416 DoubleLinkedQueueEntry<_KeyValuePair<K, V>> entry = _map.remove(key); |
| 417 if (entry == null) return null; |
| 418 entry.remove(); |
| 419 return entry.element.value; |
| 420 } |
| 421 |
| 422 V putIfAbsent(K key, V ifAbsent()) { |
| 423 V value = this[key]; |
| 424 if ((this[key] == null) && !(containsKey(key))) { |
| 425 value = ifAbsent(); |
| 426 this[key] = value; |
| 427 } |
| 428 return value; |
| 429 } |
| 430 |
| 431 Iterable<K> get keys { |
| 432 return new MappedIterable<_KeyValuePair<K, V>, K>( |
| 433 _list, (_KeyValuePair<K, V> entry) => entry.key); |
| 434 } |
| 435 |
| 436 |
| 437 Iterable<V> get values { |
| 438 return new MappedIterable<_KeyValuePair<K, V>, V>( |
| 439 _list, (_KeyValuePair<K, V> entry) => entry.value); |
| 440 } |
| 441 |
| 442 void forEach(void f(K key, V value)) { |
| 443 _list.forEach((_KeyValuePair<K, V> entry) { |
| 444 f(entry.key, entry.value); |
| 445 }); |
| 446 } |
| 447 |
| 448 bool containsKey(K key) { |
| 449 return _map.containsKey(key); |
| 450 } |
| 451 |
| 452 bool containsValue(V value) { |
| 453 return _list.any((_KeyValuePair<K, V> entry) { |
| 454 return (entry.value == value); |
| 455 }); |
| 456 } |
| 457 |
| 458 int get length { |
| 459 return _map.length; |
| 460 } |
| 461 |
| 462 bool get isEmpty { |
| 463 return length == 0; |
| 464 } |
| 465 |
| 466 void clear() { |
| 467 _map.clear(); |
| 468 _list.clear(); |
| 469 } |
| 470 |
| 471 String toString() { |
| 472 return Maps.mapToString(this); |
| 473 } |
| 474 } |
OLD | NEW |