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

Side by Side Diff: runtime/lib/collection_patch.dart

Issue 23056002: Convert HashMap and LinkedHashMap to closed addressing hash tables. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 7 years, 4 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 | « no previous file | sdk/lib/json/json.dart » ('j') | sdk/lib/json/json.dart » ('J')
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2013, 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 patch class HashMap<K, V> { 5 patch class HashMap<K, V> {
Søren Gjesse 2013/08/14 07:45:07 Base class for HashMap and LinkedHashMap with comm
Lasse Reichstein Nielsen 2013/08/14 08:38:34 I would love to, but can I do that in a patch file
6 final _HashMapTable<K, V> _hashTable = new _HashMapTable<K, V>(); 6 static const int _INITIAL_CAPACITY = 8;
7 7 static const int _MODIFICATION_COUNT_MASK = 0x3fffffff;
8 /* patch */ HashMap() { 8
9 _hashTable._container = this; 9 int _elementCount = 0;
10 } 10 List<_HashMapEntry> _buckets = new List(_INITIAL_CAPACITY);
11 int _modificationCount = 0;
12
13 /* patch */ HashMap();
14
15 /* patch */ int get length => _elementCount;
16 /* patch */ bool get isEmpty => _elementCount == 0;
17 /* patch */ bool get isNotEmpty => _elementCount != 0;
18
19 /* patch */ Iterable<K> get keys => new _HashMapKeyIterable<K>(this);
20 /* patch */ Iterable<V> get values => new _HashMapValueIterable<V>(this);
11 21
12 /* patch */ bool containsKey(Object key) { 22 /* patch */ bool containsKey(Object key) {
Søren Gjesse 2013/08/14 07:45:07 Maybe have a method (_bucketHead?) for int hashCo
Lasse Reichstein Nielsen 2013/08/14 08:38:34 In some cases the index and hashCode are reused (a
13 return _hashTable._get(key) >= 0; 23 int hashCode = key.hashCode;
24 List buckets = _buckets;
Søren Gjesse 2013/08/14 07:45:07 Why the local buckets in all methods?
Lasse Reichstein Nielsen 2013/08/14 08:38:34 Probably an attempt to help the compiler recognize
25 int index = hashCode & (buckets.length - 1);
26 _HashMapEntry entry = buckets[index];
27 while (entry != null) {
28 if (hashCode == entry.hashCode && entry.key == key) return true;
29 entry = entry.next;
30 }
31 return false;
14 } 32 }
15 33
16 /* patch */ bool containsValue(Object value) { 34 /* patch */ bool containsValue(Object value) {
17 List table = _hashTable._table; 35 List buckets = _buckets;
18 int entrySize = _hashTable._entrySize; 36 int length = buckets.length;
19 for (int offset = 0; offset < table.length; offset += entrySize) { 37 for (int i = 0; i < length; i++) {
20 if (!_hashTable._isFree(table[offset]) && 38 _HashMapEntry entry = buckets[i];
21 _hashTable._value(offset) == value) { 39 while (entry != null) {
22 return true; 40 if (entry.value == value) return true;
41 entry = entry.next;
23 } 42 }
24 } 43 }
25 return false; 44 return false;
26 } 45 }
27 46
47 /* patch */ V operator[](Object key) {
48 int hashCode = key.hashCode;
49 List buckets = _buckets;
50 int index = hashCode & (buckets.length - 1);
51 _HashMapEntry entry = buckets[index];
52 while (entry != null) {
53 if (hashCode == entry.hashCode && entry.key == key) {
54 return entry.value;
55 }
56 entry = entry.next;
57 }
58 return null;
59 }
60
61 /* patch */ void operator []=(K key, V value) {
62 int hashCode = key.hashCode;
63 List buckets = _buckets;
64 int length = buckets.length;
65 int index = hashCode & (length - 1);
66 _HashMapEntry entry = buckets[index];
67 while (entry != null) {
68 if (hashCode == entry.hashCode && entry.key == key) {
69 entry.value = value;
70 return;
71 }
72 entry = entry.next;
73 }
74 _addEntry(buckets, index, length, key, value, hashCode);
75 }
76
77 /* patch */ V putIfAbsent(K key, V ifAbsent()) {
78 int hashCode = key.hashCode;
79 List buckets = _buckets;
80 int length = buckets.length;
81 int index = hashCode & (length - 1);
82 _HashMapEntry entry = buckets[index];
83 while (entry != null) {
84 if (hashCode == entry.hashCode && entry.key == key) {
85 return entry.value;
86 }
87 entry = entry.next;
88 }
89 int stamp = _modificationCount;
90 V value = ifAbsent();
91 if (stamp == _modificationCount) {
92 _addEntry(buckets, index, length, key, value, hashCode);
93 } else {
94 this[key] = value;
95 }
96 return value;
97 }
98
28 /* patch */ void addAll(Map<K, V> other) { 99 /* patch */ void addAll(Map<K, V> other) {
29 other.forEach((K key, V value) { 100 other.forEach((K key, V value) {
30 int offset = _hashTable._put(key); 101 this[key] = value;
31 _hashTable._setValue(offset, value);
32 _hashTable._checkCapacity();
33 }); 102 });
34 } 103 }
35 104
36 /* patch */ V operator [](Object key) { 105 /* patch */ void forEach(void action(K key, V value)) {
37 int offset = _hashTable._get(key); 106 int stamp = _modificationCount;
38 if (offset >= 0) return _hashTable._value(offset); 107 List buckets = _buckets;
108 int length = buckets.length;
109 for (int i = 0; i < length; i++) {
110 _HashMapEntry entry = buckets[i];
111 while (entry != null) {
112 action(entry.key, entry.value);
113 if (stamp != _modificationCount) {
114 throw new ConcurrentModificationError(this);
115 }
116 entry = entry.next;
117 }
118 }
119 }
120
121 /* patch */ V remove(Object key) {
122 int hashCode = key.hashCode;
123 List buckets = _buckets;
124 int index = hashCode & (buckets.length - 1);
125 _HashMapEntry entry = buckets[index];
126 _HashMapEntry previous = null;
127 while (entry != null) {
128 _HashMapEntry next = entry.next;
129 if (hashCode == entry.hashCode && entry.key == key) {
130 if (previous == null) {
131 buckets[index] = next;
132 } else {
133 previous.next = next;
134 }
135 _elementCount--;
136 _modificationCount =
137 (_modificationCount + 1) & _MODIFICATION_COUNT_MASK;
138 return entry.value;
139 }
140 previous = entry;
141 entry = next;
142 }
39 return null; 143 return null;
40 } 144 }
41 145
42 /* patch */ void operator []=(K key, V value) {
43 int offset = _hashTable._put(key);
44 _hashTable._setValue(offset, value);
45 _hashTable._checkCapacity();
46 }
47
48 /* patch */ V putIfAbsent(K key, V ifAbsent()) {
49 int offset = _hashTable._probeForAdd(_hashTable._hashCodeOf(key), key);
50 Object entry = _hashTable._table[offset];
51 if (!_hashTable._isFree(entry)) {
52 return _hashTable._value(offset);
53 }
54 int modificationCount = _hashTable._modificationCount;
55 V value = ifAbsent();
56 if (modificationCount == _hashTable._modificationCount) {
57 _hashTable._setKey(offset, key);
58 _hashTable._setValue(offset, value);
59 if (entry == null) {
60 _hashTable._entryCount++;
61 _hashTable._checkCapacity();
62 } else {
63 assert(identical(entry, _TOMBSTONE));
64 _hashTable._deletedCount--;
65 }
66 _hashTable._recordModification();
67 } else {
68 // The table might have changed, so we can't trust [offset] any more.
69 // Do another lookup before setting the value.
70 offset = _hashTable._put(key);
71 _hashTable._setValue(offset, value);
72 _hashTable._checkCapacity();
73 }
74 return value;
75 }
76
77 /* patch */ V remove(Object key) {
78 int offset = _hashTable._remove(key);
79 if (offset < 0) return null;
80 V oldValue = _hashTable._value(offset);
81 _hashTable._setValue(offset, null);
82 _hashTable._checkCapacity();
83 return oldValue;
84 }
85
86 /* patch */ void clear() { 146 /* patch */ void clear() {
87 _hashTable._clear(); 147 _elementCount = 0;
88 } 148 _buckets = new List(_INITIAL_CAPACITY);
89 149 _modificationCount = (_modificationCount + 1) & _MODIFICATION_COUNT_MASK;
Søren Gjesse 2013/08/14 07:45:07 method for updating the modification count (duplic
Lasse Reichstein Nielsen 2013/08/14 08:38:34 I guess it's inlined for performance (because we c
90 /* patch */ void forEach(void action(K key, V value)) { 150 }
91 int modificationCount = _hashTable._modificationCount; 151
92 List table = _hashTable._table; 152 void _addEntry(List buckets, int index, int length,
93 int entrySize = _hashTable._entrySize; 153 K key, V value, int hashCode) {
94 for (int offset = 0; offset < table.length; offset += entrySize) { 154 _HashMapEntry entry =
95 Object entry = table[offset]; 155 new _HashMapEntry(key, value, hashCode, buckets[index]);
96 if (!_hashTable._isFree(entry)) { 156 buckets[index] = entry;
97 K key = identical(entry, _NULL) ? null : entry; 157 int newElements = _elementCount + 1;
Søren Gjesse 2013/08/14 07:45:07 Why the newElements local?
Lasse Reichstein Nielsen 2013/08/14 08:38:34 Probably for optimization, instead of risking read
98 V value = _hashTable._value(offset); 158 _elementCount = newElements;
99 action(key, value); 159 // If we end up with more than 75% non-empty entries, we
100 _hashTable._checkModification(modificationCount); 160 // resize the backing store.
101 } 161 if ((newElements << 2) > ((length << 1) + length)) _resize();
102 } 162 _modificationCount = (_modificationCount + 1) & _MODIFICATION_COUNT_MASK;
103 } 163 }
104 164
105 /* patch */ Iterable<K> get keys => new _HashTableKeyIterable<K>(_hashTable); 165 void _resize() {
106 /* patch */ Iterable<V> get values => 166 List oldBuckets = _buckets;
107 new _HashTableValueIterable<V>(_hashTable, _HashMapTable._VALUE_INDEX); 167 int oldLength = oldBuckets.length;
108 168 int newLength = oldLength << 1;
109 /* patch */ int get length => _hashTable._elementCount; 169 List newBuckets = new List(newLength);
110 170 for (int i = 0; i < oldLength; i++) {
111 /* patch */ bool get isEmpty => _hashTable._elementCount == 0; 171 _HashMapEntry entry = oldBuckets[i];
112 172 while (entry != null) {
113 /* patch */ bool get isNotEmpty => !isEmpty; 173 _HashMapEntry next = entry.next;
174 int hashCode = entry.hashCode;
175 int index = hashCode & (newLength - 1);
176 entry.next = newBuckets[index];
177 newBuckets[index] = entry;
178 entry = next;
179 }
180 }
181 _buckets = newBuckets;
182 }
183 }
184
185 class _HashMapEntry {
186 final key;
187 var value;
188 final int hashCode;
189 _HashMapEntry next;
190 _HashMapEntry(this.key, this.value, this.hashCode, this.next);
191 }
192
193 abstract class _HashMapIterable<E> extends IterableBase<E> {
194 final HashMap _map;
195 _HashMapIterable(this._map);
196 int get length => _map.length;
197 bool get isEmpty => _map.isEmpty;
198 bool get isNotEmpty => _map.isNotEmpty;
199 }
200
201 class _HashMapKeyIterable<K> extends _HashMapIterable<K> {
202 _HashMapKeyIterable(HashMap map) : super(map);
203 Iterator<K> get iterator => new _HashMapKeyIterator<K>(_map);
204 bool contains(K key) => _map.containsKey(key);
205 void forEach(void action(K key)) {
206 _map.forEach((K key, _) {
207 action(key);
208 });
209 }
210 }
211
212 class _HashMapValueIterable<V> extends _HashMapIterable<V> {
213 _HashMapValueIterable(HashMap map) : super(map);
214 Iterator<V> get iterator => new _HashMapValueIterator<V>(_map);
215 bool contains(V value) => _map.containsValue(value);
216 void forEach(void action(V value)) {
217 _map.forEach((_, V value) {
218 action(value);
219 });
220 }
221 }
222
223 abstract class _HashMapIterator<E> implements Iterator<E> {
224 final HashMap _map;
225 final int _stamp;
226
227 int _index = 0;
228 _HashMapEntry _entry;
229
230 _HashMapIterator(HashMap map)
231 : _map = map, _stamp = map._modificationCount;
232
233 bool moveNext() {
234 if (_stamp != _map._modificationCount) {
235 throw new ConcurrentModificationError(_map);
236 }
237 _HashMapEntry entry = _entry;
238 if (entry != null) {
239 _HashMapEntry next = entry.next;
240 if (next != null) {
241 _entry = next;
242 return true;
243 }
244 _entry = null;
245 }
246 List buckets = _map._buckets;
247 int length = buckets.length;
248 for (int i = _index; i < length; i++) {
249 entry = buckets[i];
250 if (entry != null) {
251 _index = i + 1;
252 _entry = entry;
253 return true;
254 }
255 }
256 _index = length;
257 return false;
258 }
259 }
260
261 class _HashMapKeyIterator<K> extends _HashMapIterator<K> {
262 _HashMapKeyIterator(HashMap map) : super(map);
263 K get current {
264 _HashMapEntry entry = _entry;
265 return (entry == null) ? null : entry.key;
266 }
267 }
268
269 class _HashMapValueIterator<V> extends _HashMapIterator<V> {
270 _HashMapValueIterator(HashMap map) : super(map);
271 V get current {
272 _HashMapEntry entry = _entry;
273 return (entry == null) ? null : entry.value;
274 }
114 } 275 }
115 276
116 patch class HashSet<E> { 277 patch class HashSet<E> {
117 static const int _INITIAL_CAPACITY = 8; 278 static const int _INITIAL_CAPACITY = 8;
118 final _HashTable<E> _table; 279 final _HashTable<E> _table;
119 280
120 /* patch */ HashSet() : _table = new _HashTable(_INITIAL_CAPACITY) { 281 /* patch */ HashSet() : _table = new _HashTable(_INITIAL_CAPACITY) {
121 _table._container = this; 282 _table._container = this;
122 } 283 }
123 284
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after
186 347
187 /* patch */ void retainWhere(bool test(E element)) { 348 /* patch */ void retainWhere(bool test(E element)) {
188 _filterWhere(test, false); 349 _filterWhere(test, false);
189 } 350 }
190 351
191 /* patch */ void clear() { 352 /* patch */ void clear() {
192 _table._clear(); 353 _table._clear();
193 } 354 }
194 } 355 }
195 356
357 class _LinkedHashMapEntry extends _HashMapEntry {
358 var _nextEntry;
Søren Gjesse 2013/08/14 07:45:07 _LinkedHashMapEntry instead of var here?
Lasse Reichstein Nielsen 2013/08/14 08:38:34 No, it may also point to LinkedHashMap. I can't pu
359 var _previousEntry;
360 _LinkedHashMapEntry(key, value, int hashCode, _LinkedHashMapEntry next,
361 this._previousEntry, this._nextEntry)
362 : super(key, value, hashCode, next) {
363 _previousEntry._nextEntry = this;
364 _nextEntry._previousEntry = this;
365 }
366 }
367
368 class _LinkedHashMapKeyIterable<K> extends IterableBase<K> {
369 LinkedHashMap<K, dynamic> _map;
370 _LinkedHashMapKeyIterable(this._map);
371 Iterator<K> get iterator => new _LinkedHashMapKeyIterator<K>(_map);
372 bool contains(K key) => _map.containsKey(key);
373 bool get isEmpty => _map.isEmpty;
374 bool get isNotEmpty => _map.isNotEmpty;
375 int get length => _map.length;
376 }
377
378 class _LinkedHashMapValueIterable<V> extends IterableBase<V> {
379 LinkedHashMap<dynamic, V> _map;
380 _LinkedHashMapValueIterable(this._map);
381 Iterator<K> get iterator => new _LinkedHashMapValueIterator<V>(_map);
382 bool contains(V value) => _map.containsValue(value);
383 bool get isEmpty => _map.isEmpty;
384 bool get isNotEmpty => _map.isNotEmpty;
385 int get length => _map.length;
386 }
387
388 abstract class _LinkedHashMapIterator<T> implements Iterator<T> {
389 final _LinkedHashMap _map;
390 var _next;
391 T _current;
392 int _modificationCount;
393 _LinkedHashMapIterator(_LinkedHashMap map)
394 : _map = map,
395 _current = null,
396 _next = map._nextEntry,
397 _modificationCount = map._modificationCount;
398
399 bool moveNext() {
400 if (_modificationCount != _map._modificationCount) {
401 throw new ConcurrentModificationError(_map);
402 }
403 if (identical(_map, _next)) {
404 _current = null;
405 return false;
406 }
407 _LinkedHashMapEntry entry = _next;
408 _next = entry._nextEntry;
409 _current = _getValue(entry);
410 return true;
411 }
412
413 T _getValue(_LinkedHashMapEntry entry);
414
415 T get current => _current;
416 }
417
418 class _LinkedHashMapKeyIterator<K> extends _LinkedHashMapIterator<K> {
419 _LinkedHashMapKeyIterator(_LinkedHashMap map) : super(map);
420 K _getValue(_LinkedHashMapEntry entry) => entry.key;
421 }
422
423 class _LinkedHashMapValueIterator<V> extends _LinkedHashMapIterator<V> {
424 _LinkedHashMapValueIterator(_LinkedHashMap map) : super(map);
425 V _getValue(_LinkedHashMapEntry entry) => entry.value;
426 }
427
428
196 /** 429 /**
197 * A hash-based map that iterates keys and values in key insertion order. 430 * A hash-based map that iterates keys and values in key insertion order.
198 */ 431 */
199 patch class LinkedHashMap<K, V> { 432 patch class LinkedHashMap<K, V> {
200 final _LinkedHashMapTable _hashTable; 433 static const int _INITIAL_CAPACITY = 8;
201 434 static const int _MODIFICATION_COUNT_MASK = 0x3fffffff;
202 /* patch */ LinkedHashMap() : _hashTable = new _LinkedHashMapTable<K, V>() { 435
203 _hashTable._container = this; 436 int _elementCount = 0;
204 } 437 List<_HashMapEntry> _buckets = new List(_INITIAL_CAPACITY);
438 int _modificationCount = 0;
439
440 var _nextEntry;
Søren Gjesse 2013/08/14 07:45:07 _LinkedHashMapEntry instead of var here?
Søren Gjesse 2013/08/14 07:45:07 _head and _tail instead of _nextEntry and _previou
Lasse Reichstein Nielsen 2013/08/14 08:38:34 It may also point to LinkedHashMap.
Lasse Reichstein Nielsen 2013/08/14 08:38:34 They have the same name as the fields on _LinkedHa
441 var _previousEntry;
442
443 /* patch */ LinkedHashMap() {
444 _nextEntry = _previousEntry = this;
Søren Gjesse 2013/08/14 07:45:07 Now I see the reason for var and the naming above.
Lasse Reichstein Nielsen 2013/08/14 08:38:34 Ack, will comment.
445 }
446
447 /* patch */ int get length => _elementCount;
448 /* patch */ bool get isEmpty => _elementCount == 0;
449 /* patch */ bool get isNotEmpty => _elementCount != 0;
450
451 /* patch */ Iterable<K> get keys => new _LinkedHashMapKeyIterable<K>(this);
452 /* patch */ Iterable<V> get values => new _LinkedHashMapValueIterable<V>(this) ;
205 453
206 /* patch */ bool containsKey(Object key) { 454 /* patch */ bool containsKey(Object key) {
207 return _hashTable._get(key) >= 0; 455 int hashCode = key.hashCode;
456 List buckets = _buckets;
457 int index = hashCode & (buckets.length - 1);
458 _HashMapEntry entry = buckets[index];
459 while (entry != null) {
460 if (hashCode == entry.hashCode && entry.key == key) return true;
461 entry = entry.next;
462 }
463 return false;
208 } 464 }
209 465
210 /* patch */ bool containsValue(Object value) { 466 /* patch */ bool containsValue(Object value) {
211 int modificationCount = _hashTable._modificationCount; 467 var cursor = _nextEntry;
212 for (int offset = _hashTable._next(_LinkedHashTable._HEAD_OFFSET); 468 int modificationCount = _modificationCount;
213 offset != _LinkedHashTable._HEAD_OFFSET; 469 while (!identical(cursor, this)) {
214 offset = _hashTable._next(offset)) { 470 _HashMapEntry entry = cursor;
215 if (_hashTable._value(offset) == value) { 471 if (entry.value == value) return true;
216 return true; 472 cursor = cursor._nextEntry;
217 }
218 // The == call may modify the table.
219 _hashTable._checkModification(modificationCount);
220 } 473 }
221 return false; 474 return false;
222 } 475 }
223 476
477 /* patch */ V operator[](Object key) {
478 int hashCode = key.hashCode;
479 List buckets = _buckets;
480 int index = hashCode & (buckets.length - 1);
481 _HashMapEntry entry = buckets[index];
482 while (entry != null) {
483 if (hashCode == entry.hashCode && entry.key == key) {
484 return entry.value;
485 }
486 entry = entry.next;
487 }
488 return null;
489 }
490
491 /* patch */ void operator []=(K key, V value) {
492 int hashCode = key.hashCode;
493 List buckets = _buckets;
494 int length = buckets.length;
495 int index = hashCode & (length - 1);
496 _HashMapEntry entry = buckets[index];
497 while (entry != null) {
498 if (hashCode == entry.hashCode && entry.key == key) {
499 entry.value = value;
500 return;
501 }
502 entry = entry.next;
503 }
504 _addEntry(buckets, index, length, key, value, hashCode);
505 }
506
507 /* patch */ V putIfAbsent(K key, V ifAbsent()) {
508 int hashCode = key.hashCode;
509 List buckets = _buckets;
510 int length = buckets.length;
511 int index = hashCode & (length - 1);
512 _HashMapEntry entry = buckets[index];
513 while (entry != null) {
514 if (hashCode == entry.hashCode && entry.key == key) {
515 return entry.value;
516 }
517 entry = entry.next;
518 }
519 int stamp = _modificationCount;
520 V value = ifAbsent();
521 if (stamp == _modificationCount) {
522 _addEntry(buckets, index, length, key, value, hashCode);
523 } else {
524 this[key] = value;
525 }
526 return value;
527 }
528
224 /* patch */ void addAll(Map<K, V> other) { 529 /* patch */ void addAll(Map<K, V> other) {
225 other.forEach((K key, V value) { 530 other.forEach((K key, V value) {
226 int offset = _hashTable._put(key); 531 this[key] = value;
227 _hashTable._setValue(offset, value);
228 _hashTable._checkCapacity();
229 }); 532 });
230 } 533 }
231 534
232 /* patch */ V operator [](Object key) { 535 /* patch */ void forEach(void action(K key, V value)) {
233 int offset = _hashTable._get(key); 536 int stamp = _modificationCount;
234 if (offset >= 0) return _hashTable._value(offset); 537 var cursor = _nextEntry;
538 while (!identical(cursor, this)) {
539 _HashMapEntry entry = cursor;
540 action(entry.key, entry.value);
541 if (stamp != _modificationCount) {
542 throw new ConcurrentModificationError(this);
543 }
544 cursor = cursor._nextEntry;
545 }
546 }
547
548 /* patch */ V remove(Object key) {
549 int hashCode = key.hashCode;
550 List buckets = _buckets;
551 int index = hashCode & (buckets.length - 1);
552 _LinkedHashMapEntry entry = buckets[index];
553 _HashMapEntry previous = null;
554 while (entry != null) {
555 _HashMapEntry next = entry.next;
556 if (hashCode == entry.hashCode && entry.key == key) {
557 if (previous == null) {
558 buckets[index] = next;
559 } else {
560 previous.next = next;
561 }
562 entry._previousEntry._nextEntry = entry._nextEntry;
563 entry._nextEntry._previousEntry = entry._previousEntry;
564 entry._nextEntry = entry._previousEntry = null;
565 _elementCount--;
566 _modificationCount =
567 (_modificationCount + 1) & _MODIFICATION_COUNT_MASK;
568 return entry.value;
569 }
570 previous = entry;
571 entry = next;
572 }
235 return null; 573 return null;
236 } 574 }
237 575
238 /* patch */ void operator []=(K key, V value) {
239 int offset = _hashTable._put(key);
240 _hashTable._setValue(offset, value);
241 _hashTable._checkCapacity();
242 }
243
244 /* patch */ V putIfAbsent(K key, V ifAbsent()) {
245 int offset = _hashTable._probeForAdd(_hashTable._hashCodeOf(key), key);
246 Object entry = _hashTable._table[offset];
247 if (!_hashTable._isFree(entry)) {
248 return _hashTable._value(offset);
249 }
250 int modificationCount = _hashTable._modificationCount;
251 V value = ifAbsent();
252 if (modificationCount == _hashTable._modificationCount) {
253 _hashTable._setKey(offset, key);
254 _hashTable._setValue(offset, value);
255 _hashTable._linkLast(offset);
256 if (entry == null) {
257 _hashTable._entryCount++;
258 _hashTable._checkCapacity();
259 } else {
260 assert(identical(entry, _TOMBSTONE));
261 _hashTable._deletedCount--;
262 }
263 _hashTable._recordModification();
264 } else {
265 // The table might have changed, so we can't trust [offset] any more.
266 // Do another lookup before setting the value.
267 offset = _hashTable._put(key);
268 _hashTable._setValue(offset, value);
269 _hashTable._checkCapacity();
270 }
271 return value;
272 }
273
274 /* patch */ V remove(Object key) {
275 int offset = _hashTable._remove(key);
276 if (offset < 0) return null;
277 Object oldValue = _hashTable._value(offset);
278 _hashTable._setValue(offset, null);
279 _hashTable._checkCapacity();
280 return oldValue;
281 }
282
283 /* patch */ void clear() { 576 /* patch */ void clear() {
284 _hashTable._clear(); 577 _elementCount = 0;
285 } 578 _nextEntry = _previousEntry = this;
286 579 _buckets = new List(_INITIAL_CAPACITY);
287 /* patch */ void forEach(void action (K key, V value)) { 580 _modificationCount = (_modificationCount + 1) & _MODIFICATION_COUNT_MASK;
288 int modificationCount = _hashTable._modificationCount; 581 }
289 for (int offset = _hashTable._next(_LinkedHashTable._HEAD_OFFSET); 582
290 offset != _LinkedHashTable._HEAD_OFFSET; 583 void _addEntry(List buckets, int index, int length,
291 offset = _hashTable._next(offset)) { 584 K key, V value, int hashCode) {
292 action(_hashTable._key(offset), _hashTable._value(offset)); 585 _HashMapEntry entry =
293 _hashTable._checkModification(modificationCount); 586 new _LinkedHashMapEntry(key, value, hashCode, buckets[index],
294 } 587 _previousEntry, this);
295 } 588 buckets[index] = entry;
296 589 int newElements = _elementCount + 1;
297 /* patch */ Iterable<K> get keys => 590 _elementCount = newElements;
298 new _LinkedHashTableKeyIterable<K>(_hashTable); 591 // If we end up with more than 75% non-empty entries, we
299 592 // resize the backing store.
300 /* patch */ Iterable<V> get values => 593 if ((newElements << 2) > ((length << 1) + length)) _resize();
301 new _LinkedHashTableValueIterable<V>(_hashTable, 594 _modificationCount = (_modificationCount + 1) & _MODIFICATION_COUNT_MASK;
302 _LinkedHashMapTable._VALUE_INDEX); 595 }
303 596
304 /* patch */ int get length => _hashTable._elementCount; 597 void _resize() {
305 598 List oldBuckets = _buckets;
306 /* patch */ bool get isEmpty => _hashTable._elementCount == 0; 599 int oldLength = oldBuckets.length;
307 600 int newLength = oldLength << 1;
308 /* patch */ bool get isNotEmpty => !isEmpty; 601 List newBuckets = new List(newLength);
602 for (int i = 0; i < oldLength; i++) {
603 _HashMapEntry entry = oldBuckets[i];
604 while (entry != null) {
605 _HashMapEntry next = entry.next;
606 int hashCode = entry.hashCode;
607 int index = hashCode & (newLength - 1);
608 entry.next = newBuckets[index];
609 newBuckets[index] = entry;
610 entry = next;
611 }
612 }
613 _buckets = newBuckets;
614 }
309 } 615 }
310 616
311 patch class LinkedHashSet<E> extends _HashSetBase<E> { 617 patch class LinkedHashSet<E> extends _HashSetBase<E> {
312 static const int _INITIAL_CAPACITY = 8; 618 static const int _INITIAL_CAPACITY = 8;
313 _LinkedHashTable<E> _table; 619 _LinkedHashTable<E> _table;
314 620
315 /* patch */ LinkedHashSet() { 621 /* patch */ LinkedHashSet() {
316 _table = new _LinkedHashTable(_INITIAL_CAPACITY); 622 _table = new _LinkedHashTable(_INITIAL_CAPACITY);
317 _table._container = this; 623 _table._container = this;
318 } 624 }
(...skipping 682 matching lines...) Expand 10 before | Expand all | Expand 10 after
1001 1307
1002 _LinkedHashMapTable() : super(_INITIAL_CAPACITY); 1308 _LinkedHashMapTable() : super(_INITIAL_CAPACITY);
1003 1309
1004 V _value(int offset) => _table[offset + _VALUE_INDEX]; 1310 V _value(int offset) => _table[offset + _VALUE_INDEX];
1005 void _setValue(int offset, V value) { _table[offset + _VALUE_INDEX] = value; } 1311 void _setValue(int offset, V value) { _table[offset + _VALUE_INDEX] = value; }
1006 1312
1007 _copyEntry(List oldTable, int fromOffset, int toOffset) { 1313 _copyEntry(List oldTable, int fromOffset, int toOffset) {
1008 _table[toOffset + _VALUE_INDEX] = oldTable[fromOffset + _VALUE_INDEX]; 1314 _table[toOffset + _VALUE_INDEX] = oldTable[fromOffset + _VALUE_INDEX];
1009 } 1315 }
1010 } 1316 }
OLDNEW
« no previous file with comments | « no previous file | sdk/lib/json/json.dart » ('j') | sdk/lib/json/json.dart » ('J')

Powered by Google App Engine
This is Rietveld 408576698