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

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

Issue 13913005: Implement JS version of LinkedHashSet and move the various HashTable implementations to the VM coll… (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Map -> set. Created 7 years, 8 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/_internal/compiler/implementation/lib/collection_patch.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) 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> {
6 final _HashMapTable<K, V> _hashTable = new _HashMapTable<K, V>(); 6 final _HashMapTable<K, V> _hashTable = new _HashMapTable<K, V>();
7 7
8 /* patch */ HashMap() { 8 /* patch */ HashMap() {
9 _hashTable._container = this; 9 _hashTable._container = this;
10 } 10 }
11 11
12
13 /* patch */ bool containsKey(K key) { 12 /* patch */ bool containsKey(K key) {
14 return _hashTable._get(key) >= 0; 13 return _hashTable._get(key) >= 0;
15 } 14 }
16 15
17 /* patch */ bool containsValue(V value) { 16 /* patch */ bool containsValue(V value) {
18 List table = _hashTable._table; 17 List table = _hashTable._table;
19 int entrySize = _hashTable._entrySize; 18 int entrySize = _hashTable._entrySize;
20 for (int offset = 0; offset < table.length; offset += entrySize) { 19 for (int offset = 0; offset < table.length; offset += entrySize) {
21 if (!_hashTable._isFree(table[offset]) && 20 if (!_hashTable._isFree(table[offset]) &&
22 _hashTable._value(offset) == value) { 21 _hashTable._value(offset) == value) {
(...skipping 160 matching lines...) Expand 10 before | Expand all | Expand 10 after
183 182
184 /* patch */ void retainWhere(bool test(E element)) { 183 /* patch */ void retainWhere(bool test(E element)) {
185 _filterWhere(test, false); 184 _filterWhere(test, false);
186 } 185 }
187 186
188 /* patch */ void clear() { 187 /* patch */ void clear() {
189 _table._clear(); 188 _table._clear();
190 } 189 }
191 } 190 }
192 191
193 class _LinkedHashMapTable<K, V> extends _LinkedHashTable<K> {
194 static const int _INITIAL_CAPACITY = 8;
195 static const int _VALUE_INDEX = 3;
196
197 int get _entrySize => 4;
198
199 _LinkedHashMapTable() : super(_INITIAL_CAPACITY);
200
201 V _value(int offset) => _table[offset + _VALUE_INDEX];
202 void _setValue(int offset, V value) { _table[offset + _VALUE_INDEX] = value; }
203
204 _copyEntry(List oldTable, int fromOffset, int toOffset) {
205 _table[toOffset + _VALUE_INDEX] = oldTable[fromOffset + _VALUE_INDEX];
206 }
207 }
208
209 /** 192 /**
210 * A hash-based map that iterates keys and values in key insertion order. 193 * A hash-based map that iterates keys and values in key insertion order.
211 */ 194 */
212 patch class LinkedHashMap<K, V> { 195 patch class LinkedHashMap<K, V> {
213 final _LinkedHashMapTable _hashTable; 196 final _LinkedHashMapTable _hashTable;
214 197
215 /* patch */ LinkedHashMap() : _hashTable = new _LinkedHashMapTable<K, V>() { 198 /* patch */ LinkedHashMap() : _hashTable = new _LinkedHashMapTable<K, V>() {
216 _hashTable._container = this; 199 _hashTable._container = this;
217 } 200 }
218 201
(...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after
311 new _LinkedHashTableKeyIterable<K>(_hashTable); 294 new _LinkedHashTableKeyIterable<K>(_hashTable);
312 295
313 /* patch */ Iterable<V> get values => 296 /* patch */ Iterable<V> get values =>
314 new _LinkedHashTableValueIterable<V>(_hashTable, 297 new _LinkedHashTableValueIterable<V>(_hashTable,
315 _LinkedHashMapTable._VALUE_INDEX); 298 _LinkedHashMapTable._VALUE_INDEX);
316 299
317 /* patch */ int get length => _hashTable._elementCount; 300 /* patch */ int get length => _hashTable._elementCount;
318 301
319 /* patch */ bool get isEmpty => _hashTable._elementCount == 0; 302 /* patch */ bool get isEmpty => _hashTable._elementCount == 0;
320 } 303 }
304
305 patch class LinkedHashSet<E> extends _HashSetBase<E> {
306 static const int _INITIAL_CAPACITY = 8;
307 _LinkedHashTable<E> _table;
308
309 /* patch */ LinkedHashSet() {
310 _table = new _LinkedHashTable(_INITIAL_CAPACITY);
311 _table._container = this;
312 }
313
314 // Iterable.
315 /* patch */ Iterator<E> get iterator {
316 return new _LinkedHashTableKeyIterator<E>(_table);
317 }
318
319 /* patch */ int get length => _table._elementCount;
320
321 /* patch */ bool get isEmpty => _table._elementCount == 0;
322
323 /* patch */ bool contains(Object object) => _table._get(object) >= 0;
324
325 /* patch */ void forEach(void action(E element)) {
326 int offset = _table._next(_LinkedHashTable._HEAD_OFFSET);
327 int modificationCount = _table._modificationCount;
328 while (offset != _LinkedHashTable._HEAD_OFFSET) {
329 E key = _table._key(offset);
330 action(key);
331 _table._checkModification(modificationCount);
332 offset = _table._next(offset);
333 }
334 }
335
336 /* patch */ E get first {
337 int firstOffset = _table._next(_LinkedHashTable._HEAD_OFFSET);
338 if (firstOffset == _LinkedHashTable._HEAD_OFFSET) {
339 throw new StateError("No elements");
340 }
341 return _table._key(firstOffset);
342 }
343
344 /* patch */ E get last {
345 int lastOffset = _table._prev(_LinkedHashTable._HEAD_OFFSET);
346 if (lastOffset == _LinkedHashTable._HEAD_OFFSET) {
347 throw new StateError("No elements");
348 }
349 return _table._key(lastOffset);
350 }
351
352 // Collection.
353 void _filterWhere(bool test(E element), bool removeMatching) {
354 int entrySize = _table._entrySize;
355 int length = _table._table.length;
356 int offset = _table._next(_LinkedHashTable._HEAD_OFFSET);
357 while (offset != _LinkedHashTable._HEAD_OFFSET) {
358 E key = _table._key(offset);
359 int nextOffset = _table._next(offset);
360 int modificationCount = _table._modificationCount;
361 bool shouldRemove = (removeMatching == test(key));
362 _table._checkModification(modificationCount);
363 if (shouldRemove) {
364 _table._deleteEntry(offset);
365 }
366 offset = nextOffset;
367 }
368 _table._checkCapacity();
369 }
370
371 /* patch */ void add(E element) {
372 _table._put(element);
373 _table._checkCapacity();
374 }
375
376 /* patch */ void addAll(Iterable<E> objects) {
377 for (E object in objects) {
378 _table._put(object);
379 _table._checkCapacity();
380 }
381 }
382
383 /* patch */ bool remove(Object object) {
384 int offset = _table._remove(object);
385 if (offset >= 0) {
386 _table._checkCapacity();
387 return true;
388 }
389 return false;
390 }
391
392 /* patch */ void removeAll(Iterable objectsToRemove) {
393 for (Object object in objectsToRemove) {
394 if (_table._remove(object) >= 0) {
395 _table._checkCapacity();
396 }
397 }
398 }
399
400 /* patch */ void removeWhere(bool test(E element)) {
401 _filterWhere(test, true);
402 }
403
404 /* patch */ void retainWhere(bool test(E element)) {
405 _filterWhere(test, false);
406 }
407
408 /* patch */ void clear() {
409 _table._clear();
410 }
411 }
412
413 class _DeadEntry {
414 const _DeadEntry();
415 }
416
417 class _NullKey {
418 const _NullKey();
419 int get hashCode => null.hashCode;
420 }
421
422 const _TOMBSTONE = const _DeadEntry();
423 const _NULL = const _NullKey();
424
425 class _HashTable<K> {
426 /**
427 * Table of entries with [_entrySize] slots per entry.
428 *
429 * Capacity in entries must be factor of two.
430 */
431 List _table;
432 /** Current capacity. Always equal to [:_table.length ~/ _entrySize:]. */
433 int _capacity;
434 /** Count of occupied entries, including deleted ones. */
435 int _entryCount = 0;
436 /** Count of deleted entries. */
437 int _deletedCount = 0;
438 /** Counter incremented when table is modified. */
439 int _modificationCount = 0;
440 /** If set, used as the source object for [ConcurrentModificationError]s. */
441 Object _container;
442
443 _HashTable(int initialCapacity) : _capacity = initialCapacity {
444 _table = _createTable(initialCapacity);
445 }
446
447 /** Reads key from table. Converts _NULL marker to null. */
448 Object _key(offset) {
449 assert(!_isFree(_table[offset]));
450 Object key = _table[offset];
451 if (!identical(key, _NULL)) return key;
452 return null;
453 }
454
455 /** Writes key to table. Converts null to _NULL marker. */
456 void _setKey(int offset, Object key) {
457 if (key == null) key = _NULL;
458 _table[offset] = key;
459 }
460
461 int get _elementCount => _entryCount - _deletedCount;
462
463 /** Size of each entry. */
464 int get _entrySize => 1;
465
466 void _checkModification(int expectedModificationCount) {
467 if (_modificationCount != expectedModificationCount) {
468 throw new ConcurrentModificationError(_container);
469 }
470 }
471
472 void _recordModification() {
473 // Value cycles after 2^30 modifications. If you keep hold of an
474 // iterator for that long, you might miss a modification detection,
475 // and iteration can go sour. Don't do that.
476 _modificationCount = (_modificationCount + 1) & (0x3FFFFFFF);
477 }
478
479 /**
480 * Create an empty table.
481 */
482 List _createTable(int capacity) {
483 List table = new List(capacity * _entrySize);
484 return table;
485 }
486
487 /** First table probe. */
488 int _firstProbe(int hashCode, int capacity) {
489 return hashCode & (capacity - 1);
490 }
491
492 /** Following table probes. */
493 int _nextProbe(int previousIndex, int probeCount, int capacity) {
494 // When capacity is a power of 2, this probing algorithm (the triangular
495 // number sequence modulo capacity) is guaranteed to hit all indices exactly
496 // once before repeating.
497 return (previousIndex + probeCount) & (capacity - 1);
498 }
499
500 /** Whether an object is a free-marker (either tombstone or free). */
501 bool _isFree(Object marker) =>
502 marker == null || identical(marker, _TOMBSTONE);
503
504 /**
505 * Look up the offset for an object in the table.
506 *
507 * Finds the offset of the object in the table, if it is there,
508 * or the first free offset for its hashCode.
509 */
510 int _probeForAdd(int hashCode, Object object) {
511 int entrySize = _entrySize;
512 int index = _firstProbe(hashCode, _capacity);
513 int firstTombstone = -1;
514 int probeCount = 0;
515 while (true) {
516 int offset = index * entrySize;
517 Object entry = _table[offset];
518 if (identical(entry, _TOMBSTONE)) {
519 if (firstTombstone < 0) firstTombstone = offset;
520 } else if (entry == null) {
521 if (firstTombstone < 0) return offset;
522 return firstTombstone;
523 } else if (identical(_NULL, entry) ? _equals(null, object)
524 : _equals(entry, object)) {
525 return offset;
526 }
527 // The _nextProbe is designed so that it hits
528 // every index eventually.
529 index = _nextProbe(index, ++probeCount, _capacity);
530 }
531 }
532
533 /**
534 * Look up the offset for an object in the table.
535 *
536 * If the object is in the table, its offset is returned.
537 *
538 * If the object is not in the table, Otherwise a negative value is returned.
539 */
540 int _probeForLookup(int hashCode, Object object) {
541 int entrySize = _entrySize;
542 int index = _firstProbe(hashCode, _capacity);
543 int probeCount = 0;
544 while (true) {
545 int offset = index * entrySize;
546 Object entry = _table[offset];
547 if (entry == null) {
548 return -1;
549 } else if (!identical(_TOMBSTONE, entry)) {
550 if (identical(_NULL, entry) ? _equals(null, object)
551 : _equals(entry, object)) {
552 return offset;
553 }
554 }
555 // The _nextProbe is designed so that it hits
556 // every index eventually.
557 index = _nextProbe(index, ++probeCount, _capacity);
558 }
559 }
560
561 // Override the following two to change equality/hashCode computations
562
563 /**
564 * Compare two object for equality.
565 *
566 * The first object is the one already in the table,
567 * and the second is the one being searched for.
568 */
569 bool _equals(Object element, Object other) {
570 return element == other;
571 }
572
573 /**
574 * Compute hash-code for an object.
575 */
576 int _hashCodeOf(Object object) => object.hashCode;
577
578 /**
579 * Ensure that the table isn't too full for its own good.
580 *
581 * Call this after adding an element.
582 */
583 int _checkCapacity() {
584 // Compute everything in multiples of entrySize to avoid division.
585 int freeCount = _capacity - _entryCount;
586 if (freeCount * 4 < _capacity ||
587 freeCount < _deletedCount) {
588 // Less than 25% free or more deleted entries than free entries.
589 _grow(_entryCount - _deletedCount);
590 }
591 }
592
593 void _grow(int contentCount) {
594 int capacity = _capacity;
595 // Don't grow to less than twice the needed capacity.
596 int minCapacity = contentCount * 2;
597 while (capacity < minCapacity) {
598 capacity *= 2;
599 }
600 // Reset to another table and add all existing elements.
601 List oldTable = _table;
602 _table = _createTable(capacity);
603 _capacity = capacity;
604 _entryCount = 0;
605 _deletedCount = 0;
606 _addAllEntries(oldTable);
607 _recordModification();
608 }
609
610 /**
611 * Copies all non-free entries from the old table to the new empty table.
612 */
613 void _addAllEntries(List oldTable) {
614 for (int i = 0; i < oldTable.length; i += _entrySize) {
615 Object object = oldTable[i];
616 if (!_isFree(object)) {
617 int toOffset = _put(object);
618 _copyEntry(oldTable, i, toOffset);
619 }
620 }
621 }
622
623 /**
624 * Copies everything but the key element from one entry to another.
625 *
626 * Called while growing the base array.
627 *
628 * Override this if any non-key fields need copying.
629 */
630 void _copyEntry(List fromTable, int fromOffset, int toOffset) {}
631
632 // The following three methods are for simple get/set/remove operations.
633 // They only affect the key of an entry. The remaining fields must be
634 // filled by the caller.
635
636 /**
637 * Returns the offset of a key in [_table], or negative if it's not there.
638 */
639 int _get(K key) {
640 return _probeForLookup(_hashCodeOf(key), key);
641 }
642
643 /**
644 * Puts the key into the table and returns its offset into [_table].
645 *
646 * If [_entrySize] is greater than 1, the caller should fill the
647 * remaining fields.
648 *
649 * Remember to call [_checkCapacity] after using this method.
650 */
651 int _put(K key) {
652 int offset = _probeForAdd(_hashCodeOf(key), key);
653 Object oldEntry = _table[offset];
654 if (oldEntry == null) {
655 _entryCount++;
656 } else if (identical(oldEntry, _TOMBSTONE)) {
657 _deletedCount--;
658 } else {
659 return offset;
660 }
661 _setKey(offset, key);
662 _recordModification();
663 return offset;
664 }
665
666 /**
667 * Removes a key from the table and returns its offset into [_table].
668 *
669 * Returns null if the key was not in the table.
670 * If [_entrySize] is greater than 1, the caller should clean up the
671 * remaining fields.
672 */
673 int _remove(K key) {
674 int offset = _probeForLookup(_hashCodeOf(key), key);
675 if (offset >= 0) {
676 _deleteEntry(offset);
677 }
678 return offset;
679 }
680
681 /** Clears the table completely, leaving it empty. */
682 void _clear() {
683 if (_elementCount == 0) return;
684 for (int i = 0; i < _table.length; i++) {
685 _table[i] = null;
686 }
687 _entryCount = _deletedCount = 0;
688 _recordModification();
689 }
690
691 /** Clears an entry in the table. */
692 void _deleteEntry(int offset) {
693 assert(!_isFree(_table[offset]));
694 _setKey(offset, _TOMBSTONE);
695 _deletedCount++;
696 _recordModification();
697 }
698 }
699
700 /**
701 * Generic iterable based on a [_HashTable].
702 */
703 abstract class _HashTableIterable<E> extends Iterable<E> {
704 final _HashTable _hashTable;
705 _HashTableIterable(this._hashTable);
706
707 Iterator<E> get iterator;
708
709 /**
710 * Return the iterated value for a given entry.
711 */
712 E _valueAt(int offset, Object key);
713
714 int get length => _hashTable._elementCount;
715
716 bool get isEmpty => _hashTable._elementCount == 0;
717
718 void forEach(void action(E element)) {
719 int entrySize = _hashTable._entrySize;
720 List table = _hashTable._table;
721 int modificationCount = _hashTable._modificationCount;
722 for (int offset = 0; offset < table.length; offset += entrySize) {
723 Object entry = table[offset];
724 if (!_hashTable._isFree(entry)) {
725 E value = _valueAt(offset, entry);
726 action(value);
727 }
728 _hashTable._checkModification(modificationCount);
729 }
730 }
731 }
732
733 abstract class _HashTableIterator<E> implements Iterator<E> {
734 final _HashTable _hashTable;
735 final int _modificationCount;
736 /** Location right after last found element. */
737 int _offset = 0;
738 E _current = null;
739
740 _HashTableIterator(_HashTable hashTable)
741 : _hashTable = hashTable,
742 _modificationCount = hashTable._modificationCount;
743
744 bool moveNext() {
745 _hashTable._checkModification(_modificationCount);
746
747 List table = _hashTable._table;
748 int entrySize = _hashTable._entrySize;
749
750 while (_offset < table.length) {
751 int currentOffset = _offset;
752 Object entry = table[currentOffset];
753 _offset = currentOffset + entrySize;
754 if (!_hashTable._isFree(entry)) {
755 _current = _valueAt(currentOffset, entry);
756 return true;
757 }
758 }
759 _current = null;
760 return false;
761 }
762
763 E get current => _current;
764
765 E _valueAt(int offset, Object key);
766 }
767
768 class _HashTableKeyIterable<K> extends _HashTableIterable<K> {
769 _HashTableKeyIterable(_HashTable<K> hashTable) : super(hashTable);
770
771 Iterator<K> get iterator => new _HashTableKeyIterator<K>(_hashTable);
772
773 K _valueAt(int offset, Object key) {
774 if (identical(key, _NULL)) return null;
775 return key;
776 }
777
778 bool contains(Object value) => _hashTable._get(value) >= 0;
779 }
780
781 class _HashTableKeyIterator<K> extends _HashTableIterator<K> {
782 _HashTableKeyIterator(_HashTable hashTable) : super(hashTable);
783
784 K _valueAt(int offset, Object key) {
785 if (identical(key, _NULL)) return null;
786 return key;
787 }
788 }
789
790 class _HashTableValueIterable<V> extends _HashTableIterable<V> {
791 final int _entryIndex;
792
793 _HashTableValueIterable(_HashTable hashTable, this._entryIndex)
794 : super(hashTable);
795
796 Iterator<V> get iterator {
797 return new _HashTableValueIterator<V>(_hashTable, _entryIndex);
798 }
799
800 V _valueAt(int offset, Object key) => _hashTable._table[offset + _entryIndex];
801 }
802
803 class _HashTableValueIterator<V> extends _HashTableIterator<V> {
804 final int _entryIndex;
805
806 _HashTableValueIterator(_HashTable hashTable, this._entryIndex)
807 : super(hashTable);
808
809 V _valueAt(int offset, Object key) => _hashTable._table[offset + _entryIndex];
810 }
811
812 class _HashMapTable<K, V> extends _HashTable<K> {
813 static const int _INITIAL_CAPACITY = 8;
814 static const int _VALUE_INDEX = 1;
815
816 _HashMapTable() : super(_INITIAL_CAPACITY);
817
818 int get _entrySize => 2;
819
820 V _value(int offset) => _table[offset + _VALUE_INDEX];
821 void _setValue(int offset, V value) { _table[offset + _VALUE_INDEX] = value; }
822
823 _copyEntry(List fromTable, int fromOffset, int toOffset) {
824 _table[toOffset + _VALUE_INDEX] = fromTable[fromOffset + _VALUE_INDEX];
825 }
826 }
827
828 /** Unique marker object for the head of a linked list of entries. */
829 class _LinkedHashTableHeadMarker {
830 const _LinkedHashTableHeadMarker();
831 }
832
833 const _LinkedHashTableHeadMarker _HEAD_MARKER =
834 const _LinkedHashTableHeadMarker();
835
836 class _LinkedHashTable<K> extends _HashTable<K> {
837 static const _NEXT_INDEX = 1;
838 static const _PREV_INDEX = 2;
839 static const _HEAD_OFFSET = 0;
840
841 _LinkedHashTable(int initialCapacity) : super(initialCapacity);
842
843 int get _entrySize => 3;
844
845 List _createTable(int capacity) {
846 List result = new List(capacity * _entrySize);
847 result[_HEAD_OFFSET] = _HEAD_MARKER;
848 result[_HEAD_OFFSET + _NEXT_INDEX] = _HEAD_OFFSET;
849 result[_HEAD_OFFSET + _PREV_INDEX] = _HEAD_OFFSET;
850 return result;
851 }
852
853 int _next(int offset) => _table[offset + _NEXT_INDEX];
854 void _setNext(int offset, int to) { _table[offset + _NEXT_INDEX] = to; }
855
856 int _prev(int offset) => _table[offset + _PREV_INDEX];
857 void _setPrev(int offset, int to) { _table[offset + _PREV_INDEX] = to; }
858
859 void _linkLast(int offset) {
860 // Add entry at offset at end of double-linked list.
861 int last = _prev(_HEAD_OFFSET);
862 _setNext(offset, _HEAD_OFFSET);
863 _setPrev(offset, last);
864 _setNext(last, offset);
865 _setPrev(_HEAD_OFFSET, offset);
866 }
867
868 void _unlink(int offset) {
869 assert(offset != _HEAD_OFFSET);
870 int next = _next(offset);
871 int prev = _prev(offset);
872 _setNext(offset, null);
873 _setPrev(offset, null);
874 _setNext(prev, next);
875 _setPrev(next, prev);
876 }
877
878 /**
879 * Copies all non-free entries from the old table to the new empty table.
880 */
881 void _addAllEntries(List oldTable) {
882 int offset = oldTable[_HEAD_OFFSET + _NEXT_INDEX];
883 while (offset != _HEAD_OFFSET) {
884 Object object = oldTable[offset];
885 int nextOffset = oldTable[offset + _NEXT_INDEX];
886 int toOffset = _put(object);
887 _copyEntry(oldTable, offset, toOffset);
888 offset = nextOffset;
889 }
890 }
891
892 void _clear() {
893 if (_elementCount == 0) return;
894 _setNext(_HEAD_OFFSET, _HEAD_OFFSET);
895 _setPrev(_HEAD_OFFSET, _HEAD_OFFSET);
896 for (int i = _entrySize; i < _table.length; i++) {
897 _table[i] = null;
898 }
899 _entryCount = _deletedCount = 0;
900 _recordModification();
901 }
902
903 int _put(K key) {
904 int offset = _probeForAdd(_hashCodeOf(key), key);
905 Object oldEntry = _table[offset];
906 if (identical(oldEntry, _TOMBSTONE)) {
907 _deletedCount--;
908 } else if (oldEntry == null) {
909 _entryCount++;
910 } else {
911 return offset;
912 }
913 _recordModification();
914 _setKey(offset, key);
915 _linkLast(offset);
916 return offset;
917 }
918
919 void _deleteEntry(int offset) {
920 _unlink(offset);
921 _setKey(offset, _TOMBSTONE);
922 _deletedCount++;
923 _recordModification();
924 }
925 }
926
927 class _LinkedHashTableKeyIterable<K> extends Iterable<K> {
928 final _LinkedHashTable<K> _table;
929 _LinkedHashTableKeyIterable(this._table);
930 Iterator<K> get iterator => new _LinkedHashTableKeyIterator<K>(_table);
931
932 bool contains(Object value) => _table._get(value) >= 0;
933
934 int get length => _table._elementCount;
935 }
936
937 class _LinkedHashTableKeyIterator<K> extends _LinkedHashTableIterator<K> {
938 _LinkedHashTableKeyIterator(_LinkedHashTable<K> hashTable): super(hashTable);
939
940 K _getCurrent(int offset) => _hashTable._key(offset);
941 }
942
943 class _LinkedHashTableValueIterable<V> extends Iterable<V> {
944 final _LinkedHashTable _hashTable;
945 final int _valueIndex;
946 _LinkedHashTableValueIterable(this._hashTable, this._valueIndex);
947 Iterator<V> get iterator =>
948 new _LinkedHashTableValueIterator<V>(_hashTable, _valueIndex);
949 int get length => _hashTable._elementCount;
950 }
951
952 class _LinkedHashTableValueIterator<V> extends _LinkedHashTableIterator<V> {
953 final int _valueIndex;
954
955 _LinkedHashTableValueIterator(_LinkedHashTable hashTable, this._valueIndex)
956 : super(hashTable);
957
958 V _getCurrent(int offset) => _hashTable._table[offset + _valueIndex];
959 }
960
961 abstract class _LinkedHashTableIterator<T> implements Iterator<T> {
962 final _LinkedHashTable _hashTable;
963 final int _modificationCount;
964 int _offset;
965 T _current;
966
967 _LinkedHashTableIterator(_LinkedHashTable table)
968 : _hashTable = table,
969 _modificationCount = table._modificationCount,
970 _offset = table._next(_LinkedHashTable._HEAD_OFFSET);
971
972 bool moveNext() {
973 _hashTable._checkModification(_modificationCount);
974 if (_offset == _LinkedHashTable._HEAD_OFFSET) {
975 _current = null;
976 return false;
977 }
978 _current = _getCurrent(_offset);
979 _offset = _hashTable._next(_offset);
980 return true;
981 }
982
983 T _getCurrent(int offset);
984
985 T get current => _current;
986 }
987
988 class _LinkedHashMapTable<K, V> extends _LinkedHashTable<K> {
989 static const int _INITIAL_CAPACITY = 8;
990 static const int _VALUE_INDEX = 3;
991
992 int get _entrySize => 4;
993
994 _LinkedHashMapTable() : super(_INITIAL_CAPACITY);
995
996 V _value(int offset) => _table[offset + _VALUE_INDEX];
997 void _setValue(int offset, V value) { _table[offset + _VALUE_INDEX] = value; }
998
999 _copyEntry(List oldTable, int fromOffset, int toOffset) {
1000 _table[toOffset + _VALUE_INDEX] = oldTable[fromOffset + _VALUE_INDEX];
1001 }
1002 }
OLDNEW
« no previous file with comments | « no previous file | sdk/lib/_internal/compiler/implementation/lib/collection_patch.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698