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

Unified Diff: runtime/lib/collection_patch.dart

Issue 23494027: Make LinkedHashMap also have a factory constructor and be customizable (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 7 years, 3 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 side-by-side diff with in-line comments
Download patch
Index: runtime/lib/collection_patch.dart
diff --git a/runtime/lib/collection_patch.dart b/runtime/lib/collection_patch.dart
index 3b3bcc089f41ee5237c695fff916420420072575..b344c7f500b9fc3abbce522a5e348ffc622fda18 100644
--- a/runtime/lib/collection_patch.dart
+++ b/runtime/lib/collection_patch.dart
@@ -7,7 +7,7 @@ patch class HashMap<K, V> {
int hashCode(K key) }) {
if (hashCode == null) {
if (equals == null) {
- return new _HashMapImpl<K, V>();
+ return new _HashMap<K, V>();
}
if (identical(identical, equals)) {
return new _IdentityHashMap<K, V>();
@@ -22,7 +22,7 @@ patch class HashMap<K, V> {
const int _MODIFICATION_COUNT_MASK = 0x3fffffff;
-class _HashMapImpl<K, V> implements HashMap<K, V> {
+class _HashMap<K, V> implements HashMap<K, V> {
static const int _INITIAL_CAPACITY = 8;
int _elementCount = 0;
@@ -201,7 +201,7 @@ class _HashMapImpl<K, V> implements HashMap<K, V> {
String toString() => Maps.mapToString(this);
}
-class _CustomHashMap<K, V> extends _HashMapImpl<K, V> {
+class _CustomHashMap<K, V> extends _HashMap<K, V> {
final _Equality<K> _equals;
final _Hasher<K> _hashCode;
_CustomHashMap(this._equals, this._hashCode);
@@ -298,7 +298,7 @@ class _CustomHashMap<K, V> extends _HashMapImpl<K, V> {
String toString() => Maps.mapToString(this);
}
-class _IdentityHashMap<K, V> extends _HashMapImpl<K, V> {
+class _IdentityHashMap<K, V> extends _HashMap<K, V> {
bool containsKey(Object key) {
int hashCode = key.hashCode;
List buckets = _buckets;
@@ -596,11 +596,11 @@ class _LinkedHashMapValueIterable<V> extends IterableBase<V> {
}
abstract class _LinkedHashMapIterator<T> implements Iterator<T> {
- final _LinkedHashMap _map;
+ final LinkedHashMap _map;
var _next;
T _current;
int _modificationCount;
- _LinkedHashMapIterator(_LinkedHashMap map)
+ _LinkedHashMapIterator(LinkedHashMap map)
: _map = map,
_current = null,
_next = map._nextEntry,
@@ -626,12 +626,12 @@ abstract class _LinkedHashMapIterator<T> implements Iterator<T> {
}
class _LinkedHashMapKeyIterator<K> extends _LinkedHashMapIterator<K> {
- _LinkedHashMapKeyIterator(_LinkedHashMap map) : super(map);
+ _LinkedHashMapKeyIterator(LinkedHashMap map) : super(map);
K _getValue(_LinkedHashMapEntry entry) => entry.key;
}
class _LinkedHashMapValueIterator<V> extends _LinkedHashMapIterator<V> {
- _LinkedHashMapValueIterator(_LinkedHashMap map) : super(map);
+ _LinkedHashMapValueIterator(LinkedHashMap map) : super(map);
V _getValue(_LinkedHashMapEntry entry) => entry.value;
}
@@ -640,130 +640,246 @@ class _LinkedHashMapValueIterator<V> extends _LinkedHashMapIterator<V> {
* A hash-based map that iterates keys and values in key insertion order.
*/
patch class LinkedHashMap<K, V> {
- static const int _INITIAL_CAPACITY = 8;
- static const int _MODIFICATION_COUNT_MASK = 0x3fffffff;
+ var _nextEntry;
+ var _previousEntry;
- int _elementCount = 0;
- List<_HashMapEntry> _buckets = new List(_INITIAL_CAPACITY);
- int _modificationCount = 0;
+ /* patch */ factory LinkedHashMap({ bool equals(K key1, K key2),
+ int hashCode(K key) }) {
+ if (hashCode == null) {
+ if (equals == null) {
+ return new _LinkedHashMap<K, V>();
+ }
+ if (identical(identical, equals)) {
+ return new _LinkedIdentityHashMap<K, V>();
+ }
+ hashCode = _defaultHashCode;
+ } else if (equals == null) {
+ equals = _defaultEquals;
+ }
+ return new _LinkedCustomHashMap<K, V>(equals, hashCode);
+ }
+}
+class _LinkedHashMap<K, V> extends _HashMap<K, V>
+ implements LinkedHashMap<K, V> {
floitsch 2013/09/05 13:44:28 nit: indentation.
Lasse Reichstein Nielsen 2013/09/06 08:49:24 Done.
var _nextEntry;
var _previousEntry;
- /* patch */ LinkedHashMap() {
+ _LinkedHashMap() {
_nextEntry = _previousEntry = this;
}
- /* patch */ int get length => _elementCount;
- /* patch */ bool get isEmpty => _elementCount == 0;
- /* patch */ bool get isNotEmpty => _elementCount != 0;
-
- /* patch */ Iterable<K> get keys => new _LinkedHashMapKeyIterable<K>(this);
- /* patch */ Iterable<V> get values => new _LinkedHashMapValueIterable<V>(this);
-
- /* patch */ bool containsKey(Object key) {
- int hashCode = key.hashCode;
- List buckets = _buckets;
- int index = hashCode & (buckets.length - 1);
- _HashMapEntry entry = buckets[index];
- while (entry != null) {
- if (hashCode == entry.hashCode && entry.key == key) return true;
- entry = entry.next;
+ bool containsValue(Object value) {
+ int modificationCount = _modificationCount;
+ var cursor = _nextEntry;
+ while (!identical(cursor, this)) {
+ _HashMapEntry entry = cursor;
+ if (entry.value == value) return true;
+ if (modificationCount != _modificationCount) {
+ throw new ConcurrentModificationError(this);
+ }
+ cursor = cursor._nextEntry;
}
return false;
}
- /* patch */ bool containsValue(Object value) {
- var cursor = _nextEntry;
+ void forEach(void action(K key, V value)) {
int modificationCount = _modificationCount;
+ var cursor = _nextEntry;
while (!identical(cursor, this)) {
_HashMapEntry entry = cursor;
- if (entry.value == value) return true;
+ action(entry.key, entry.value);
+ if (modificationCount != _modificationCount) {
+ throw new ConcurrentModificationError(this);
+ }
cursor = cursor._nextEntry;
}
- return false;
}
- /* patch */ V operator[](Object key) {
+ /* patch */ V remove(Object key) {
int hashCode = key.hashCode;
List buckets = _buckets;
int index = hashCode & (buckets.length - 1);
- _HashMapEntry entry = buckets[index];
+ _LinkedHashMapEntry entry = buckets[index];
+ _HashMapEntry previous = null;
while (entry != null) {
+ _HashMapEntry next = entry.next;
if (hashCode == entry.hashCode && entry.key == key) {
+ if (previous == null) {
+ buckets[index] = next;
+ } else {
+ previous.next = next;
+ }
+ entry._previousEntry._nextEntry = entry._nextEntry;
floitsch 2013/09/05 13:44:28 As usual: I prefer temporary variables: previous =
floitsch 2013/09/05 13:44:28 Starting at this line this code is the same for al
Lasse Reichstein Nielsen 2013/09/06 08:49:24 Similar code. It may differ on equality and hashco
+ entry._nextEntry._previousEntry = entry._previousEntry;
+ entry._nextEntry = entry._previousEntry = null;
+ _elementCount--;
+ _modificationCount =
+ (_modificationCount + 1) & _MODIFICATION_COUNT_MASK;
return entry.value;
}
- entry = entry.next;
+ previous = entry;
+ entry = next;
}
return null;
}
- /* patch */ void operator []=(K key, V value) {
- int hashCode = key.hashCode;
- List buckets = _buckets;
- int length = buckets.length;
- int index = hashCode & (length - 1);
- _HashMapEntry entry = buckets[index];
- while (entry != null) {
- if (hashCode == entry.hashCode && entry.key == key) {
- entry.value = value;
- return;
+ void clear() {
+ _nextEntry = _previousEntry = this;
+ super.clear();
+ }
+
+ void _addEntry(List buckets, int index, int length,
floitsch 2013/09/05 13:44:28 same code too. right?
Lasse Reichstein Nielsen 2013/09/06 08:49:24 Exactly same code in all three sub-classes, yes.
+ K key, V value, int hashCode) {
+ _HashMapEntry entry =
+ new _LinkedHashMapEntry(key, value, hashCode, buckets[index],
+ _previousEntry, this);
+ buckets[index] = entry;
+ int newElements = _elementCount + 1;
+ _elementCount = newElements;
+ // If we end up with more than 75% non-empty entries, we
+ // resize the backing store.
+ if ((newElements << 2) > ((length << 1) + length)) _resize();
+ _modificationCount = (_modificationCount + 1) & _MODIFICATION_COUNT_MASK;
+ }
+
+ Iterable<K> get keys => new _LinkedHashMapKeyIterable<K>(this);
+ Iterable<V> get values => new _LinkedHashMapValueIterable<V>(this);
+}
+
+class _LinkedIdentityHashMap<K, V> extends _IdentityHashMap<K, V>
+ implements LinkedHashMap<K, V> {
+ var _nextEntry;
+ var _previousEntry;
+
+ _LinkedIdentityHashMap() {
+ _nextEntry = _previousEntry = this;
+ }
+
+ bool containsValue(Object value) {
+ int modificationCount = _modificationCount;
+ var cursor = _nextEntry;
+ while (!identical(cursor, this)) {
+ _HashMapEntry entry = cursor;
+ if (entry.value == value) return true;
+ if (modificationCount != _modificationCount) {
+ throw new ConcurrentModificationError(this);
}
- entry = entry.next;
+ cursor = cursor._nextEntry;
+ }
+ return false;
+ }
+
+ void forEach(void action(K key, V value)) {
+ int modificationCount = _modificationCount;
+ var cursor = _nextEntry;
+ while (!identical(cursor, this)) {
+ _HashMapEntry entry = cursor;
+ action(entry.key, entry.value);
+ if (modificationCount != _modificationCount) {
+ throw new ConcurrentModificationError(this);
+ }
+ cursor = cursor._nextEntry;
}
- _addEntry(buckets, index, length, key, value, hashCode);
}
- /* patch */ V putIfAbsent(K key, V ifAbsent()) {
+ V remove(Object key) {
int hashCode = key.hashCode;
List buckets = _buckets;
- int length = buckets.length;
- int index = hashCode & (length - 1);
- _HashMapEntry entry = buckets[index];
+ int index = hashCode & (buckets.length - 1);
+ _LinkedHashMapEntry entry = buckets[index];
+ _HashMapEntry previous = null;
while (entry != null) {
- if (hashCode == entry.hashCode && entry.key == key) {
+ _HashMapEntry next = entry.next;
+ if (hashCode == entry.hashCode && identical(entry.key, key)) {
+ if (previous == null) {
+ buckets[index] = next;
+ } else {
+ previous.next = next;
+ }
+ entry._previousEntry._nextEntry = entry._nextEntry;
floitsch 2013/09/05 13:44:28 temporary variables.
Lasse Reichstein Nielsen 2013/09/06 08:49:24 Done.
+ entry._nextEntry._previousEntry = entry._previousEntry;
+ entry._nextEntry = entry._previousEntry = null;
+ _elementCount--;
+ _modificationCount =
+ (_modificationCount + 1) & _MODIFICATION_COUNT_MASK;
return entry.value;
}
- entry = entry.next;
- }
- int stamp = _modificationCount;
- V value = ifAbsent();
- if (stamp == _modificationCount) {
- _addEntry(buckets, index, length, key, value, hashCode);
- } else {
- this[key] = value;
+ previous = entry;
+ entry = next;
}
- return value;
+ return null;
}
- /* patch */ void addAll(Map<K, V> other) {
- other.forEach((K key, V value) {
- this[key] = value;
- });
+ void clear() {
+ _nextEntry = _previousEntry = this;
+ super.clear();
}
- /* patch */ void forEach(void action(K key, V value)) {
- int stamp = _modificationCount;
+ void _addEntry(List buckets, int index, int length,
+ K key, V value, int hashCode) {
+ buckets[index] =
+ new _LinkedHashMapEntry(key, value, hashCode, buckets[index],
+ _previousEntry, this);
+ int newElements = _elementCount + 1;
+ _elementCount = newElements;
+ // If we end up with more than 75% non-empty entries, we
+ // resize the backing store.
+ if ((newElements << 2) > ((length << 1) + length)) _resize();
+ _modificationCount = (_modificationCount + 1) & _MODIFICATION_COUNT_MASK;
+ }
+
+ Iterable<K> get keys => new _LinkedHashMapKeyIterable<K>(this);
+ Iterable<V> get values => new _LinkedHashMapValueIterable<V>(this);
+}
+
+class _LinkedCustomHashMap<K, V> extends _CustomHashMap<K, V>
+ implements LinkedHashMap<K, V> {
+ var _nextEntry;
+ var _previousEntry;
+
+ _LinkedCustomHashMap(bool equals(K key1, K key2),
+ int hashCode(K key))
+ : super(equals, hashCode) {
+ _nextEntry = _previousEntry = this;
+ }
+
+ bool containsValue(Object value) {
+ int modificationCount = _modificationCount;
+ var cursor = _nextEntry;
+ while (!identical(cursor, this)) {
+ _HashMapEntry entry = cursor;
+ if (entry.value == value) return true;
+ if (modificationCount != _modificationCount) {
+ throw new ConcurrentModificationError(this);
+ }
+ cursor = cursor._nextEntry;
+ }
+ return false;
+ }
+
+ void forEach(void action(K key, V value)) {
+ int modificationCount = _modificationCount;
var cursor = _nextEntry;
while (!identical(cursor, this)) {
_HashMapEntry entry = cursor;
action(entry.key, entry.value);
- if (stamp != _modificationCount) {
+ if (modificationCount != _modificationCount) {
throw new ConcurrentModificationError(this);
}
cursor = cursor._nextEntry;
}
}
- /* patch */ V remove(Object key) {
- int hashCode = key.hashCode;
+ V remove(Object key) {
+ int hashCode = _hashCode(key);
List buckets = _buckets;
int index = hashCode & (buckets.length - 1);
_LinkedHashMapEntry entry = buckets[index];
_HashMapEntry previous = null;
while (entry != null) {
_HashMapEntry next = entry.next;
- if (hashCode == entry.hashCode && entry.key == key) {
+ if (hashCode == entry.hashCode && _equals(entry.key, key)) {
if (previous == null) {
buckets[index] = next;
} else {
@@ -783,19 +899,16 @@ patch class LinkedHashMap<K, V> {
return null;
}
- /* patch */ void clear() {
- _elementCount = 0;
+ void clear() {
_nextEntry = _previousEntry = this;
- _buckets = new List(_INITIAL_CAPACITY);
- _modificationCount = (_modificationCount + 1) & _MODIFICATION_COUNT_MASK;
+ super.clear();
}
void _addEntry(List buckets, int index, int length,
K key, V value, int hashCode) {
- _HashMapEntry entry =
+ buckets[index] =
new _LinkedHashMapEntry(key, value, hashCode, buckets[index],
_previousEntry, this);
- buckets[index] = entry;
int newElements = _elementCount + 1;
_elementCount = newElements;
// If we end up with more than 75% non-empty entries, we
@@ -804,26 +917,11 @@ patch class LinkedHashMap<K, V> {
_modificationCount = (_modificationCount + 1) & _MODIFICATION_COUNT_MASK;
}
- void _resize() {
- List oldBuckets = _buckets;
- int oldLength = oldBuckets.length;
- int newLength = oldLength << 1;
- List newBuckets = new List(newLength);
- for (int i = 0; i < oldLength; i++) {
- _HashMapEntry entry = oldBuckets[i];
- while (entry != null) {
- _HashMapEntry next = entry.next;
- int hashCode = entry.hashCode;
- int index = hashCode & (newLength - 1);
- entry.next = newBuckets[index];
- newBuckets[index] = entry;
- entry = next;
- }
- }
- _buckets = newBuckets;
- }
+ Iterable<K> get keys => new _LinkedHashMapKeyIterable<K>(this);
+ Iterable<V> get values => new _LinkedHashMapValueIterable<V>(this);
}
+
patch class LinkedHashSet<E> extends _HashSetBase<E> {
static const int _INITIAL_CAPACITY = 8;
_LinkedHashTable<E> _table;

Powered by Google App Engine
This is Rietveld 408576698