| OLD | NEW | 
|     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   /* patch */ factory HashMap({ bool equals(K key1, K key2), |     6   /* patch */ factory HashMap({ bool equals(K key1, K key2), | 
|     7                                 int hashCode(K key), |     7                                 int hashCode(K key), | 
|     8                                 bool isValidKey(potentialKey) }) { |     8                                 bool isValidKey(potentialKey) }) { | 
|     9     if (isValidKey == null) { |     9     if (isValidKey == null) { | 
|    10       if (hashCode == null) { |    10       if (hashCode == null) { | 
| (...skipping 412 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
|   423   final HashMap _map; |   423   final HashMap _map; | 
|   424   _HashMapIterable(this._map); |   424   _HashMapIterable(this._map); | 
|   425   int get length => _map.length; |   425   int get length => _map.length; | 
|   426   bool get isEmpty => _map.isEmpty; |   426   bool get isEmpty => _map.isEmpty; | 
|   427   bool get isNotEmpty => _map.isNotEmpty; |   427   bool get isNotEmpty => _map.isNotEmpty; | 
|   428 } |   428 } | 
|   429  |   429  | 
|   430 class _HashMapKeyIterable<K> extends _HashMapIterable<K> { |   430 class _HashMapKeyIterable<K> extends _HashMapIterable<K> { | 
|   431   _HashMapKeyIterable(HashMap map) : super(map); |   431   _HashMapKeyIterable(HashMap map) : super(map); | 
|   432   Iterator<K> get iterator => new _HashMapKeyIterator<K>(_map); |   432   Iterator<K> get iterator => new _HashMapKeyIterator<K>(_map); | 
|   433   bool contains(K key) => _map.containsKey(key); |   433   bool contains(Object key) => _map.containsKey(key); | 
|   434   void forEach(void action(K key)) { |   434   void forEach(void action(K key)) { | 
|   435     _map.forEach((K key, _) { |   435     _map.forEach((K key, _) { | 
|   436       action(key); |   436       action(key); | 
|   437     }); |   437     }); | 
|   438   } |   438   } | 
|   439 } |   439 } | 
|   440  |   440  | 
|   441 class _HashMapValueIterable<V> extends _HashMapIterable<V> { |   441 class _HashMapValueIterable<V> extends _HashMapIterable<V> { | 
|   442   _HashMapValueIterable(HashMap map) : super(map); |   442   _HashMapValueIterable(HashMap map) : super(map); | 
|   443   Iterator<V> get iterator => new _HashMapValueIterator<V>(_map); |   443   Iterator<V> get iterator => new _HashMapValueIterator<V>(_map); | 
|   444   bool contains(V value) => _map.containsValue(value); |   444   bool contains(Object value) => _map.containsValue(value); | 
|   445   void forEach(void action(V value)) { |   445   void forEach(void action(V value)) { | 
|   446     _map.forEach((_, V value) { |   446     _map.forEach((_, V value) { | 
|   447       action(value); |   447       action(value); | 
|   448     }); |   448     }); | 
|   449   } |   449   } | 
|   450 } |   450 } | 
|   451  |   451  | 
|   452 abstract class _HashMapIterator<E> implements Iterator<E> { |   452 abstract class _HashMapIterator<E> implements Iterator<E> { | 
|   453   final HashMap _map; |   453   final HashMap _map; | 
|   454   final int _stamp; |   454   final int _stamp; | 
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
|   497  |   497  | 
|   498 class _HashMapValueIterator<V> extends _HashMapIterator<V> { |   498 class _HashMapValueIterator<V> extends _HashMapIterator<V> { | 
|   499   _HashMapValueIterator(HashMap map) : super(map); |   499   _HashMapValueIterator(HashMap map) : super(map); | 
|   500   V get current { |   500   V get current { | 
|   501     _HashMapEntry entry = _entry; |   501     _HashMapEntry entry = _entry; | 
|   502     return (entry == null) ? null : entry.value; |   502     return (entry == null) ? null : entry.value; | 
|   503   } |   503   } | 
|   504 } |   504 } | 
|   505  |   505  | 
|   506 patch class HashSet<E> { |   506 patch class HashSet<E> { | 
 |   507   /* patch */ factory HashSet({ bool equals(E e1, E e2), | 
 |   508                                 int hashCode(E e), | 
 |   509                                 bool isValidKey(potentialKey) }) { | 
 |   510     if (isValidKey == null) { | 
 |   511       if (hashCode == null) { | 
 |   512         if (equals == null) { | 
 |   513           return new _HashSet<E>(); | 
 |   514         } | 
 |   515         if (identical(identical, equals)) { | 
 |   516           return new _IdentityHashSet<E>(); | 
 |   517         } | 
 |   518         _hashCode = _defaultHashCode; | 
 |   519       } else if (equals == null) { | 
 |   520         _equals = _defaultEquals; | 
 |   521       } | 
 |   522       isValidKey = new _TypeTest<E>().test; | 
 |   523     } else { | 
 |   524       if (hashCode == null) hashCode = _defaultHashCode; | 
 |   525       if (equals == null) equals = _defaultEquals; | 
 |   526     } | 
 |   527     return new _CustomHashSet<E>(equals, hashCode, isValidKey); | 
 |   528   } | 
 |   529 } | 
 |   530  | 
 |   531 class _HashSet<E> extends _HashSetBase<E> implements HashSet<E> { | 
|   507   static const int _INITIAL_CAPACITY = 8; |   532   static const int _INITIAL_CAPACITY = 8; | 
|   508   final _HashTable<E> _table; |   533  | 
|   509  |   534   List<_HashSetEntry> _buckets = new List(_INITIAL_CAPACITY); | 
|   510   /* patch */ HashSet() : _table = new _HashTable(_INITIAL_CAPACITY) { |   535   int _elementCount = 0; | 
|   511     _table._container = this; |   536   int _modificationCount = 0; | 
|   512   } |   537  | 
|   513  |   538   bool _equals(e1, e2) => e1 == e2; | 
|   514   factory HashSet.from(Iterable<E> iterable) { |   539   int _hashCode(e) => e.hashCode; | 
|   515     return new HashSet<E>()..addAll(iterable); |  | 
|   516   } |  | 
|   517  |   540  | 
|   518   // Iterable. |   541   // Iterable. | 
|   519   /* patch */ Iterator<E> get iterator => new _HashTableKeyIterator<E>(_table); |   542  | 
|   520  |   543   Iterator<E> get iterator => new _HashSetIterator<E>(this); | 
|   521   /* patch */ int get length => _table._elementCount; |   544  | 
|   522  |   545   int get length => _elementCount; | 
|   523   /* patch */ bool get isEmpty => _table._elementCount == 0; |   546  | 
|   524  |   547   bool get isEmpty => _elementCount == 0; | 
|   525   /* patch */ bool get isNotEmpty => !isEmpty; |   548  | 
|   526  |   549   bool get isNotEmpty => _elementCount != 0; | 
|   527   /* patch */ bool contains(Object object) => _table._get(object) >= 0; |   550  | 
|   528  |   551   bool contains(Object object) { | 
|   529   // Collection. |   552     int index = _hashCode(object) & (_buckets.length - 1); | 
|   530   /* patch */ void add(E element) { |   553     HashSetEntry entry = _buckets[index]; | 
|   531     _table._put(element); |   554     while (entry != null) { | 
|   532     _table._checkCapacity(); |   555       if (_equals(entry.key, object)) return true; | 
|   533   } |   556       entry = entry.next; | 
|   534  |   557     } | 
|   535   /* patch */ void addAll(Iterable<E> objects) { |   558     return false; | 
 |   559   } | 
 |   560  | 
 |   561   // Set. | 
 |   562  | 
 |   563   void add(E element) { | 
 |   564     int hashCode = _hashCode(element); | 
 |   565     int index = hashCode & (_buckets.length - 1); | 
 |   566     HashSetEntry entry = _buckets[index]; | 
 |   567     while (entry != null) { | 
 |   568       if (_equals(entry.key, element)) return; | 
 |   569       entry = entry.next; | 
 |   570     } | 
 |   571     _addEntry(element, hashCode, index); | 
 |   572   } | 
 |   573  | 
 |   574   void addAll(Iterable<E> objects) { | 
 |   575     int ctr = 0; | 
|   536     for (E object in objects) { |   576     for (E object in objects) { | 
|   537       _table._put(object); |   577       ctr++; | 
|   538       _table._checkCapacity(); |   578       add(object); | 
|   539     } |   579     } | 
|   540   } |   580   } | 
|   541  |   581  | 
|   542   /* patch */ bool remove(Object object) { |   582   bool _remove(Object object, int hashCode) { | 
|   543     int offset = _table._remove(object); |   583     int index = hashCode & (_buckets.length - 1); | 
|   544     _table._checkCapacity(); |   584     _HashSetEntry entry = _buckets[index]; | 
|   545     return offset >= 0; |   585     _HashSetEntry previous = null; | 
|   546   } |   586     while (entry != null) { | 
|   547  |   587       if (_equals(entry.key, object)) { | 
|   548   /* patch */ void removeAll(Iterable<Object> objectsToRemove) { |   588         _HashSetEntry next = entry.remove(); | 
 |   589         if (previous == null) { | 
 |   590           _buckets[index] = next; | 
 |   591         } else { | 
 |   592           previous.next = next; | 
 |   593         } | 
 |   594         _elementCount--; | 
 |   595         _modificationCount = | 
 |   596             (_modificationCount + 1) & _MODIFICATION_COUNT_MASK; | 
 |   597         return true; | 
 |   598       } | 
 |   599       previous = entry; | 
 |   600       entry = entry.next; | 
 |   601     } | 
 |   602     return false; | 
 |   603   } | 
 |   604  | 
 |   605   bool remove(Object object) => _remove(object, _hashCode(object)); | 
 |   606  | 
 |   607   void removeAll(Iterable<Object> objectsToRemove) { | 
|   549     for (Object object in objectsToRemove) { |   608     for (Object object in objectsToRemove) { | 
|   550       _table._remove(object); |   609       _remove(object, _hashCode(object)); | 
|   551       _table._checkCapacity(); |   610     } | 
|   552     } |   611   } | 
 |   612  | 
 |   613   void retainAll(Iterable<Object> objectsToRetain) { | 
 |   614     super._retainAll(objectsToRetain, (o) => o is E); | 
|   553   } |   615   } | 
|   554  |   616  | 
|   555   void _filterWhere(bool test(E element), bool removeMatching) { |   617   void _filterWhere(bool test(E element), bool removeMatching) { | 
|   556     int entrySize = _table._entrySize; |   618     int length = _buckets.length; | 
|   557     int length = _table._table.length; |   619     for (int index =  0; index < length; index++) { | 
|   558     for (int offset =  0; offset < length; offset += entrySize) { |   620       HashSetEntry entry = _buckets[index]; | 
|   559       Object entry = _table._table[offset]; |   621       HashSetEntry previous = null; | 
|   560       if (!_table._isFree(entry)) { |   622       while (entry != null) { | 
|   561         E key = identical(entry, _NULL) ? null : entry; |   623         int modificationCount = _modificationCount; | 
|   562         int modificationCount = _table._modificationCount; |   624         bool testResult = test(entry.key); | 
|   563         bool shouldRemove = (removeMatching == test(key)); |   625         if (modificationCount != _modificationCount) { | 
|   564         _table._checkModification(modificationCount); |   626           throw new ConcurrentModificationError(this); | 
|   565         if (shouldRemove) { |   627         } | 
|   566           _table._deleteEntry(offset); |   628         if (testResult == removeMatching) { | 
|   567         } |   629           HashSetEntry next = entry.remove(); | 
|   568       } |   630           if (previous == null) { | 
|   569     } |   631             _buckets[index] = next; | 
|   570     _table._checkCapacity(); |   632           } else { | 
|   571   } |   633             previous.next = next; | 
|   572  |   634           } | 
|   573   /* patch */ void removeWhere(bool test(E element)) { |   635           _elementCount--; | 
 |   636           _modificationCount = | 
 |   637               (_modificationCount + 1) & _MODIFICATION_COUNT_MASK; | 
 |   638           entry = next; | 
 |   639         } else { | 
 |   640           previous = entry; | 
 |   641           entry = entry.next; | 
 |   642         } | 
 |   643       } | 
 |   644     } | 
 |   645   } | 
 |   646  | 
 |   647   void removeWhere(bool test(E element)) { | 
|   574     _filterWhere(test, true); |   648     _filterWhere(test, true); | 
|   575   } |   649   } | 
|   576  |   650  | 
|   577   /* patch */ void retainWhere(bool test(E element)) { |   651   void retainWhere(bool test(E element)) { | 
|   578     _filterWhere(test, false); |   652     _filterWhere(test, false); | 
|   579   } |   653   } | 
|   580  |   654  | 
|   581   /* patch */ void clear() { |   655   void clear() { | 
|   582     _table._clear(); |   656     _elementCount = 0; | 
|   583   } |   657     _buckets = new List(_INITIAL_CAPACITY); | 
 |   658     _modificationCount++; | 
 |   659   } | 
 |   660  | 
 |   661   void _addEntry(E key, int hashCode, int index) { | 
 |   662     _buckets[index] = new _HashSetEntry(key, hashCode, _buckets[index]); | 
 |   663     int newElements = _elementCount + 1; | 
 |   664     _elementCount = newElements; | 
 |   665     int length = _buckets.length; | 
 |   666     // If we end up with more than 75% non-empty entries, we | 
 |   667     // resize the backing store. | 
 |   668     if ((newElements << 2) > ((length << 1) + length)) _resize(); | 
 |   669     _modificationCount = (_modificationCount + 1) & _MODIFICATION_COUNT_MASK; | 
 |   670   } | 
 |   671  | 
 |   672   void _resize() { | 
 |   673     int oldLength = _buckets.length; | 
 |   674     int newLength = oldLength << 1; | 
 |   675     List oldBuckets = _buckets; | 
 |   676     List newBuckets = new List(newLength); | 
 |   677     for (int i = 0; i < oldLength; i++) { | 
 |   678       _HashSetEntry entry = oldBuckets[i]; | 
 |   679       while (entry != null) { | 
 |   680         _HashSetEntry next = entry.next; | 
 |   681         int newIndex = entry.hashCode & (newLength - 1); | 
 |   682         entry.next = newBuckets[newIndex]; | 
 |   683         newBuckets[newIndex] = entry; | 
 |   684         entry = next; | 
 |   685       } | 
 |   686     } | 
 |   687     _buckets = newBuckets; | 
 |   688   } | 
 |   689  | 
 |   690   HashSet<E> _newSet() => new _HashSet<E>(); | 
 |   691 } | 
 |   692  | 
 |   693 class _IdentityHashSet<E> extends _HashSet<E> { | 
 |   694   bool _equals(e1, e2) => identical(e1, e2); | 
 |   695   HashSet<E> _newSet() => new _IdentityHashSet<E>(); | 
 |   696 } | 
 |   697  | 
 |   698 class _CustomHashSet<E> extends _HashSet<E> { | 
 |   699   final _Equality<E> _equality; | 
 |   700   final _Hasher<E> _hasher; | 
 |   701   final _Predicate _validKey; | 
 |   702   _CustomHashSet(this._equality, this._hasher, this._validKey); | 
 |   703  | 
 |   704   bool remove(Object element) { | 
 |   705     if (!_validKey(element)) return false; | 
 |   706     return super.remove(element); | 
 |   707   } | 
 |   708  | 
 |   709   bool contains(Object element) { | 
 |   710     if (!_validKey(element)) return false; | 
 |   711     return super.contains(element); | 
 |   712   } | 
 |   713  | 
 |   714   bool containsAll(Iterable<Object> elements) { | 
 |   715     for (Object element in elements) { | 
 |   716       if (!_validKey(element) || !this.contains(element)) return false; | 
 |   717     } | 
 |   718     return true; | 
 |   719   } | 
 |   720  | 
 |   721   void removeAll(Iterable<Object> elements) { | 
 |   722     for (Object element in elements) { | 
 |   723       if (_validKey(element)) { | 
 |   724         super._remove(element, _hasher(element)); | 
 |   725       } | 
 |   726     } | 
 |   727   } | 
 |   728  | 
 |   729   void retainAll(Iterable<Object> elements) { | 
 |   730     super._retainAll(elements, _validKey); | 
 |   731   } | 
 |   732  | 
 |   733   bool _equals(e1, e2) => _equality(e1, e2); | 
 |   734   int _hashCode(e) => _hasher(e); | 
 |   735  | 
 |   736   HashSet<E> _newSet() => new _CustomHashSet<E>(_equality, _hasher, _validKey); | 
 |   737 } | 
 |   738  | 
 |   739 class _HashSetEntry { | 
 |   740   final key; | 
 |   741   final int hashCode; | 
 |   742   _HashSetEntry next; | 
 |   743   _HashSetEntry(this.key, this.hashCode, this.next); | 
 |   744  | 
 |   745   _HashSetEntry remove() { | 
 |   746     _HashSetEntry result = next; | 
 |   747     next = null; | 
 |   748     return result; | 
 |   749   } | 
 |   750 } | 
 |   751  | 
 |   752 class _HashSetIterator<E> implements Iterator<E> { | 
 |   753   final _HashSet _set; | 
 |   754   final int _modificationCount; | 
 |   755   int _index = 0; | 
 |   756   _HashSetEntry _next = null; | 
 |   757   E _current = null; | 
 |   758  | 
 |   759   _HashSetIterator(_HashSet hashSet) | 
 |   760       : _set = hashSet, _modificationCount = hashSet._modificationCount; | 
 |   761  | 
 |   762   bool moveNext() { | 
 |   763     if (_modificationCount != _set._modificationCount) { | 
 |   764       throw new ConcurrentModificationError(_set); | 
 |   765     } | 
 |   766     if (_next != null) { | 
 |   767       _current = _next.key; | 
 |   768       _next = _next.next; | 
 |   769       return true; | 
 |   770     } | 
 |   771     List<_HashSetEntry> buckets = _set._buckets; | 
 |   772     while (_index < buckets.length) { | 
 |   773       _next = buckets[_index]; | 
 |   774       _index = _index + 1; | 
 |   775       if (_next != null) { | 
 |   776         _current = _next.key; | 
 |   777         _next = _next.next; | 
 |   778         return true; | 
 |   779       } | 
 |   780     } | 
 |   781     _current = null; | 
 |   782     return false; | 
 |   783   } | 
 |   784  | 
 |   785   E get current => _current; | 
|   584 } |   786 } | 
|   585  |   787  | 
|   586 class _LinkedHashMapEntry extends _HashMapEntry { |   788 class _LinkedHashMapEntry extends _HashMapEntry { | 
 |   789   /// Double-linked list of entries of a linked hash map. | 
 |   790   /// The _LinkedHashMap itself is the head of the list, so the type is "var". | 
 |   791   /// Both are initialized to `this` when initialized. | 
|   587   var _nextEntry; |   792   var _nextEntry; | 
|   588   var _previousEntry; |   793   var _previousEntry; | 
|   589   _LinkedHashMapEntry(key, value, int hashCode, _LinkedHashMapEntry next, |   794   _LinkedHashMapEntry(key, value, int hashCode, _LinkedHashMapEntry next, | 
|   590                       this._previousEntry, this._nextEntry) |   795                       this._previousEntry, this._nextEntry) | 
|   591       : super(key, value, hashCode, next) { |   796       : super(key, value, hashCode, next) { | 
|   592     _previousEntry._nextEntry = this; |   797     _previousEntry._nextEntry = this; | 
|   593     _nextEntry._previousEntry = this; |   798     _nextEntry._previousEntry = this; | 
|   594   } |   799   } | 
|   595 } |   800 } | 
|   596  |   801  | 
|   597 class _LinkedHashMapKeyIterable<K> extends IterableBase<K> { |   802 class _LinkedHashMapKeyIterable<K> extends IterableBase<K> { | 
|   598   LinkedHashMap<K, dynamic> _map; |   803   LinkedHashMap<K, dynamic> _map; | 
|   599   _LinkedHashMapKeyIterable(this._map); |   804   _LinkedHashMapKeyIterable(this._map); | 
|   600   Iterator<K> get iterator => new _LinkedHashMapKeyIterator<K>(_map); |   805   Iterator<K> get iterator => new _LinkedHashMapKeyIterator<K>(_map); | 
|   601   bool contains(K key) => _map.containsKey(key); |   806   bool contains(Object key) => _map.containsKey(key); | 
|   602   bool get isEmpty => _map.isEmpty; |   807   bool get isEmpty => _map.isEmpty; | 
|   603   bool get isNotEmpty => _map.isNotEmpty; |   808   bool get isNotEmpty => _map.isNotEmpty; | 
|   604   int get length => _map.length; |   809   int get length => _map.length; | 
|   605 } |   810 } | 
|   606  |   811  | 
|   607 class _LinkedHashMapValueIterable<V> extends IterableBase<V> { |   812 class _LinkedHashMapValueIterable<V> extends IterableBase<V> { | 
|   608   LinkedHashMap<dynamic, V> _map; |   813   LinkedHashMap<dynamic, V> _map; | 
|   609   _LinkedHashMapValueIterable(this._map); |   814   _LinkedHashMapValueIterable(this._map); | 
|   610   Iterator<K> get iterator => new _LinkedHashMapValueIterator<V>(_map); |   815   Iterator<K> get iterator => new _LinkedHashMapValueIterator<V>(_map); | 
|   611   bool contains(V value) => _map.containsValue(value); |   816   bool contains(Object value) => _map.containsValue(value); | 
|   612   bool get isEmpty => _map.isEmpty; |   817   bool get isEmpty => _map.isEmpty; | 
|   613   bool get isNotEmpty => _map.isNotEmpty; |   818   bool get isNotEmpty => _map.isNotEmpty; | 
|   614   int get length => _map.length; |   819   int get length => _map.length; | 
|   615 } |   820 } | 
|   616  |   821  | 
|   617 abstract class _LinkedHashMapIterator<T> implements Iterator<T> { |   822 abstract class _LinkedHashMapIterator<T> implements Iterator<T> { | 
|   618   final LinkedHashMap _map; |   823   final LinkedHashMap _map; | 
|   619   var _next; |   824   var _next; | 
|   620   T _current; |   825   T _current; | 
|   621   int _modificationCount; |   826   int _modificationCount; | 
| (...skipping 30 matching lines...) Expand all  Loading... | 
|   652 class _LinkedHashMapValueIterator<V> extends _LinkedHashMapIterator<V> { |   857 class _LinkedHashMapValueIterator<V> extends _LinkedHashMapIterator<V> { | 
|   653   _LinkedHashMapValueIterator(LinkedHashMap map) : super(map); |   858   _LinkedHashMapValueIterator(LinkedHashMap map) : super(map); | 
|   654   V _getValue(_LinkedHashMapEntry entry) => entry.value; |   859   V _getValue(_LinkedHashMapEntry entry) => entry.value; | 
|   655 } |   860 } | 
|   656  |   861  | 
|   657  |   862  | 
|   658 /** |   863 /** | 
|   659  * A hash-based map that iterates keys and values in key insertion order. |   864  * A hash-based map that iterates keys and values in key insertion order. | 
|   660  */ |   865  */ | 
|   661 patch class LinkedHashMap<K, V> { |   866 patch class LinkedHashMap<K, V> { | 
 |   867   /// Holds a double-linked list of entries in insertion order. | 
 |   868   /// The fields have the same name as the ones in [_LinkedHashMapEntry], | 
 |   869   /// and this map is itself used as the head entry of the list. | 
 |   870   /// Set to `this` when initialized, representing the empty list (containing | 
 |   871   /// only the head entry itself). | 
|   662   var _nextEntry; |   872   var _nextEntry; | 
|   663   var _previousEntry; |   873   var _previousEntry; | 
|   664  |   874  | 
|   665   /* patch */ factory LinkedHashMap({ bool equals(K key1, K key2), |   875   /* patch */ factory LinkedHashMap({ bool equals(K key1, K key2), | 
|   666                                       int hashCode(K key), |   876                                       int hashCode(K key), | 
|   667                                       bool isValidKey(potentialKey) }) { |   877                                       bool isValidKey(potentialKey) }) { | 
|   668     if (isValidKey == null) { |   878     if (isValidKey == null) { | 
|   669       if (hashCode == null) { |   879       if (hashCode == null) { | 
|   670         if (equals == null) { |   880         if (equals == null) { | 
|   671           return new _LinkedHashMap<K, V>(); |   881           return new _LinkedHashMap<K, V>(); | 
| (...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
|   731   } |   941   } | 
|   732  |   942  | 
|   733   void _addEntry(List buckets, int index, int length, |   943   void _addEntry(List buckets, int index, int length, | 
|   734                  K key, V value, int hashCode) { |   944                  K key, V value, int hashCode) { | 
|   735     _HashMapEntry entry = |   945     _HashMapEntry entry = | 
|   736         new _LinkedHashMapEntry(key, value, hashCode, buckets[index], |   946         new _LinkedHashMapEntry(key, value, hashCode, buckets[index], | 
|   737                                 _previousEntry, this); |   947                                 _previousEntry, this); | 
|   738     buckets[index] = entry; |   948     buckets[index] = entry; | 
|   739     int newElements = _elementCount + 1; |   949     int newElements = _elementCount + 1; | 
|   740     _elementCount = newElements; |   950     _elementCount = newElements; | 
 |   951  | 
|   741     // If we end up with more than 75% non-empty entries, we |   952     // If we end up with more than 75% non-empty entries, we | 
|   742     // resize the backing store. |   953     // resize the backing store. | 
|   743     if ((newElements << 2) > ((length << 1) + length)) _resize(); |   954     if ((newElements << 2) > ((length << 1) + length)) _resize(); | 
|   744     _modificationCount = (_modificationCount + 1) & _MODIFICATION_COUNT_MASK; |   955     _modificationCount = (_modificationCount + 1) & _MODIFICATION_COUNT_MASK; | 
|   745   } |   956   } | 
|   746  |   957  | 
|   747   void _removeEntry(_LinkedHashMapEntry entry, |   958   void _removeEntry(_LinkedHashMapEntry entry, | 
|   748                     _HashMapEntry previousInBucket, |   959                     _HashMapEntry previousInBucket, | 
|   749                     int bucketIndex) { |   960                     int bucketIndex) { | 
|   750     var previousInChain = entry._previousEntry; |   961     var previousInChain = entry._previousEntry; | 
| (...skipping 30 matching lines...) Expand all  Loading... | 
|   781                                  with _LinkedHashMapMixin<K, V> { |   992                                  with _LinkedHashMapMixin<K, V> { | 
|   782   _LinkedCustomHashMap(bool equals(K key1, K key2), |   993   _LinkedCustomHashMap(bool equals(K key1, K key2), | 
|   783                        int hashCode(K key), |   994                        int hashCode(K key), | 
|   784                        bool isValidKey(potentialKey)) |   995                        bool isValidKey(potentialKey)) | 
|   785       : super(equals, hashCode, isValidKey) { |   996       : super(equals, hashCode, isValidKey) { | 
|   786     _nextEntry = _previousEntry = this; |   997     _nextEntry = _previousEntry = this; | 
|   787   } |   998   } | 
|   788 } |   999 } | 
|   789  |  1000  | 
|   790  |  1001  | 
|   791 patch class LinkedHashSet<E> extends _HashSetBase<E> { |  1002 patch class LinkedHashSet<E> { | 
|   792   static const int _INITIAL_CAPACITY = 8; |  1003   /* patch */ factory LinkedHashSet({ bool equals(E e1, E e2), | 
|   793   _LinkedHashTable<E> _table; |  1004                                       int hashCode(E e), | 
|   794  |  1005                                       bool isValidKey(potentialKey) }) { | 
|   795   /* patch */ LinkedHashSet() { |  1006     if (isValidKey == null) { | 
|   796     _table = new _LinkedHashTable(_INITIAL_CAPACITY); |  1007       if (hashCode == null) { | 
|   797     _table._container = this; |  1008         if (equals == null) { | 
 |  1009           return new _LinkedHashSet<E>(); | 
 |  1010         } | 
 |  1011         if (identical(identical, equals)) { | 
 |  1012           return new _LinkedIdentityHashSet<E>(); | 
 |  1013         } | 
 |  1014         _hashCode = _defaultHashCode; | 
 |  1015       } else if (equals == null) { | 
 |  1016         _equals = _defaultEquals; | 
 |  1017       } | 
 |  1018       isValidKey = new _TypeTest<E>().test; | 
 |  1019     } else { | 
 |  1020       if (hashCode == null) hashCode = _defaultHashCode; | 
 |  1021       if (equals == null) equals = _defaultEquals; | 
 |  1022     } | 
 |  1023     return new _LinkedCustomHashSet<E>(equals, hashCode, isValidKey); | 
 |  1024   } | 
 |  1025 } | 
 |  1026  | 
 |  1027 class _LinkedHashSetEntry extends _HashSetEntry { | 
 |  1028   /// Links this element into a double-linked list of elements of a hash set. | 
 |  1029   /// The hash set object itself is used as the head entry of the list, so | 
 |  1030   /// the field is typed as "var". | 
 |  1031   /// Both links are initialized to `this` when the object is created. | 
 |  1032   var _nextEntry; | 
 |  1033   var _previousEntry; | 
 |  1034   _LinkedHashSetEntry(var key, int hashCode, _LinkedHashSetEntry next, | 
 |  1035                       this._previousEntry, this._nextEntry) | 
 |  1036       : super(key, hashCode, next) { | 
 |  1037     _previousEntry._nextEntry = _nextEntry._previousEntry = this; | 
 |  1038   } | 
 |  1039  | 
 |  1040   _LinkedHashSetEntry remove() { | 
 |  1041     _previousEntry._nextEntry = _nextEntry; | 
 |  1042     _nextEntry._previousEntry = _previousEntry; | 
 |  1043     _nextEntry = _previousEntry = this; | 
 |  1044     return super.remove(); | 
 |  1045   } | 
 |  1046 } | 
 |  1047  | 
 |  1048 class _LinkedHashSet<E> extends _HashSet<E> | 
 |  1049                         implements LinkedHashSet<E> { | 
 |  1050   /// Holds a double linked list of the element entries of the set in | 
 |  1051   /// insertion order. | 
 |  1052   /// The fields have the same names as the ones in [_LinkedHashSetEntry], | 
 |  1053   /// allowing this object to be used as the head entry of the list. | 
 |  1054   /// The fields are initialized to `this` when created, representing the | 
 |  1055   /// empty list that only contains the head entry. | 
 |  1056   var _nextEntry; | 
 |  1057   var _previousEntry; | 
 |  1058  | 
 |  1059   _LinkedHashSet() { | 
 |  1060     _nextEntry = _previousEntry = this; | 
|   798   } |  1061   } | 
|   799  |  1062  | 
|   800   // Iterable. |  1063   // Iterable. | 
|   801   /* patch */ Iterator<E> get iterator { |  1064  | 
|   802     return new _LinkedHashTableKeyIterator<E>(_table); |  1065   Iterator<E> get iterator => new _LinkedHashSetIterator<E>(this); | 
|   803   } |  1066  | 
|   804  |  1067   void forEach(void action(E element)) { | 
|   805   /* patch */ int get length => _table._elementCount; |  1068     var cursor = _nextEntry; | 
|   806  |  1069     int modificationCount = _modificationCount; | 
|   807   /* patch */ bool get isEmpty => _table._elementCount == 0; |  1070     while (!identical(cursor, this)) { | 
|   808  |  1071       _LinkedHashSetEntry entry = cursor; | 
|   809   /* patch */ bool get isNotEmpty => !isEmpty; |  1072       action(entry.key); | 
|   810  |  1073       if (_modificationCount != modificationCount) { | 
|   811   /* patch */ bool contains(Object object) => _table._get(object) >= 0; |  1074         throw new ConcurrentModificationError(this); | 
|   812  |  1075       } | 
|   813   /* patch */ void forEach(void action(E element)) { |  1076       cursor = entry._nextEntry; | 
|   814     int offset = _table._next(_LinkedHashTable._HEAD_OFFSET); |  1077     } | 
|   815     int modificationCount = _table._modificationCount; |  1078   } | 
|   816     while (offset != _LinkedHashTable._HEAD_OFFSET) { |  1079  | 
|   817       E key = _table._key(offset); |  1080   E get first { | 
|   818       action(key); |  1081     if (identical(_nextEntry, this)) { | 
|   819       _table._checkModification(modificationCount); |  | 
|   820       offset = _table._next(offset); |  | 
|   821     } |  | 
|   822   } |  | 
|   823  |  | 
|   824   /* patch */ E get first { |  | 
|   825     int firstOffset = _table._next(_LinkedHashTable._HEAD_OFFSET); |  | 
|   826     if (firstOffset == _LinkedHashTable._HEAD_OFFSET) { |  | 
|   827       throw new StateError("No elements"); |  1082       throw new StateError("No elements"); | 
|   828     } |  1083     } | 
|   829     return _table._key(firstOffset); |  1084     _LinkedHashSetEntry entry = _nextEntry; | 
|   830   } |  1085     return entry.key; | 
|   831  |  1086   } | 
|   832   /* patch */ E get last { |  1087  | 
|   833     int lastOffset = _table._prev(_LinkedHashTable._HEAD_OFFSET); |  1088   E get last { | 
|   834     if (lastOffset == _LinkedHashTable._HEAD_OFFSET) { |  1089     if (identical(_previousEntry, this)) { | 
|   835       throw new StateError("No elements"); |  1090       throw new StateError("No elements"); | 
|   836     } |  1091     } | 
|   837     return _table._key(lastOffset); |  1092     _LinkedHashSetEntry entry = _previousEntry; | 
|   838   } |  1093     return entry.key; | 
|   839  |  1094   } | 
|   840   // Collection. |  1095  | 
 |  1096   // Set. | 
 |  1097  | 
|   841   void _filterWhere(bool test(E element), bool removeMatching) { |  1098   void _filterWhere(bool test(E element), bool removeMatching) { | 
|   842     int entrySize = _table._entrySize; |  1099     var cursor = _nextEntry; | 
|   843     int length = _table._table.length; |  1100     while (!identical(cursor, this)) { | 
|   844     int offset = _table._next(_LinkedHashTable._HEAD_OFFSET); |  1101       _LinkedHashSetEntry entry = cursor; | 
|   845     while (offset != _LinkedHashTable._HEAD_OFFSET) { |  1102       int modificationCount = _modificationCount; | 
|   846       E key = _table._key(offset); |  1103       bool testResult = test(entry.key); | 
|   847       int nextOffset = _table._next(offset); |  1104       if (modificationCount != _modificationCount) { | 
|   848       int modificationCount = _table._modificationCount; |  1105         throw new ConcurrentModificationError(this); | 
|   849       bool shouldRemove = (removeMatching == test(key)); |  1106       } | 
|   850       _table._checkModification(modificationCount); |  1107       cursor = entry._nextEntry; | 
|   851       if (shouldRemove) { |  1108       if (testResult == removeMatching) { | 
|   852         _table._deleteEntry(offset); |  1109         _remove(entry.key, entry.hashCode); | 
|   853       } |  1110       } | 
|   854       offset = nextOffset; |  1111     } | 
|   855     } |  1112   } | 
|   856     _table._checkCapacity(); |  1113  | 
|   857   } |  1114   void _addEntry(E key, int hashCode, int index) { | 
|   858  |  1115     _buckets[index] = | 
|   859   /* patch */ void add(E element) { |  1116         new _LinkedHashSetEntry(key, hashCode, _buckets[index], | 
|   860     _table._put(element); |  1117                                 _previousEntry, this); | 
|   861     _table._checkCapacity(); |  1118     int newElements = _elementCount + 1; | 
|   862   } |  1119     _elementCount = newElements; | 
|   863  |  1120     int length = _buckets.length; | 
|   864   /* patch */ void addAll(Iterable<E> objects) { |  1121     // If we end up with more than 75% non-empty entries, we | 
|   865     for (E object in objects) { |  1122     // resize the backing store. | 
|   866       _table._put(object); |  1123     if ((newElements << 2) > ((length << 1) + length)) _resize(); | 
|   867       _table._checkCapacity(); |  1124     _modificationCount = (_modificationCount + 1) & _MODIFICATION_COUNT_MASK; | 
|   868     } |  1125   } | 
|   869   } |  1126  | 
|   870  |  1127   void clear() { | 
|   871   /* patch */ bool remove(Object object) { |  1128     _nextEntry = _previousEntry = this; | 
|   872     int offset = _table._remove(object); |  1129     super.clear(); | 
|   873     if (offset >= 0) { |  1130   } | 
|   874       _table._checkCapacity(); |  1131  | 
|   875       return true; |  1132   HashSet<E> _newSet() => new _LinkedHashSet<E>(); | 
|   876     } |  1133 } | 
|   877     return false; |  1134  | 
|   878   } |  1135 class _LinkedIdentityHashSet<E> extends _LinkedHashSet<E> { | 
|   879  |  1136   bool _equals(e1, e2) => identical(e1, e2); | 
|   880   /* patch */ void removeAll(Iterable objectsToRemove) { |  1137   HashSet<E> _newSet() => new _LinkedIdentityHashSet<E>(); | 
|   881     for (Object object in objectsToRemove) { |  1138 } | 
|   882       if (_table._remove(object) >= 0) { |  1139  | 
|   883         _table._checkCapacity(); |  1140 class _LinkedCustomHashSet<E> extends _LinkedHashSet<E> { | 
|   884       } |  1141   final _Equality<E> _equality; | 
|   885     } |  1142   final _Hasher<E> _hasher; | 
|   886   } |  1143   final _Predicate _validKey; | 
|   887  |  1144  | 
|   888   /* patch */ void removeWhere(bool test(E element)) { |  1145   _LinkedCustomHashSet(this._equality, this._hasher, bool validKey(object)) | 
|   889     _filterWhere(test, true); |  1146       : _validKey = (validKey != null) ? validKey : new _TypeTest<E>().test; | 
|   890   } |  1147  | 
|   891  |  1148   bool _equals(e1, e2) => _equality(e1, e2); | 
|   892   /* patch */ void retainWhere(bool test(E element)) { |  1149  | 
|   893     _filterWhere(test, false); |  1150   int _hashCode(e) => _hasher(e); | 
|   894   } |  1151  | 
|   895  |  1152   bool contains(Object o) { | 
|   896   /* patch */ void clear() { |  1153     if (!_validKey(o)) return false; | 
|   897     _table._clear(); |  1154     return super.contains(o); | 
|   898   } |  1155   } | 
|   899 } |  1156  | 
|   900  |  1157   bool remove(Object o) { | 
|   901 class _DeadEntry { |  1158     if (!_validKey(o)) return false; | 
|   902   const _DeadEntry(); |  1159     return super.remove(o); | 
|   903 } |  1160   } | 
|   904  |  1161  | 
|   905 class _NullKey { |  1162   bool containsAll(Iterable<Object> elements) { | 
|   906   const _NullKey(); |  1163     for (Object element in elements) { | 
|   907   int get hashCode => null.hashCode; |  1164       if (!_validKey(element) || !this.contains(element)) return false; | 
|   908 } |  1165     } | 
|   909  |  1166     return true; | 
|   910 const _TOMBSTONE = const _DeadEntry(); |  1167   } | 
|   911 const _NULL = const _NullKey(); |  1168  | 
|   912  |  1169   void removeAll(Iterable<Object> elements) { | 
|   913 class _HashTable<K> { |  1170     for (Object element in elements) { | 
|   914   /** |  1171       if (_validKey(element)) { | 
|   915    * Table of entries with [_entrySize] slots per entry. |  1172         super._remove(element, _hasher(element)); | 
|   916    * |  1173       } | 
|   917    * Capacity in entries must be factor of two. |  1174     } | 
|   918    */ |  1175   } | 
|   919   List _table; |  1176  | 
|   920   /** Current capacity. Always equal to [:_table.length ~/ _entrySize:]. */ |  1177   void retainAll(Iterable<Object> elements) { | 
|   921   int _capacity; |  1178     super._retainAll(elements, _validKey); | 
|   922   /** Count of occupied entries, including deleted ones. */ |  1179   } | 
|   923   int _entryCount = 0; |  1180  | 
|   924   /** Count of deleted entries. */ |  1181   HashSet<E> _newSet() => | 
|   925   int _deletedCount = 0; |  1182       new _LinkedCustomHashSet<E>(_equality, _hasher, _validKey); | 
|   926   /** Counter incremented when table is modified. */ |  1183 } | 
|   927   int _modificationCount = 0; |  1184  | 
|   928   /** If set, used as the source object for [ConcurrentModificationError]s. */ |  1185 class _LinkedHashSetIterator<E> implements Iterator<E> { | 
|   929   Object _container; |  1186   final _LinkedHashSet _set; | 
|   930  |  | 
|   931   _HashTable(int initialCapacity) : _capacity = initialCapacity { |  | 
|   932     _table = _createTable(initialCapacity); |  | 
|   933   } |  | 
|   934  |  | 
|   935   /** Reads key from table. Converts _NULL marker to null. */ |  | 
|   936   Object _key(offset) { |  | 
|   937     assert(!_isFree(_table[offset])); |  | 
|   938     Object key = _table[offset]; |  | 
|   939     if (!identical(key, _NULL)) return key; |  | 
|   940     return null; |  | 
|   941   } |  | 
|   942  |  | 
|   943   /** Writes key to table. Converts null to _NULL marker. */ |  | 
|   944   void _setKey(int offset, Object key) { |  | 
|   945     if (key == null) key = _NULL; |  | 
|   946     _table[offset] = key; |  | 
|   947   } |  | 
|   948  |  | 
|   949   int get _elementCount => _entryCount - _deletedCount; |  | 
|   950  |  | 
|   951   /** Size of each entry. */ |  | 
|   952   int get _entrySize => 1; |  | 
|   953  |  | 
|   954   void _checkModification(int expectedModificationCount) { |  | 
|   955     if (_modificationCount != expectedModificationCount) { |  | 
|   956       throw new ConcurrentModificationError(_container); |  | 
|   957     } |  | 
|   958   } |  | 
|   959  |  | 
|   960   void _recordModification() { |  | 
|   961     // Value cycles after 2^30 modifications. If you keep hold of an |  | 
|   962     // iterator for that long, you might miss a modification detection, |  | 
|   963     // and iteration can go sour. Don't do that. |  | 
|   964     _modificationCount = (_modificationCount + 1) & (0x3FFFFFFF); |  | 
|   965   } |  | 
|   966  |  | 
|   967   /** |  | 
|   968    * Create an empty table. |  | 
|   969    */ |  | 
|   970   List _createTable(int capacity) { |  | 
|   971     List table = new List(capacity * _entrySize); |  | 
|   972     return table; |  | 
|   973   } |  | 
|   974  |  | 
|   975   /** First table probe. */ |  | 
|   976   int _firstProbe(int hashCode, int capacity) { |  | 
|   977     return hashCode & (capacity - 1); |  | 
|   978   } |  | 
|   979  |  | 
|   980   /** Following table probes. */ |  | 
|   981   int _nextProbe(int previousIndex, int probeCount, int capacity) { |  | 
|   982     // When capacity is a power of 2, this probing algorithm (the triangular |  | 
|   983     // number sequence modulo capacity) is guaranteed to hit all indices exactly |  | 
|   984     // once before repeating. |  | 
|   985     return (previousIndex + probeCount) & (capacity - 1); |  | 
|   986   } |  | 
|   987  |  | 
|   988   /** Whether an object is a free-marker (either tombstone or free). */ |  | 
|   989   bool _isFree(Object marker) => |  | 
|   990       marker == null || identical(marker, _TOMBSTONE); |  | 
|   991  |  | 
|   992   /** |  | 
|   993    * Look up the offset for an object in the table. |  | 
|   994    * |  | 
|   995    * Finds the offset of the object in the table, if it is there, |  | 
|   996    * or the first free offset for its hashCode. |  | 
|   997    */ |  | 
|   998   int _probeForAdd(int hashCode, Object object) { |  | 
|   999     int entrySize = _entrySize; |  | 
|  1000     int index = _firstProbe(hashCode, _capacity); |  | 
|  1001     int firstTombstone = -1; |  | 
|  1002     int probeCount = 0; |  | 
|  1003     while (true) { |  | 
|  1004       int offset = index * entrySize; |  | 
|  1005       Object entry = _table[offset]; |  | 
|  1006       if (identical(entry, _TOMBSTONE)) { |  | 
|  1007         if (firstTombstone < 0) firstTombstone = offset; |  | 
|  1008       } else if (entry == null) { |  | 
|  1009         if (firstTombstone < 0) return offset; |  | 
|  1010         return firstTombstone; |  | 
|  1011       } else if (identical(_NULL, entry) ? _equals(null, object) |  | 
|  1012                                          : _equals(entry, object)) { |  | 
|  1013         return offset; |  | 
|  1014       } |  | 
|  1015       // The _nextProbe is designed so that it hits |  | 
|  1016       // every index eventually. |  | 
|  1017       index = _nextProbe(index, ++probeCount, _capacity); |  | 
|  1018     } |  | 
|  1019   } |  | 
|  1020  |  | 
|  1021   /** |  | 
|  1022    * Look up the offset for an object in the table. |  | 
|  1023    * |  | 
|  1024    * If the object is in the table, its offset is returned. |  | 
|  1025    * |  | 
|  1026    * If the object is not in the table, Otherwise a negative value is returned. |  | 
|  1027    */ |  | 
|  1028   int _probeForLookup(int hashCode, Object object) { |  | 
|  1029     int entrySize = _entrySize; |  | 
|  1030     int index = _firstProbe(hashCode, _capacity); |  | 
|  1031     int probeCount = 0; |  | 
|  1032     while (true) { |  | 
|  1033       int offset = index * entrySize; |  | 
|  1034       Object entry = _table[offset]; |  | 
|  1035       if (entry == null) { |  | 
|  1036         return -1; |  | 
|  1037       } else if (!identical(_TOMBSTONE, entry)) { |  | 
|  1038         if (identical(_NULL, entry) ? _equals(null, object) |  | 
|  1039                                     : _equals(entry, object)) { |  | 
|  1040           return offset; |  | 
|  1041         } |  | 
|  1042       } |  | 
|  1043       // The _nextProbe is designed so that it hits |  | 
|  1044       // every index eventually. |  | 
|  1045       index = _nextProbe(index, ++probeCount, _capacity); |  | 
|  1046     } |  | 
|  1047   } |  | 
|  1048  |  | 
|  1049   // Override the following two to change equality/hashCode computations |  | 
|  1050  |  | 
|  1051   /** |  | 
|  1052    * Compare two object for equality. |  | 
|  1053    * |  | 
|  1054    * The first object is the one already in the table, |  | 
|  1055    * and the second is the one being searched for. |  | 
|  1056    */ |  | 
|  1057   bool _equals(Object element, Object other) { |  | 
|  1058     return element == other; |  | 
|  1059   } |  | 
|  1060  |  | 
|  1061   /** |  | 
|  1062    * Compute hash-code for an object. |  | 
|  1063    */ |  | 
|  1064   int _hashCodeOf(Object object) => object.hashCode; |  | 
|  1065  |  | 
|  1066   /** |  | 
|  1067    * Ensure that the table isn't too full for its own good. |  | 
|  1068    * |  | 
|  1069    * Call this after adding an element. |  | 
|  1070    */ |  | 
|  1071   int _checkCapacity() { |  | 
|  1072     // Compute everything in multiples of entrySize to avoid division. |  | 
|  1073     int freeCount = _capacity - _entryCount; |  | 
|  1074     if (freeCount * 4 < _capacity || |  | 
|  1075         freeCount < _deletedCount) { |  | 
|  1076       // Less than 25% free or more deleted entries than free entries. |  | 
|  1077       _grow(_entryCount - _deletedCount); |  | 
|  1078     } |  | 
|  1079   } |  | 
|  1080  |  | 
|  1081   void _grow(int contentCount) { |  | 
|  1082     int capacity = _capacity; |  | 
|  1083     // Don't grow to less than twice the needed capacity. |  | 
|  1084     int minCapacity = contentCount * 2; |  | 
|  1085     while (capacity < minCapacity) { |  | 
|  1086       capacity *= 2; |  | 
|  1087     } |  | 
|  1088     // Reset to another table and add all existing elements. |  | 
|  1089     List oldTable = _table; |  | 
|  1090     _table = _createTable(capacity); |  | 
|  1091     _capacity = capacity; |  | 
|  1092     _entryCount = 0; |  | 
|  1093     _deletedCount = 0; |  | 
|  1094     _addAllEntries(oldTable); |  | 
|  1095     _recordModification(); |  | 
|  1096   } |  | 
|  1097  |  | 
|  1098   /** |  | 
|  1099    * Copies all non-free entries from the old table to the new empty table. |  | 
|  1100    */ |  | 
|  1101   void _addAllEntries(List oldTable) { |  | 
|  1102     for (int i = 0; i < oldTable.length; i += _entrySize) { |  | 
|  1103       Object object = oldTable[i]; |  | 
|  1104       if (!_isFree(object)) { |  | 
|  1105         int toOffset = _put(object); |  | 
|  1106         _copyEntry(oldTable, i, toOffset); |  | 
|  1107       } |  | 
|  1108     } |  | 
|  1109   } |  | 
|  1110  |  | 
|  1111   /** |  | 
|  1112    * Copies everything but the key element from one entry to another. |  | 
|  1113    * |  | 
|  1114    * Called while growing the base array. |  | 
|  1115    * |  | 
|  1116    * Override this if any non-key fields need copying. |  | 
|  1117    */ |  | 
|  1118   void _copyEntry(List fromTable, int fromOffset, int toOffset) {} |  | 
|  1119  |  | 
|  1120   // The following three methods are for simple get/set/remove operations. |  | 
|  1121   // They only affect the key of an entry. The remaining fields must be |  | 
|  1122   // filled by the caller. |  | 
|  1123  |  | 
|  1124   /** |  | 
|  1125    * Returns the offset of a key in [_table], or negative if it's not there. |  | 
|  1126    */ |  | 
|  1127   int _get(Object key) { |  | 
|  1128     return _probeForLookup(_hashCodeOf(key), key); |  | 
|  1129   } |  | 
|  1130  |  | 
|  1131   /** |  | 
|  1132    * Puts the key into the table and returns its offset into [_table]. |  | 
|  1133    * |  | 
|  1134    * If [_entrySize] is greater than 1, the caller should fill the |  | 
|  1135    * remaining fields. |  | 
|  1136    * |  | 
|  1137    * Remember to call [_checkCapacity] after using this method. |  | 
|  1138    */ |  | 
|  1139   int _put(K key) { |  | 
|  1140     int offset = _probeForAdd(_hashCodeOf(key), key); |  | 
|  1141     Object oldEntry = _table[offset]; |  | 
|  1142     if (oldEntry == null) { |  | 
|  1143       _entryCount++; |  | 
|  1144     } else if (identical(oldEntry, _TOMBSTONE)) { |  | 
|  1145       _deletedCount--; |  | 
|  1146     } else { |  | 
|  1147       return offset; |  | 
|  1148     } |  | 
|  1149     _setKey(offset, key); |  | 
|  1150     _recordModification(); |  | 
|  1151     return offset; |  | 
|  1152   } |  | 
|  1153  |  | 
|  1154   /** |  | 
|  1155    * Removes a key from the table and returns its offset into [_table]. |  | 
|  1156    * |  | 
|  1157    * Returns null if the key was not in the table. |  | 
|  1158    * If [_entrySize] is greater than 1, the caller should clean up the |  | 
|  1159    * remaining fields. |  | 
|  1160    */ |  | 
|  1161   int _remove(Object key) { |  | 
|  1162     int offset = _probeForLookup(_hashCodeOf(key), key); |  | 
|  1163     if (offset >= 0) { |  | 
|  1164       _deleteEntry(offset); |  | 
|  1165     } |  | 
|  1166     return offset; |  | 
|  1167   } |  | 
|  1168  |  | 
|  1169   /** Clears the table completely, leaving it empty. */ |  | 
|  1170   void _clear() { |  | 
|  1171     if (_elementCount == 0) return; |  | 
|  1172     for (int i = 0; i < _table.length; i++) { |  | 
|  1173       _table[i] = null; |  | 
|  1174     } |  | 
|  1175     _entryCount = _deletedCount = 0; |  | 
|  1176     _recordModification(); |  | 
|  1177   } |  | 
|  1178  |  | 
|  1179   /** Clears an entry in the table. */ |  | 
|  1180   void _deleteEntry(int offset) { |  | 
|  1181     assert(!_isFree(_table[offset])); |  | 
|  1182     _setKey(offset, _TOMBSTONE); |  | 
|  1183     _deletedCount++; |  | 
|  1184     _recordModification(); |  | 
|  1185   } |  | 
|  1186 } |  | 
|  1187  |  | 
|  1188 /** |  | 
|  1189  * Generic iterable based on a [_HashTable]. |  | 
|  1190  */ |  | 
|  1191 abstract class _HashTableIterable<E> extends IterableBase<E> { |  | 
|  1192   final _HashTable _hashTable; |  | 
|  1193   _HashTableIterable(this._hashTable); |  | 
|  1194  |  | 
|  1195   Iterator<E> get iterator; |  | 
|  1196  |  | 
|  1197   /** |  | 
|  1198    * Return the iterated value for a given entry. |  | 
|  1199    */ |  | 
|  1200   E _valueAt(int offset, Object key); |  | 
|  1201  |  | 
|  1202   int get length => _hashTable._elementCount; |  | 
|  1203  |  | 
|  1204   bool get isEmpty => _hashTable._elementCount == 0; |  | 
|  1205  |  | 
|  1206   void forEach(void action(E element)) { |  | 
|  1207     int entrySize = _hashTable._entrySize; |  | 
|  1208     List table = _hashTable._table; |  | 
|  1209     int modificationCount = _hashTable._modificationCount; |  | 
|  1210     for (int offset = 0; offset < table.length; offset += entrySize) { |  | 
|  1211       Object entry = table[offset]; |  | 
|  1212       if (!_hashTable._isFree(entry)) { |  | 
|  1213         E value = _valueAt(offset, entry); |  | 
|  1214         action(value); |  | 
|  1215       } |  | 
|  1216       _hashTable._checkModification(modificationCount); |  | 
|  1217     } |  | 
|  1218   } |  | 
|  1219 } |  | 
|  1220  |  | 
|  1221 abstract class _HashTableIterator<E> implements Iterator<E> { |  | 
|  1222   final _HashTable _hashTable; |  | 
|  1223   final int _modificationCount; |  1187   final int _modificationCount; | 
|  1224   /** Location right after last found element. */ |  1188   var _next; | 
|  1225   int _offset = 0; |  1189   E _current; | 
|  1226   E _current = null; |  1190  | 
|  1227  |  1191   _LinkedHashSetIterator(_LinkedHashSet hashSet) | 
|  1228   _HashTableIterator(_HashTable hashTable) |  1192       : _set = hashSet, | 
|  1229       : _hashTable = hashTable, |  1193         _modificationCount = hashSet._modificationCount, | 
|  1230         _modificationCount = hashTable._modificationCount; |  1194         _next = hashSet._nextEntry; | 
|  1231  |  1195  | 
|  1232   bool moveNext() { |  1196   bool moveNext() { | 
|  1233     _hashTable._checkModification(_modificationCount); |  1197     if (_modificationCount != _set._modificationCount) { | 
|  1234  |  1198       throw new ConcurrentModificationError(_set); | 
|  1235     List table = _hashTable._table; |  1199     } | 
|  1236     int entrySize = _hashTable._entrySize; |  1200     if (identical(_set, _next)) { | 
|  1237  |  | 
|  1238     while (_offset < table.length) { |  | 
|  1239       int currentOffset = _offset; |  | 
|  1240       Object entry = table[currentOffset]; |  | 
|  1241       _offset = currentOffset + entrySize; |  | 
|  1242       if (!_hashTable._isFree(entry)) { |  | 
|  1243         _current = _valueAt(currentOffset, entry); |  | 
|  1244         return true; |  | 
|  1245       } |  | 
|  1246     } |  | 
|  1247     _current = null; |  | 
|  1248     return false; |  | 
|  1249   } |  | 
|  1250  |  | 
|  1251   E get current => _current; |  | 
|  1252  |  | 
|  1253   E _valueAt(int offset, Object key); |  | 
|  1254 } |  | 
|  1255  |  | 
|  1256 class _HashTableKeyIterable<K> extends _HashTableIterable<K> { |  | 
|  1257   _HashTableKeyIterable(_HashTable<K> hashTable) : super(hashTable); |  | 
|  1258  |  | 
|  1259   Iterator<K> get iterator => new _HashTableKeyIterator<K>(_hashTable); |  | 
|  1260  |  | 
|  1261   K _valueAt(int offset, Object key) { |  | 
|  1262     if (identical(key, _NULL)) return null; |  | 
|  1263     return key; |  | 
|  1264   } |  | 
|  1265  |  | 
|  1266   bool contains(Object value) => _hashTable._get(value) >= 0; |  | 
|  1267 } |  | 
|  1268  |  | 
|  1269 class _HashTableKeyIterator<K> extends _HashTableIterator<K> { |  | 
|  1270   _HashTableKeyIterator(_HashTable hashTable) : super(hashTable); |  | 
|  1271  |  | 
|  1272   K _valueAt(int offset, Object key) { |  | 
|  1273     if (identical(key, _NULL)) return null; |  | 
|  1274     return key; |  | 
|  1275   } |  | 
|  1276 } |  | 
|  1277  |  | 
|  1278 class _HashTableValueIterable<V> extends _HashTableIterable<V> { |  | 
|  1279   final int _entryIndex; |  | 
|  1280  |  | 
|  1281   _HashTableValueIterable(_HashTable hashTable, this._entryIndex) |  | 
|  1282       : super(hashTable); |  | 
|  1283  |  | 
|  1284   Iterator<V> get iterator { |  | 
|  1285     return new _HashTableValueIterator<V>(_hashTable, _entryIndex); |  | 
|  1286   } |  | 
|  1287  |  | 
|  1288   V _valueAt(int offset, Object key) => _hashTable._table[offset + _entryIndex]; |  | 
|  1289 } |  | 
|  1290  |  | 
|  1291 class _HashTableValueIterator<V> extends _HashTableIterator<V> { |  | 
|  1292   final int _entryIndex; |  | 
|  1293  |  | 
|  1294   _HashTableValueIterator(_HashTable hashTable, this._entryIndex) |  | 
|  1295       : super(hashTable); |  | 
|  1296  |  | 
|  1297   V _valueAt(int offset, Object key) => _hashTable._table[offset + _entryIndex]; |  | 
|  1298 } |  | 
|  1299  |  | 
|  1300 class _HashMapTable<K, V> extends _HashTable<K> { |  | 
|  1301   static const int _INITIAL_CAPACITY = 8; |  | 
|  1302   static const int _VALUE_INDEX = 1; |  | 
|  1303  |  | 
|  1304   _HashMapTable() : super(_INITIAL_CAPACITY); |  | 
|  1305  |  | 
|  1306   int get _entrySize => 2; |  | 
|  1307  |  | 
|  1308   V _value(int offset) => _table[offset + _VALUE_INDEX]; |  | 
|  1309   void _setValue(int offset, V value) { _table[offset + _VALUE_INDEX] = value; } |  | 
|  1310  |  | 
|  1311   _copyEntry(List fromTable, int fromOffset, int toOffset) { |  | 
|  1312     _table[toOffset + _VALUE_INDEX] = fromTable[fromOffset + _VALUE_INDEX]; |  | 
|  1313   } |  | 
|  1314 } |  | 
|  1315  |  | 
|  1316 /** Unique marker object for the head of a linked list of entries. */ |  | 
|  1317 class _LinkedHashTableHeadMarker { |  | 
|  1318   const _LinkedHashTableHeadMarker(); |  | 
|  1319 } |  | 
|  1320  |  | 
|  1321 const _LinkedHashTableHeadMarker _HEAD_MARKER = |  | 
|  1322     const _LinkedHashTableHeadMarker(); |  | 
|  1323  |  | 
|  1324 class _LinkedHashTable<K> extends _HashTable<K> { |  | 
|  1325   static const _NEXT_INDEX = 1; |  | 
|  1326   static const _PREV_INDEX = 2; |  | 
|  1327   static const _HEAD_OFFSET = 0; |  | 
|  1328  |  | 
|  1329   _LinkedHashTable(int initialCapacity) : super(initialCapacity); |  | 
|  1330  |  | 
|  1331   int get _entrySize => 3; |  | 
|  1332  |  | 
|  1333   List _createTable(int capacity) { |  | 
|  1334     List result = new List(capacity * _entrySize); |  | 
|  1335     result[_HEAD_OFFSET] = _HEAD_MARKER; |  | 
|  1336     result[_HEAD_OFFSET + _NEXT_INDEX] = _HEAD_OFFSET; |  | 
|  1337     result[_HEAD_OFFSET + _PREV_INDEX] = _HEAD_OFFSET; |  | 
|  1338     return result; |  | 
|  1339   } |  | 
|  1340  |  | 
|  1341   int _next(int offset) => _table[offset + _NEXT_INDEX]; |  | 
|  1342   void _setNext(int offset, int to) { _table[offset + _NEXT_INDEX] = to; } |  | 
|  1343  |  | 
|  1344   int _prev(int offset) => _table[offset + _PREV_INDEX]; |  | 
|  1345   void _setPrev(int offset, int to) { _table[offset + _PREV_INDEX] = to; } |  | 
|  1346  |  | 
|  1347   void _linkLast(int offset) { |  | 
|  1348     // Add entry at offset at end of double-linked list. |  | 
|  1349     int last = _prev(_HEAD_OFFSET); |  | 
|  1350     _setNext(offset, _HEAD_OFFSET); |  | 
|  1351     _setPrev(offset, last); |  | 
|  1352     _setNext(last, offset); |  | 
|  1353     _setPrev(_HEAD_OFFSET, offset); |  | 
|  1354   } |  | 
|  1355  |  | 
|  1356   void _unlink(int offset) { |  | 
|  1357     assert(offset != _HEAD_OFFSET); |  | 
|  1358     int next = _next(offset); |  | 
|  1359     int prev = _prev(offset); |  | 
|  1360     _setNext(offset, null); |  | 
|  1361     _setPrev(offset, null); |  | 
|  1362     _setNext(prev, next); |  | 
|  1363     _setPrev(next, prev); |  | 
|  1364   } |  | 
|  1365  |  | 
|  1366   /** |  | 
|  1367    * Copies all non-free entries from the old table to the new empty table. |  | 
|  1368    */ |  | 
|  1369   void _addAllEntries(List oldTable) { |  | 
|  1370     int offset = oldTable[_HEAD_OFFSET + _NEXT_INDEX]; |  | 
|  1371     while (offset != _HEAD_OFFSET) { |  | 
|  1372       Object object = oldTable[offset]; |  | 
|  1373       int nextOffset = oldTable[offset + _NEXT_INDEX]; |  | 
|  1374       int toOffset = _put(object); |  | 
|  1375       _copyEntry(oldTable, offset, toOffset); |  | 
|  1376       offset = nextOffset; |  | 
|  1377     } |  | 
|  1378   } |  | 
|  1379  |  | 
|  1380   void _clear() { |  | 
|  1381     if (_elementCount == 0) return; |  | 
|  1382     _setNext(_HEAD_OFFSET, _HEAD_OFFSET); |  | 
|  1383     _setPrev(_HEAD_OFFSET, _HEAD_OFFSET); |  | 
|  1384     for (int i = _entrySize; i < _table.length; i++) { |  | 
|  1385       _table[i] = null; |  | 
|  1386     } |  | 
|  1387     _entryCount = _deletedCount = 0; |  | 
|  1388     _recordModification(); |  | 
|  1389   } |  | 
|  1390  |  | 
|  1391   int _put(K key) { |  | 
|  1392     int offset = _probeForAdd(_hashCodeOf(key), key); |  | 
|  1393     Object oldEntry = _table[offset]; |  | 
|  1394     if (identical(oldEntry, _TOMBSTONE)) { |  | 
|  1395       _deletedCount--; |  | 
|  1396     } else if (oldEntry == null) { |  | 
|  1397       _entryCount++; |  | 
|  1398     } else { |  | 
|  1399       return offset; |  | 
|  1400     } |  | 
|  1401     _recordModification(); |  | 
|  1402     _setKey(offset, key); |  | 
|  1403     _linkLast(offset); |  | 
|  1404     return offset; |  | 
|  1405   } |  | 
|  1406  |  | 
|  1407   void _deleteEntry(int offset) { |  | 
|  1408     _unlink(offset); |  | 
|  1409     _setKey(offset, _TOMBSTONE); |  | 
|  1410     _deletedCount++; |  | 
|  1411     _recordModification(); |  | 
|  1412   } |  | 
|  1413 } |  | 
|  1414  |  | 
|  1415 class _LinkedHashTableKeyIterable<K> extends IterableBase<K> { |  | 
|  1416   final _LinkedHashTable<K> _table; |  | 
|  1417   _LinkedHashTableKeyIterable(this._table); |  | 
|  1418   Iterator<K> get iterator => new _LinkedHashTableKeyIterator<K>(_table); |  | 
|  1419  |  | 
|  1420   bool contains(Object value) => _table._get(value) >= 0; |  | 
|  1421  |  | 
|  1422   int get length => _table._elementCount; |  | 
|  1423 } |  | 
|  1424  |  | 
|  1425 class _LinkedHashTableKeyIterator<K> extends _LinkedHashTableIterator<K> { |  | 
|  1426   _LinkedHashTableKeyIterator(_LinkedHashTable<K> hashTable): super(hashTable); |  | 
|  1427  |  | 
|  1428   K _getCurrent(int offset) => _hashTable._key(offset); |  | 
|  1429 } |  | 
|  1430  |  | 
|  1431 class _LinkedHashTableValueIterable<V> extends IterableBase<V> { |  | 
|  1432   final _LinkedHashTable _hashTable; |  | 
|  1433   final int _valueIndex; |  | 
|  1434   _LinkedHashTableValueIterable(this._hashTable, this._valueIndex); |  | 
|  1435   Iterator<V> get iterator => |  | 
|  1436       new _LinkedHashTableValueIterator<V>(_hashTable, _valueIndex); |  | 
|  1437   int get length => _hashTable._elementCount; |  | 
|  1438 } |  | 
|  1439  |  | 
|  1440 class _LinkedHashTableValueIterator<V> extends _LinkedHashTableIterator<V> { |  | 
|  1441   final int _valueIndex; |  | 
|  1442  |  | 
|  1443   _LinkedHashTableValueIterator(_LinkedHashTable hashTable, this._valueIndex) |  | 
|  1444       : super(hashTable); |  | 
|  1445  |  | 
|  1446   V _getCurrent(int offset) => _hashTable._table[offset + _valueIndex]; |  | 
|  1447 } |  | 
|  1448  |  | 
|  1449 abstract class _LinkedHashTableIterator<T> implements Iterator<T> { |  | 
|  1450   final _LinkedHashTable _hashTable; |  | 
|  1451   final int _modificationCount; |  | 
|  1452   int _offset; |  | 
|  1453   T _current; |  | 
|  1454  |  | 
|  1455   _LinkedHashTableIterator(_LinkedHashTable table) |  | 
|  1456       : _hashTable = table, |  | 
|  1457         _modificationCount = table._modificationCount, |  | 
|  1458         _offset = table._next(_LinkedHashTable._HEAD_OFFSET); |  | 
|  1459  |  | 
|  1460   bool moveNext() { |  | 
|  1461     _hashTable._checkModification(_modificationCount); |  | 
|  1462     if (_offset == _LinkedHashTable._HEAD_OFFSET) { |  | 
|  1463       _current = null; |  1201       _current = null; | 
|  1464       return false; |  1202       return false; | 
|  1465     } |  1203     } | 
|  1466     _current = _getCurrent(_offset); |  1204     _LinkedHashSetEntry entry = _next; | 
|  1467     _offset = _hashTable._next(_offset); |  1205     _current = entry.key; | 
 |  1206     _next = entry._nextEntry; | 
|  1468     return true; |  1207     return true; | 
|  1469   } |  1208   } | 
|  1470  |  1209  | 
|  1471   T _getCurrent(int offset); |  1210   E get current => _current; | 
|  1472  |  1211 } | 
|  1473   T get current => _current; |  | 
|  1474 } |  | 
|  1475  |  | 
|  1476 class _LinkedHashMapTable<K, V> extends _LinkedHashTable<K> { |  | 
|  1477   static const int _INITIAL_CAPACITY = 8; |  | 
|  1478   static const int _VALUE_INDEX = 3; |  | 
|  1479  |  | 
|  1480   int get _entrySize => 4; |  | 
|  1481  |  | 
|  1482   _LinkedHashMapTable() : super(_INITIAL_CAPACITY); |  | 
|  1483  |  | 
|  1484   V _value(int offset) => _table[offset + _VALUE_INDEX]; |  | 
|  1485   void _setValue(int offset, V value) { _table[offset + _VALUE_INDEX] = value; } |  | 
|  1486  |  | 
|  1487   _copyEntry(List oldTable, int fromOffset, int toOffset) { |  | 
|  1488     _table[toOffset + _VALUE_INDEX] = oldTable[fromOffset + _VALUE_INDEX]; |  | 
|  1489   } |  | 
|  1490 } |  | 
| OLD | NEW |