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