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

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

Issue 12254048: Revert "Reapply "New implementation of {,Linked}Hash{Set,Map}."" (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: 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
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
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
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
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
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 }
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