Index: runtime/lib/collection_patch.dart |
diff --git a/runtime/lib/collection_patch.dart b/runtime/lib/collection_patch.dart |
index 5bd4ab93657d4ff5f096a3ecdd303661da79e104..f78951f4374bbc044f0dd9df88e391f25985c694 100644 |
--- a/runtime/lib/collection_patch.dart |
+++ b/runtime/lib/collection_patch.dart |
@@ -3,23 +3,40 @@ |
// BSD-style license that can be found in the LICENSE file. |
patch class HashMap<K, V> { |
+ /* patch */ factory HashMap({ bool equals(K key1, K key2), |
+ int hashCode(K key) }) { |
+ if (hashCode == null) { |
+ if (equals == null) { |
+ return new _HashMapImpl<K, V>(); |
+ } |
+ if (identical(identical, equals)) { |
+ return new _IdentityHashMap<K, V>(); |
+ } |
+ hashCode = _defaultHashCode; |
+ } else if (equals == null) { |
+ equals = _defaultEquals; |
+ } |
+ return new _CustomHashMap<K, V>(equals, hashCode); |
+ } |
+} |
+ |
+const int _MODIFICATION_COUNT_MASK = 0x3fffffff; |
+ |
+class _HashMapImpl<K, V> implements HashMap<K, V> { |
static const int _INITIAL_CAPACITY = 8; |
- static const int _MODIFICATION_COUNT_MASK = 0x3fffffff; |
int _elementCount = 0; |
List<_HashMapEntry> _buckets = new List(_INITIAL_CAPACITY); |
int _modificationCount = 0; |
- /* patch */ HashMap._internal(); |
- |
- /* patch */ int get length => _elementCount; |
- /* patch */ bool get isEmpty => _elementCount == 0; |
- /* patch */ bool get isNotEmpty => _elementCount != 0; |
+ int get length => _elementCount; |
+ bool get isEmpty => _elementCount == 0; |
+ bool get isNotEmpty => _elementCount != 0; |
- /* patch */ Iterable<K> get keys => new _HashMapKeyIterable<K>(this); |
- /* patch */ Iterable<V> get values => new _HashMapValueIterable<V>(this); |
+ Iterable<K> get keys => new _HashMapKeyIterable<K>(this); |
+ Iterable<V> get values => new _HashMapValueIterable<V>(this); |
- /* patch */ bool containsKey(Object key) { |
+ bool containsKey(Object key) { |
int hashCode = key.hashCode; |
List buckets = _buckets; |
int index = hashCode & (buckets.length - 1); |
@@ -31,7 +48,7 @@ patch class HashMap<K, V> { |
return false; |
} |
- /* patch */ bool containsValue(Object value) { |
+ bool containsValue(Object value) { |
List buckets = _buckets; |
int length = buckets.length; |
for (int i = 0; i < length; i++) { |
@@ -44,7 +61,7 @@ patch class HashMap<K, V> { |
return false; |
} |
- /* patch */ V operator[](Object key) { |
+ V operator[](Object key) { |
int hashCode = key.hashCode; |
List buckets = _buckets; |
int index = hashCode & (buckets.length - 1); |
@@ -58,7 +75,7 @@ patch class HashMap<K, V> { |
return null; |
} |
- /* patch */ void operator []=(K key, V value) { |
+ void operator []=(K key, V value) { |
int hashCode = key.hashCode; |
List buckets = _buckets; |
int length = buckets.length; |
@@ -74,7 +91,7 @@ patch class HashMap<K, V> { |
_addEntry(buckets, index, length, key, value, hashCode); |
} |
- /* patch */ V putIfAbsent(K key, V ifAbsent()) { |
+ V putIfAbsent(K key, V ifAbsent()) { |
int hashCode = key.hashCode; |
List buckets = _buckets; |
int length = buckets.length; |
@@ -96,13 +113,13 @@ patch class HashMap<K, V> { |
return value; |
} |
- /* patch */ void addAll(Map<K, V> other) { |
+ void addAll(Map<K, V> other) { |
other.forEach((K key, V value) { |
this[key] = value; |
}); |
} |
- /* patch */ void forEach(void action(K key, V value)) { |
+ void forEach(void action(K key, V value)) { |
int stamp = _modificationCount; |
List buckets = _buckets; |
int length = buckets.length; |
@@ -118,7 +135,7 @@ patch class HashMap<K, V> { |
} |
} |
- /* patch */ V remove(Object key) { |
+ V remove(Object key) { |
int hashCode = key.hashCode; |
List buckets = _buckets; |
int index = hashCode & (buckets.length - 1); |
@@ -143,7 +160,7 @@ patch class HashMap<K, V> { |
return null; |
} |
- /* patch */ void clear() { |
+ void clear() { |
_elementCount = 0; |
_buckets = new List(_INITIAL_CAPACITY); |
_modificationCount = (_modificationCount + 1) & _MODIFICATION_COUNT_MASK; |
@@ -182,6 +199,193 @@ patch class HashMap<K, V> { |
} |
} |
+class _CustomHashMap<K, V> extends _HashMapImpl<K, V> { |
+ final Function _equals; |
+ final Function _hashCode; |
+ _CustomHashMap(this._equals, this._hashCode); |
+ |
+ bool containsKey(Object key) { |
+ int hashCode = _hashCode(key); |
+ List buckets = _buckets; |
+ int index = hashCode & (buckets.length - 1); |
+ _HashMapEntry entry = buckets[index]; |
+ while (entry != null) { |
+ if (hashCode == entry.hashCode && _equals(entry.key, key)) return true; |
+ entry = entry.next; |
+ } |
+ return false; |
+ } |
+ |
+ V operator[](Object key) { |
+ int hashCode = _hashCode(key); |
+ List buckets = _buckets; |
+ int index = hashCode & (buckets.length - 1); |
+ _HashMapEntry entry = buckets[index]; |
+ while (entry != null) { |
+ if (hashCode == entry.hashCode && _equals(entry.key, key)) { |
+ return entry.value; |
+ } |
+ entry = entry.next; |
+ } |
+ return null; |
+ } |
+ |
+ void operator []=(K key, V value) { |
+ int hashCode = _hashCode(key); |
+ List buckets = _buckets; |
+ int length = buckets.length; |
+ int index = hashCode & (length - 1); |
+ _HashMapEntry entry = buckets[index]; |
+ while (entry != null) { |
+ if (hashCode == entry.hashCode && _equals(entry.key, key)) { |
+ entry.value = value; |
+ return; |
+ } |
+ entry = entry.next; |
+ } |
+ _addEntry(buckets, index, length, key, value, hashCode); |
+ } |
+ |
+ V putIfAbsent(K key, V ifAbsent()) { |
+ int hashCode = _hashCode(key); |
+ List buckets = _buckets; |
+ int length = buckets.length; |
+ int index = hashCode & (length - 1); |
+ _HashMapEntry entry = buckets[index]; |
+ while (entry != null) { |
+ if (hashCode == entry.hashCode && _equals(entry.key, key)) { |
+ 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; |
+ } |
+ return value; |
+ } |
+ |
+ V remove(Object key) { |
+ int hashCode = _hashCode(key); |
+ List buckets = _buckets; |
+ int index = hashCode & (buckets.length - 1); |
+ _HashMapEntry entry = buckets[index]; |
+ _HashMapEntry previous = null; |
+ while (entry != null) { |
+ _HashMapEntry next = entry.next; |
+ if (hashCode == entry.hashCode && _equals(entry.key, key)) { |
+ if (previous == null) { |
+ buckets[index] = next; |
+ } else { |
+ previous.next = next; |
+ } |
+ _elementCount--; |
+ _modificationCount = |
+ (_modificationCount + 1) & _MODIFICATION_COUNT_MASK; |
+ return entry.value; |
+ } |
+ previous = entry; |
+ entry = next; |
+ } |
+ return null; |
+ } |
+} |
+ |
+class _IdentityHashMap<K, V> extends _HashMapImpl<K, V> { |
+ 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 && identical(entry.key, key)) return true; |
+ entry = entry.next; |
+ } |
+ return false; |
+ } |
+ |
+ V operator[](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 && identical(entry.key, key)) { |
+ return entry.value; |
+ } |
+ entry = entry.next; |
+ } |
+ return null; |
+ } |
+ |
+ 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 && identical(entry.key, key)) { |
+ entry.value = value; |
+ return; |
+ } |
+ entry = entry.next; |
+ } |
+ _addEntry(buckets, index, length, key, value, hashCode); |
+ } |
+ |
+ V putIfAbsent(K key, V ifAbsent()) { |
+ 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 && identical(entry.key, key)) { |
+ 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; |
+ } |
+ return value; |
+ } |
+ |
+ V remove(Object key) { |
+ int hashCode = key.hashCode; |
+ List buckets = _buckets; |
+ int index = hashCode & (buckets.length - 1); |
+ _HashMapEntry entry = buckets[index]; |
+ _HashMapEntry previous = null; |
+ while (entry != null) { |
+ _HashMapEntry next = entry.next; |
+ if (hashCode == entry.hashCode && identical(entry.key, key)) { |
+ if (previous == null) { |
+ buckets[index] = next; |
+ } else { |
+ previous.next = next; |
+ } |
+ _elementCount--; |
+ _modificationCount = |
+ (_modificationCount + 1) & _MODIFICATION_COUNT_MASK; |
+ return entry.value; |
+ } |
+ previous = entry; |
+ entry = next; |
+ } |
+ return null; |
+ } |
+} |
+ |
+ |
class _HashMapEntry { |
final key; |
var value; |