Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(106)

Side by Side Diff: sdk/lib/collection/map.dart

Issue 12213010: New implementation of {,Linked}Hash{Set,Map}. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Fixed copyright statments. Created 7 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « sdk/lib/collection/linked_hash_table.dart ('k') | sdk/lib/collection/set.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(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 }
OLDNEW
« no previous file with comments | « sdk/lib/collection/linked_hash_table.dart ('k') | sdk/lib/collection/set.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698