mirror of
https://github.com/dart-lang/sdk
synced 2024-09-20 09:56:28 +00:00
Revert "Make LinkedHashMap also have a factory constructor and be customizable"
Dartium expectations expects "LinkedHashMap" and gets "_LinkedHashMap". Review URL: https://codereview.chromium.org//23890008 git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@27250 260f80e4-7a28-3924-810f-c04153c831b5
This commit is contained in:
parent
dff262d761
commit
761f55b1b9
|
@ -31,10 +31,13 @@ bool isInstanceOf(o, Type t) {
|
|||
if (oTypeName == tTypeName) {
|
||||
return true;
|
||||
}
|
||||
if (oTypeName.startsWith("List") && tTypeName == "List") {
|
||||
if (oTypeName.startsWith("HashMap") && tTypeName == "Map") {
|
||||
return true;
|
||||
}
|
||||
if (tTypeName == "Map" && o is Map) {
|
||||
if (oTypeName.startsWith("LinkedHashMap") && tTypeName == "Map") {
|
||||
return true;
|
||||
}
|
||||
if (oTypeName.startsWith("List") && tTypeName == "List") {
|
||||
return true;
|
||||
}
|
||||
// Dart Analysis Engine specific
|
||||
|
|
|
@ -344,7 +344,9 @@ class _TemplateIterator {
|
|||
return;
|
||||
}
|
||||
|
||||
var instanceCache = new HashMap(equals: identical);
|
||||
// TODO(jmesserly): IdentityMap matches JS semantics, but it's O(N) right
|
||||
// now. See http://dartbug.com/4161.
|
||||
var instanceCache = new IdentityMap();
|
||||
var removeDelta = 0;
|
||||
for (var splice in splices) {
|
||||
for (int i = 0; i < splice.removedCount; i++) {
|
||||
|
|
|
@ -40,7 +40,7 @@ class Writer implements ReaderOrWriter {
|
|||
* but also serves to record which objects we have already seen.
|
||||
*/
|
||||
final Map<dynamic, Reference> references =
|
||||
new HashMap<Object, Reference>(equals: identical);
|
||||
new IdentityMap<Object, Reference>();
|
||||
|
||||
/**
|
||||
* The state of objects that need to be serialized is stored here.
|
||||
|
|
|
@ -180,3 +180,64 @@ class _Sentinel {
|
|||
final _wrappedObject;
|
||||
const _Sentinel(this._wrappedObject);
|
||||
}
|
||||
|
||||
/**
|
||||
* This is used in the implementation of [IdentityMap]. We wrap all the keys
|
||||
* in an [_IdentityMapKey] that compares using the identity of the wrapped
|
||||
* objects. It also treats equal primitive values as identical
|
||||
* to conserve space.
|
||||
*/
|
||||
class _IdentityMapKey {
|
||||
_IdentityMapKey(this._value);
|
||||
var _value;
|
||||
|
||||
/**
|
||||
* Check if an object is primitive to know if we should compare it using
|
||||
* equality or identity. We don't test null/true/false where it's the same.
|
||||
*/
|
||||
_isPrimitive(x) => x is String || x is num;
|
||||
|
||||
operator ==(_IdentityMapKey w) =>
|
||||
_isPrimitive(_value) ? _value == w._value : identical(_value, w._value);
|
||||
get hashCode => _value.hashCode;
|
||||
get object => _value;
|
||||
}
|
||||
|
||||
/**
|
||||
* This provides an identity map. We wrap all the objects in
|
||||
* an [_IdentityMapKey] that compares using the identity of the
|
||||
* wrapped objects. It also treats equal primitive values as identical
|
||||
* to conserve space.
|
||||
*/
|
||||
class IdentityMap<K, V> extends LinkedHashMap<K, V> {
|
||||
// TODO(alanknight): Replace with a system identity-based map once
|
||||
// one is available. Issue 4161.
|
||||
// TODO(lrn): Replace with identity map when custom hash maps are introduced
|
||||
// (which is soon).
|
||||
|
||||
// Check before wrapping because some methods may call others, e.g. on
|
||||
// dart2js putIfAbsent calls containsKey, so without this we wrap forever.
|
||||
_wrap(Object key) =>
|
||||
(key is _IdentityMapKey) ? key : new _IdentityMapKey(key);
|
||||
_unwrap(_IdentityMapKey wrapper) => wrapper.object;
|
||||
|
||||
Iterable<K> get keys => super.keys.map((x) => _unwrap(x));
|
||||
Iterable<V> get values => super.values;
|
||||
|
||||
void forEach(void f(K key, V value)) {
|
||||
super.forEach((k, v) => f(_unwrap(k), v));
|
||||
}
|
||||
|
||||
V operator [](K key) => super[_wrap(key)];
|
||||
|
||||
void operator []=(K key, V value) {
|
||||
super[_wrap(key)] = value;
|
||||
}
|
||||
|
||||
V putIfAbsent(K key, Function ifAbsent) =>
|
||||
super.putIfAbsent(_wrap(key), ifAbsent);
|
||||
|
||||
bool containsKey(Object key) => super.containsKey(_wrap(key));
|
||||
|
||||
V remove(Object key) => super.remove(_wrap(key));
|
||||
}
|
||||
|
|
48
pkg/serialization/test/polyfill_identity_map_test.dart
Normal file
48
pkg/serialization/test/polyfill_identity_map_test.dart
Normal file
|
@ -0,0 +1,48 @@
|
|||
// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
|
||||
// for details. All rights reserved. Use of this source code is governed by a
|
||||
// BSD-style license that can be found in the LICENSE file.
|
||||
|
||||
/**
|
||||
* Provide a trivial test for identity based hashed collections, which we
|
||||
* provide here until an implementation is available in the regular libraries.
|
||||
*/
|
||||
// TODO(alanknight): Remove once identity-hashed collections are available.
|
||||
// Issue 4161.
|
||||
library identity_set_test;
|
||||
|
||||
import 'package:unittest/unittest.dart';
|
||||
import 'package:serialization/src/serialization_helpers.dart';
|
||||
|
||||
class Foo {
|
||||
var x;
|
||||
Foo(this.x);
|
||||
int get hashCode => x.hashCode;
|
||||
bool operator ==(a) => a.x == x;
|
||||
}
|
||||
|
||||
main() {
|
||||
test('basic', () {
|
||||
var one = new Foo(3);
|
||||
var two = new Foo(3);
|
||||
var map = new Map();
|
||||
var identityMap = new IdentityMap();
|
||||
map[one] = one;
|
||||
map[two] = two;
|
||||
identityMap[one] = one;
|
||||
identityMap[two] = two;
|
||||
expect(map.length, 1);
|
||||
expect(identityMap.length, 2);
|
||||
for (var each in identityMap.values) {
|
||||
expect(each, one);
|
||||
}
|
||||
});
|
||||
|
||||
test('uniquing primitives', () {
|
||||
var map = new IdentityMap();
|
||||
var one = 'one';
|
||||
var two = new String.fromCharCodes(one.codeUnits);
|
||||
map[one] = 1;
|
||||
expect(map[two], 1);
|
||||
expect(map[one], 1);
|
||||
});
|
||||
}
|
|
@ -4,35 +4,25 @@
|
|||
|
||||
patch class HashMap<K, V> {
|
||||
/* patch */ factory HashMap({ bool equals(K key1, K key2),
|
||||
int hashCode(K key),
|
||||
bool isValidKey(potentialKey) }) {
|
||||
if (isValidKey == null) {
|
||||
if (hashCode == null) {
|
||||
if (equals == null) {
|
||||
return new _HashMap<K, V>();
|
||||
}
|
||||
if (identical(identical, equals)) {
|
||||
return new _IdentityHashMap<K, V>();
|
||||
}
|
||||
hashCode = _defaultHashCode;
|
||||
} else if (equals == null) {
|
||||
equals = _defaultEquals;
|
||||
}
|
||||
} else {
|
||||
if (hashCode == null) {
|
||||
hashCode = _defaultHashCode;
|
||||
}
|
||||
int hashCode(K key) }) {
|
||||
if (hashCode == null) {
|
||||
if (equals == null) {
|
||||
equals = _defaultEquals;
|
||||
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, isValidKey);
|
||||
return new _CustomHashMap<K, V>(equals, hashCode);
|
||||
}
|
||||
}
|
||||
|
||||
const int _MODIFICATION_COUNT_MASK = 0x3fffffff;
|
||||
|
||||
class _HashMap<K, V> implements HashMap<K, V> {
|
||||
class _HashMapImpl<K, V> implements HashMap<K, V> {
|
||||
static const int _INITIAL_CAPACITY = 8;
|
||||
|
||||
int _elementCount = 0;
|
||||
|
@ -154,7 +144,11 @@ class _HashMap<K, V> implements HashMap<K, V> {
|
|||
while (entry != null) {
|
||||
_HashMapEntry next = entry.next;
|
||||
if (hashCode == entry.hashCode && entry.key == key) {
|
||||
_removeEntry(entry, previous, index);
|
||||
if (previous == null) {
|
||||
buckets[index] = next;
|
||||
} else {
|
||||
previous.next = next;
|
||||
}
|
||||
_elementCount--;
|
||||
_modificationCount =
|
||||
(_modificationCount + 1) & _MODIFICATION_COUNT_MASK;
|
||||
|
@ -172,16 +166,6 @@ class _HashMap<K, V> implements HashMap<K, V> {
|
|||
_modificationCount = (_modificationCount + 1) & _MODIFICATION_COUNT_MASK;
|
||||
}
|
||||
|
||||
void _removeEntry(_HashMapEntry entry,
|
||||
_HashMapEntry previousInBucket,
|
||||
int bucketIndex) {
|
||||
if (previousInBucket == null) {
|
||||
_buckets[bucketIndex] = entry.next;
|
||||
} else {
|
||||
previousInBucket.next = entry.next;
|
||||
}
|
||||
}
|
||||
|
||||
void _addEntry(List buckets, int index, int length,
|
||||
K key, V value, int hashCode) {
|
||||
_HashMapEntry entry =
|
||||
|
@ -217,15 +201,12 @@ class _HashMap<K, V> implements HashMap<K, V> {
|
|||
String toString() => Maps.mapToString(this);
|
||||
}
|
||||
|
||||
class _CustomHashMap<K, V> extends _HashMap<K, V> {
|
||||
class _CustomHashMap<K, V> extends _HashMapImpl<K, V> {
|
||||
final _Equality<K> _equals;
|
||||
final _Hasher<K> _hashCode;
|
||||
final _Predicate _validKey;
|
||||
_CustomHashMap(this._equals, this._hashCode, validKey)
|
||||
: _validKey = (validKey != null) ? validKey : new _TypeTest<K>().test;
|
||||
_CustomHashMap(this._equals, this._hashCode);
|
||||
|
||||
bool containsKey(Object key) {
|
||||
if (!_validKey(key)) return false;
|
||||
int hashCode = _hashCode(key);
|
||||
List buckets = _buckets;
|
||||
int index = hashCode & (buckets.length - 1);
|
||||
|
@ -238,7 +219,6 @@ class _CustomHashMap<K, V> extends _HashMap<K, V> {
|
|||
}
|
||||
|
||||
V operator[](Object key) {
|
||||
if (!_validKey(key)) return null;
|
||||
int hashCode = _hashCode(key);
|
||||
List buckets = _buckets;
|
||||
int index = hashCode & (buckets.length - 1);
|
||||
|
@ -291,7 +271,6 @@ class _CustomHashMap<K, V> extends _HashMap<K, V> {
|
|||
}
|
||||
|
||||
V remove(Object key) {
|
||||
if (!_validKey(key)) return null;
|
||||
int hashCode = _hashCode(key);
|
||||
List buckets = _buckets;
|
||||
int index = hashCode & (buckets.length - 1);
|
||||
|
@ -300,7 +279,11 @@ class _CustomHashMap<K, V> extends _HashMap<K, V> {
|
|||
while (entry != null) {
|
||||
_HashMapEntry next = entry.next;
|
||||
if (hashCode == entry.hashCode && _equals(entry.key, key)) {
|
||||
_removeEntry(entry, previous, index);
|
||||
if (previous == null) {
|
||||
buckets[index] = next;
|
||||
} else {
|
||||
previous.next = next;
|
||||
}
|
||||
_elementCount--;
|
||||
_modificationCount =
|
||||
(_modificationCount + 1) & _MODIFICATION_COUNT_MASK;
|
||||
|
@ -315,7 +298,7 @@ class _CustomHashMap<K, V> extends _HashMap<K, V> {
|
|||
String toString() => Maps.mapToString(this);
|
||||
}
|
||||
|
||||
class _IdentityHashMap<K, V> extends _HashMap<K, V> {
|
||||
class _IdentityHashMap<K, V> extends _HashMapImpl<K, V> {
|
||||
bool containsKey(Object key) {
|
||||
int hashCode = key.hashCode;
|
||||
List buckets = _buckets;
|
||||
|
@ -389,7 +372,11 @@ class _IdentityHashMap<K, V> extends _HashMap<K, V> {
|
|||
while (entry != null) {
|
||||
_HashMapEntry next = entry.next;
|
||||
if (hashCode == entry.hashCode && identical(entry.key, key)) {
|
||||
_removeEntry(entry, previous, index);
|
||||
if (previous == null) {
|
||||
buckets[index] = next;
|
||||
} else {
|
||||
previous.next = next;
|
||||
}
|
||||
_elementCount--;
|
||||
_modificationCount =
|
||||
(_modificationCount + 1) & _MODIFICATION_COUNT_MASK;
|
||||
|
@ -609,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,
|
||||
|
@ -639,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;
|
||||
}
|
||||
|
||||
|
@ -653,72 +640,153 @@ 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;
|
||||
|
||||
int _elementCount = 0;
|
||||
List<_HashMapEntry> _buckets = new List(_INITIAL_CAPACITY);
|
||||
int _modificationCount = 0;
|
||||
|
||||
var _nextEntry;
|
||||
var _previousEntry;
|
||||
|
||||
/* patch */ factory LinkedHashMap({ bool equals(K key1, K key2),
|
||||
int hashCode(K key),
|
||||
bool isValidKey(potentialKey) }) {
|
||||
if (isValidKey == null) {
|
||||
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;
|
||||
}
|
||||
} else {
|
||||
if (hashCode == null) {
|
||||
hashCode = _defaultHashCode;
|
||||
}
|
||||
if (equals == null) {
|
||||
equals = _defaultEquals;
|
||||
}
|
||||
}
|
||||
return new _LinkedCustomHashMap<K, V>(equals, hashCode, isValidKey);
|
||||
/* patch */ LinkedHashMap() {
|
||||
_nextEntry = _previousEntry = this;
|
||||
}
|
||||
}
|
||||
|
||||
// Methods that are exactly the same in all three linked hash map variants.
|
||||
abstract class _LinkedHashMapMixin<K, V> implements LinkedHashMap<K, V> {
|
||||
var _nextEntry;
|
||||
var _previousEntry;
|
||||
/* patch */ int get length => _elementCount;
|
||||
/* patch */ bool get isEmpty => _elementCount == 0;
|
||||
/* patch */ bool get isNotEmpty => _elementCount != 0;
|
||||
|
||||
bool containsValue(Object value) {
|
||||
int modificationCount = _modificationCount;
|
||||
/* 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;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/* patch */ bool containsValue(Object value) {
|
||||
var cursor = _nextEntry;
|
||||
int modificationCount = _modificationCount;
|
||||
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;
|
||||
/* patch */ 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 && entry.key == key) {
|
||||
return entry.value;
|
||||
}
|
||||
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;
|
||||
}
|
||||
entry = entry.next;
|
||||
}
|
||||
_addEntry(buckets, index, length, key, value, hashCode);
|
||||
}
|
||||
|
||||
/* patch */ 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 && 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;
|
||||
}
|
||||
|
||||
/* patch */ void addAll(Map<K, V> other) {
|
||||
other.forEach((K key, V value) {
|
||||
this[key] = value;
|
||||
});
|
||||
}
|
||||
|
||||
/* patch */ void forEach(void action(K key, V value)) {
|
||||
int stamp = _modificationCount;
|
||||
var cursor = _nextEntry;
|
||||
while (!identical(cursor, this)) {
|
||||
_HashMapEntry entry = cursor;
|
||||
action(entry.key, entry.value);
|
||||
if (modificationCount != _modificationCount) {
|
||||
if (stamp != _modificationCount) {
|
||||
throw new ConcurrentModificationError(this);
|
||||
}
|
||||
cursor = cursor._nextEntry;
|
||||
}
|
||||
}
|
||||
|
||||
void clear() {
|
||||
_nextEntry = _previousEntry = this;
|
||||
/* patch */ V remove(Object key) {
|
||||
int hashCode = key.hashCode;
|
||||
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 (previous == null) {
|
||||
buckets[index] = next;
|
||||
} else {
|
||||
previous.next = next;
|
||||
}
|
||||
entry._previousEntry._nextEntry = entry._nextEntry;
|
||||
entry._nextEntry._previousEntry = entry._previousEntry;
|
||||
entry._nextEntry = entry._previousEntry = null;
|
||||
_elementCount--;
|
||||
_modificationCount =
|
||||
(_modificationCount + 1) & _MODIFICATION_COUNT_MASK;
|
||||
return entry.value;
|
||||
}
|
||||
previous = entry;
|
||||
entry = next;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/* patch */ void clear() {
|
||||
_elementCount = 0;
|
||||
_buckets = new List(_HashMap._INITIAL_CAPACITY);
|
||||
_nextEntry = _previousEntry = this;
|
||||
_buckets = new List(_INITIAL_CAPACITY);
|
||||
_modificationCount = (_modificationCount + 1) & _MODIFICATION_COUNT_MASK;
|
||||
}
|
||||
|
||||
|
@ -736,50 +804,26 @@ abstract class _LinkedHashMapMixin<K, V> implements LinkedHashMap<K, V> {
|
|||
_modificationCount = (_modificationCount + 1) & _MODIFICATION_COUNT_MASK;
|
||||
}
|
||||
|
||||
void _removeEntry(_LinkedHashMapEntry entry,
|
||||
_HashMapEntry previousInBucket,
|
||||
int bucketIndex) {
|
||||
var previousInChain = entry._previousEntry;
|
||||
var nextInChain = entry._nextEntry;
|
||||
previousInChain._nextEntry = nextInChain;
|
||||
nextInChain._previousEntry = previousInChain;
|
||||
if (previousInBucket == null) {
|
||||
_buckets[bucketIndex] = entry.next;
|
||||
} else {
|
||||
previousInBucket.next = entry.next;
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Iterable<K> get keys => new _LinkedHashMapKeyIterable<K>(this);
|
||||
Iterable<V> get values => new _LinkedHashMapValueIterable<V>(this);
|
||||
}
|
||||
|
||||
class _LinkedHashMap<K, V> extends _HashMap<K, V>
|
||||
with _LinkedHashMapMixin<K, V> {
|
||||
_LinkedHashMap() {
|
||||
_nextEntry = _previousEntry = this;
|
||||
_buckets = newBuckets;
|
||||
}
|
||||
}
|
||||
|
||||
class _LinkedIdentityHashMap<K, V> extends _IdentityHashMap<K, V>
|
||||
with _LinkedHashMapMixin<K, V> {
|
||||
_LinkedIdentityHashMap() {
|
||||
_nextEntry = _previousEntry = this;
|
||||
}
|
||||
}
|
||||
|
||||
class _LinkedCustomHashMap<K, V> extends _CustomHashMap<K, V>
|
||||
with _LinkedHashMapMixin<K, V> {
|
||||
_LinkedCustomHashMap(bool equals(K key1, K key2),
|
||||
int hashCode(K key),
|
||||
bool isValidKey(potentialKey))
|
||||
: super(equals, hashCode, isValidKey) {
|
||||
_nextEntry = _previousEntry = this;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
patch class LinkedHashSet<E> extends _HashSetBase<E> {
|
||||
static const int _INITIAL_CAPACITY = 8;
|
||||
_LinkedHashTable<E> _table;
|
||||
|
|
|
@ -6,34 +6,23 @@
|
|||
import 'dart:_foreign_helper' show JS;
|
||||
|
||||
patch class HashMap<K, V> {
|
||||
patch factory HashMap({ bool equals(K key1, K key2),
|
||||
int hashCode(K key),
|
||||
bool isValidKey(potentialKey) }) {
|
||||
if (isValidKey == null) {
|
||||
if (hashCode == null) {
|
||||
if (equals == null) {
|
||||
return new _HashMap<K, V>();
|
||||
}
|
||||
if (identical(identical, equals)) {
|
||||
return new _IdentityHashMap<K, V>();
|
||||
}
|
||||
hashCode = _defaultHashCode;
|
||||
} else if (equals == null) {
|
||||
equals = _defaultEquals;
|
||||
}
|
||||
} else {
|
||||
if (hashCode == null) {
|
||||
hashCode = _defaultHashCode;
|
||||
}
|
||||
patch factory HashMap({ bool equals(K key1, K key2), int hashCode(K key) }) {
|
||||
if (hashCode == null) {
|
||||
if (equals == null) {
|
||||
equals = _defaultEquals;
|
||||
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, isValidKey);
|
||||
return new _CustomHashMap<K, V>(equals, hashCode);
|
||||
}
|
||||
}
|
||||
|
||||
class _HashMap<K, V> implements HashMap<K, V> {
|
||||
class _HashMapImpl<K, V> implements HashMap<K, V> {
|
||||
int _length = 0;
|
||||
|
||||
// The hash map contents are divided into three parts: one part for
|
||||
|
@ -54,7 +43,7 @@ class _HashMap<K, V> implements HashMap<K, V> {
|
|||
// guard against concurrent modifications.
|
||||
List _keys;
|
||||
|
||||
_Hash();
|
||||
_HashMapImpl();
|
||||
|
||||
int get length => _length;
|
||||
bool get isEmpty => _length == 0;
|
||||
|
@ -245,7 +234,7 @@ class _HashMap<K, V> implements HashMap<K, V> {
|
|||
_setTableEntry(table, key, value);
|
||||
}
|
||||
|
||||
V _removeHashTableEntry(var table, Object key) {
|
||||
V _removeHashTableEntry(var table, K key) {
|
||||
if (table != null && _hasTableEntry(table, key)) {
|
||||
V value = _getTableEntry(table, key);
|
||||
_deleteTableEntry(table, key);
|
||||
|
@ -336,7 +325,7 @@ class _HashMap<K, V> implements HashMap<K, V> {
|
|||
}
|
||||
}
|
||||
|
||||
class _IdentityHashMap<K, V> extends _HashMap<K, V> {
|
||||
class _IdentityHashMap<K, V> extends _HashMapImpl<K, V> {
|
||||
int _findBucketIndex(var bucket, var key) {
|
||||
if (bucket == null) return -1;
|
||||
int length = JS('int', '#.length', bucket);
|
||||
|
@ -347,27 +336,10 @@ class _IdentityHashMap<K, V> extends _HashMap<K, V> {
|
|||
}
|
||||
}
|
||||
|
||||
class _CustomHashMap<K, V> extends _HashMap<K, V> {
|
||||
class _CustomHashMap<K, V> extends _HashMapImpl<K, V> {
|
||||
final _Equality<K> _equals;
|
||||
final _Hasher<K> _hashCode;
|
||||
final _Predicate _validKey;
|
||||
_CustomHashMap(this._equals, this._hashCode, bool validKey(potentialKey))
|
||||
: _validKey = (validKey != null) ? validKey : ((v) => v is K);
|
||||
|
||||
V operator[](Object key) {
|
||||
if (!_validKey(key)) return null;
|
||||
return super[key];
|
||||
}
|
||||
|
||||
bool containsKey(Object key) {
|
||||
if (!_validKey(key)) return false;
|
||||
return super.containsKey(key);
|
||||
}
|
||||
|
||||
V remove(Object key) {
|
||||
if (!_validKey(key)) return null;
|
||||
return super.remove(key);
|
||||
}
|
||||
_CustomHashMap(this._equals, this._hashCode);
|
||||
|
||||
int _computeHashCode(var key) {
|
||||
// We force the hash codes to be unsigned 30-bit integers to avoid
|
||||
|
@ -444,34 +416,6 @@ class HashMapKeyIterator<E> implements Iterator<E> {
|
|||
}
|
||||
|
||||
patch class LinkedHashMap<K, V> {
|
||||
patch factory LinkedHashMap({ bool equals(K key1, K key2),
|
||||
int hashCode(K key),
|
||||
bool isValidKey(potentialKey) }) {
|
||||
if (isValidKey == null) {
|
||||
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;
|
||||
}
|
||||
} else {
|
||||
if (hashCode == null) {
|
||||
hashCode = _defaultHashCode;
|
||||
}
|
||||
if (equals == null) {
|
||||
equals = _defaultEquals;
|
||||
}
|
||||
}
|
||||
return new _LinkedCustomHashMap<K, V>(equals, hashCode, isValidKey);
|
||||
}
|
||||
}
|
||||
|
||||
class _LinkedHashMap<K, V> implements LinkedHashMap<K, V> {
|
||||
int _length = 0;
|
||||
|
||||
// The hash map contents are divided into three parts: one part for
|
||||
|
@ -496,22 +440,22 @@ class _LinkedHashMap<K, V> implements LinkedHashMap<K, V> {
|
|||
// iterated over.
|
||||
int _modifications = 0;
|
||||
|
||||
_LinkedHash();
|
||||
patch LinkedHashMap();
|
||||
|
||||
int get length => _length;
|
||||
bool get isEmpty => _length == 0;
|
||||
bool get isNotEmpty => !isEmpty;
|
||||
patch int get length => _length;
|
||||
patch bool get isEmpty => _length == 0;
|
||||
patch bool get isNotEmpty => !isEmpty;
|
||||
|
||||
|
||||
Iterable<K> get keys {
|
||||
patch Iterable<K> get keys {
|
||||
return new LinkedHashMapKeyIterable<K>(this);
|
||||
}
|
||||
|
||||
Iterable<V> get values {
|
||||
patch Iterable<V> get values {
|
||||
return keys.map((each) => this[each]);
|
||||
}
|
||||
|
||||
bool containsKey(Object key) {
|
||||
patch bool containsKey(Object key) {
|
||||
if (_isStringKey(key)) {
|
||||
var strings = _strings;
|
||||
if (strings == null) return false;
|
||||
|
@ -530,17 +474,17 @@ class _LinkedHashMap<K, V> implements LinkedHashMap<K, V> {
|
|||
}
|
||||
}
|
||||
|
||||
bool containsValue(Object value) {
|
||||
patch bool containsValue(Object value) {
|
||||
return keys.any((each) => this[each] == value);
|
||||
}
|
||||
|
||||
void addAll(Map<K, V> other) {
|
||||
patch void addAll(Map<K, V> other) {
|
||||
other.forEach((K key, V value) {
|
||||
this[key] = value;
|
||||
});
|
||||
}
|
||||
|
||||
V operator[](Object key) {
|
||||
patch V operator[](Object key) {
|
||||
if (_isStringKey(key)) {
|
||||
var strings = _strings;
|
||||
if (strings == null) return null;
|
||||
|
@ -562,7 +506,7 @@ class _LinkedHashMap<K, V> implements LinkedHashMap<K, V> {
|
|||
}
|
||||
}
|
||||
|
||||
void operator[]=(K key, V value) {
|
||||
patch void operator[]=(K key, V value) {
|
||||
if (_isStringKey(key)) {
|
||||
var strings = _strings;
|
||||
if (strings == null) _strings = strings = _newHashTable();
|
||||
|
@ -592,14 +536,14 @@ class _LinkedHashMap<K, V> implements LinkedHashMap<K, V> {
|
|||
}
|
||||
}
|
||||
|
||||
V putIfAbsent(K key, V ifAbsent()) {
|
||||
patch V putIfAbsent(K key, V ifAbsent()) {
|
||||
if (containsKey(key)) return this[key];
|
||||
V value = ifAbsent();
|
||||
this[key] = value;
|
||||
return value;
|
||||
}
|
||||
|
||||
V remove(Object key) {
|
||||
patch V remove(Object key) {
|
||||
if (_isStringKey(key)) {
|
||||
return _removeHashTableEntry(_strings, key);
|
||||
} else if (_isNumericKey(key)) {
|
||||
|
@ -620,7 +564,7 @@ class _LinkedHashMap<K, V> implements LinkedHashMap<K, V> {
|
|||
}
|
||||
}
|
||||
|
||||
void clear() {
|
||||
patch void clear() {
|
||||
if (_length > 0) {
|
||||
_strings = _nums = _rest = _first = _last = null;
|
||||
_length = 0;
|
||||
|
@ -628,7 +572,7 @@ class _LinkedHashMap<K, V> implements LinkedHashMap<K, V> {
|
|||
}
|
||||
}
|
||||
|
||||
void forEach(void action(K key, V value)) {
|
||||
patch void forEach(void action(K key, V value)) {
|
||||
LinkedHashMapCell cell = _first;
|
||||
int modifications = _modifications;
|
||||
while (cell != null) {
|
||||
|
@ -649,7 +593,7 @@ class _LinkedHashMap<K, V> implements LinkedHashMap<K, V> {
|
|||
}
|
||||
}
|
||||
|
||||
V _removeHashTableEntry(var table, Object key) {
|
||||
V _removeHashTableEntry(var table, K key) {
|
||||
if (table == null) return null;
|
||||
LinkedHashMapCell cell = _getTableEntry(table, key);
|
||||
if (cell == null) return null;
|
||||
|
@ -711,7 +655,7 @@ class _LinkedHashMap<K, V> implements LinkedHashMap<K, V> {
|
|||
return key is num && JS('bool', '(# & 0x3ffffff) === #', key, key);
|
||||
}
|
||||
|
||||
int _computeHashCode(var key) {
|
||||
static int _computeHashCode(var key) {
|
||||
// We force the hash codes to be unsigned 30-bit integers to avoid
|
||||
// issues with problematic keys like '__proto__'. Another option
|
||||
// would be to throw an exception if the hash code isn't a number.
|
||||
|
@ -731,12 +675,12 @@ class _LinkedHashMap<K, V> implements LinkedHashMap<K, V> {
|
|||
JS('void', 'delete #[#]', table, key);
|
||||
}
|
||||
|
||||
List _getBucket(var table, var key) {
|
||||
static List _getBucket(var table, var key) {
|
||||
var hash = _computeHashCode(key);
|
||||
return JS('var', '#[#]', table, hash);
|
||||
}
|
||||
|
||||
int _findBucketIndex(var bucket, var key) {
|
||||
static int _findBucketIndex(var bucket, var key) {
|
||||
if (bucket == null) return -1;
|
||||
int length = JS('int', '#.length', bucket);
|
||||
for (int i = 0; i < length; i++) {
|
||||
|
@ -758,61 +702,6 @@ class _LinkedHashMap<K, V> implements LinkedHashMap<K, V> {
|
|||
_deleteTableEntry(table, temporaryKey);
|
||||
return table;
|
||||
}
|
||||
|
||||
String toString() => Maps.mapToString(this);
|
||||
}
|
||||
|
||||
class _LinkedIdentityHashMap<K, V> extends _LinkedHashMap<K, V> {
|
||||
int _findBucketIndex(var bucket, var key) {
|
||||
if (bucket == null) return -1;
|
||||
int length = JS('int', '#.length', bucket);
|
||||
for (int i = 0; i < length; i++) {
|
||||
LinkedHashMapCell cell = JS('var', '#[#]', bucket, i);
|
||||
if (identical(cell._key, key)) return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
class _LinkedCustomHashMap<K, V> extends _LinkedHashMap<K, V> {
|
||||
final _Equality<K> _equals;
|
||||
final _Hasher<K> _hashCode;
|
||||
final _Predicate _validKey;
|
||||
_LinkedCustomHashMap(this._equals, this._hashCode,
|
||||
bool validKey(potentialKey))
|
||||
: _validKey = (validKey != null) ? validKey : ((v) => v is K);
|
||||
|
||||
V operator[](Object key) {
|
||||
if (!_validKey(key)) return null;
|
||||
return super[key];
|
||||
}
|
||||
|
||||
bool containsKey(Object key) {
|
||||
if (!_validKey(key)) return false;
|
||||
return super.containsKey(key);
|
||||
}
|
||||
|
||||
V remove(Object key) {
|
||||
if (!_validKey(key)) return null;
|
||||
return super.remove(key);
|
||||
}
|
||||
|
||||
int _computeHashCode(var key) {
|
||||
// We force the hash codes to be unsigned 30-bit integers to avoid
|
||||
// issues with problematic keys like '__proto__'. Another option
|
||||
// would be to throw an exception if the hash code isn't a number.
|
||||
return JS('int', '# & 0x3ffffff', _hashCode(key));
|
||||
}
|
||||
|
||||
int _findBucketIndex(var bucket, var key) {
|
||||
if (bucket == null) return -1;
|
||||
int length = JS('int', '#.length', bucket);
|
||||
for (int i = 0; i < length; i++) {
|
||||
LinkedHashMapCell cell = JS('var', '#[#]', bucket, i);
|
||||
if (_equals(cell._key, key)) return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
class LinkedHashMapCell {
|
||||
|
|
|
@ -41,14 +41,6 @@ abstract class HashMap<K, V> implements Map<K, V> {
|
|||
* for keys in order to place them in the hash table. If it is omitted, the
|
||||
* key's own [Object.hashCode] is used.
|
||||
*
|
||||
* If using methods like [operator[]], [remove] and [containsKey] together
|
||||
* with a custom equality and hashcode, an extra `isValidKey` function
|
||||
* can be supplied. This function is called before calling [equals] or
|
||||
* [hashCode] with an argument that may not be a [K] instance, and if the
|
||||
* call returns false, the key is assumed to not be in the set.
|
||||
* The [isValidKey] function defaults to just testing if the object is a
|
||||
* [K] instance.
|
||||
*
|
||||
* The used `equals` and `hashCode` method should always be consistent,
|
||||
* so that if `equals(a, b)` then `hashCode(a) == hashCode(b)`. The hash
|
||||
* of an object, or what it compares equal to, should not change while the
|
||||
|
@ -58,9 +50,7 @@ abstract class HashMap<K, V> implements Map<K, V> {
|
|||
* you also want to supply the other. The only common exception is to pass
|
||||
* [identical] as the equality and use the default hash code.
|
||||
*/
|
||||
external factory HashMap({bool equals(K key1, K key2),
|
||||
int hashCode(K key),
|
||||
bool isValidKey(potentialKey)});
|
||||
external factory HashMap({bool equals(K key1, K key2), int hashCode(K key)});
|
||||
|
||||
/**
|
||||
* Creates a [HashMap] that contains all key value pairs of [other].
|
||||
|
|
|
@ -18,10 +18,8 @@ part of dart.collection;
|
|||
*
|
||||
* The map allows `null` as a key.
|
||||
*/
|
||||
abstract class LinkedHashMap<K, V> implements HashMap<K, V> {
|
||||
external factory LinkedHashMap({ bool equals(K key1, K key2),
|
||||
int hashCode(K key),
|
||||
bool isValidKey(potentialKey) });
|
||||
class LinkedHashMap<K, V> implements HashMap<K, V> {
|
||||
external LinkedHashMap();
|
||||
|
||||
/**
|
||||
* Creates a [LinkedHashMap] that contains all key value pairs of [other].
|
||||
|
@ -66,4 +64,35 @@ abstract class LinkedHashMap<K, V> implements HashMap<K, V> {
|
|||
Maps._fillMapWithIterables(map, keys, values);
|
||||
return map;
|
||||
}
|
||||
|
||||
external bool containsKey(Object key);
|
||||
|
||||
external bool containsValue(Object value);
|
||||
|
||||
external void addAll(Map<K, V> other);
|
||||
|
||||
external V operator [](Object key);
|
||||
|
||||
external void operator []=(K key, V value);
|
||||
|
||||
external V putIfAbsent(K key, V ifAbsent());
|
||||
|
||||
external V remove(Object key);
|
||||
|
||||
external void clear();
|
||||
|
||||
external void forEach(void action (K key, V value));
|
||||
|
||||
/** The keys of the map, in insertion order. */
|
||||
external Iterable<K> get keys;
|
||||
/** The values of the map, in the order of their corresponding [keys].*/
|
||||
external Iterable<V> get values;
|
||||
|
||||
external int get length;
|
||||
|
||||
external bool get isEmpty;
|
||||
|
||||
external bool get isNotEmpty;
|
||||
|
||||
String toString() => Maps.mapToString(this);
|
||||
}
|
||||
|
|
|
@ -4,8 +4,6 @@
|
|||
|
||||
part of dart.collection;
|
||||
|
||||
typedef bool _Predicate<T>(T value);
|
||||
|
||||
/**
|
||||
* A node in a splay tree. It holds the sorting key and the left
|
||||
* and right children in the tree.
|
||||
|
@ -231,10 +229,6 @@ abstract class _SplayTree<K> {
|
|||
}
|
||||
}
|
||||
|
||||
class _TypeTest<T> {
|
||||
bool test(v) => v is T;
|
||||
}
|
||||
|
||||
/*
|
||||
* A [Map] of objects that can be ordered relative to each other.
|
||||
*
|
||||
|
@ -244,31 +238,19 @@ class _TypeTest<T> {
|
|||
* Keys of the map are compared using the `compare` function passed in
|
||||
* the constructor. If that is omitted, the objects are assumed to be
|
||||
* [Comparable], and are compared using their [Comparable.compareTo]
|
||||
* method. Non-comparable objects (including `null`) will not work as keys
|
||||
* in that case.
|
||||
*
|
||||
* To allow calling [operator[]], [remove] or [containsKey] with objects
|
||||
* that are not supported by the `compare` function, an extra `isValidKey`
|
||||
* predicate function can be supplied. This function is tested before
|
||||
* using the `compare` function on an argument value that may not be a [K]
|
||||
* value. If omitted, the `isValidKey` function defaults to testing if the
|
||||
* value is a [K].
|
||||
* method. This also means that `null` is *not* allowed as a key.
|
||||
*/
|
||||
class SplayTreeMap<K, V> extends _SplayTree<K> implements Map<K, V> {
|
||||
Comparator<K> _comparator;
|
||||
_Predicate _validKey;
|
||||
|
||||
SplayTreeMap([int compare(K key1, K key2), bool isValidKey(potentialKey)])
|
||||
: _comparator = (compare == null) ? Comparable.compare : compare,
|
||||
_validKey = (isValidKey != null) ? isValidKey : ((v) => v is K);
|
||||
SplayTreeMap([int compare(K key1, K key2)])
|
||||
: _comparator = (compare == null) ? Comparable.compare : compare;
|
||||
|
||||
/**
|
||||
* Creates a [SplayTreeMap] that contains all key value pairs of [other].
|
||||
*/
|
||||
factory SplayTreeMap.from(Map<K, V> other,
|
||||
[ int compare(K key1, K key2),
|
||||
bool isValidKey(potentialKey)]) =>
|
||||
new SplayTreeMap(compare, isValidKey)..addAll(other);
|
||||
factory SplayTreeMap.from(Map<K, V> other, [int compare(K key1, K key2)]) =>
|
||||
new SplayTreeMap(compare)..addAll(other);
|
||||
|
||||
/**
|
||||
* Creates a [SplayTreeMap] where the keys and values are computed from the
|
||||
|
@ -284,9 +266,8 @@ class SplayTreeMap<K, V> extends _SplayTree<K> implements Map<K, V> {
|
|||
* identity function.
|
||||
*/
|
||||
factory SplayTreeMap.fromIterable(Iterable<K> iterable,
|
||||
{K key(element), V value(element), int compare(K key1, K key2),
|
||||
bool isValidKey(potentialKey) }) {
|
||||
SplayTreeMap<K, V> map = new SplayTreeMap<K, V>(compare, isValidKey);
|
||||
{K key(element), V value(element), int compare(K key1, K key2)}) {
|
||||
SplayTreeMap<K, V> map = new SplayTreeMap<K, V>(compare);
|
||||
Maps._fillMapWithMappedIterable(map, iterable, key, value);
|
||||
return map;
|
||||
}
|
||||
|
@ -303,8 +284,8 @@ class SplayTreeMap<K, V> extends _SplayTree<K> implements Map<K, V> {
|
|||
* It is an error if the two [Iterable]s don't have the same length.
|
||||
*/
|
||||
factory SplayTreeMap.fromIterables(Iterable<K> keys, Iterable<V> values,
|
||||
[int compare(K key1, K key2), bool isValidKey(potentialKey)]) {
|
||||
SplayTreeMap<K, V> map = new SplayTreeMap<K, V>(compare, isValidKey);
|
||||
[int compare(K key1, K key2)]) {
|
||||
SplayTreeMap<K, V> map = new SplayTreeMap<K, V>(compare);
|
||||
Maps._fillMapWithIterables(map, keys, values);
|
||||
return map;
|
||||
}
|
||||
|
@ -315,7 +296,7 @@ class SplayTreeMap<K, V> extends _SplayTree<K> implements Map<K, V> {
|
|||
|
||||
V operator [](Object key) {
|
||||
if (key == null) throw new ArgumentError(key);
|
||||
if (!_validKey(key)) return null;
|
||||
if (key is! K) return null;
|
||||
if (_root != null) {
|
||||
int comp = _splay(key);
|
||||
if (comp == 0) {
|
||||
|
@ -327,7 +308,7 @@ class SplayTreeMap<K, V> extends _SplayTree<K> implements Map<K, V> {
|
|||
}
|
||||
|
||||
V remove(Object key) {
|
||||
if (!_validKey(key)) return null;
|
||||
if (key is! K) return null;
|
||||
_SplayTreeMapNode mapRoot = _remove(key);
|
||||
if (mapRoot != null) return mapRoot.value;
|
||||
return null;
|
||||
|
@ -397,7 +378,7 @@ class SplayTreeMap<K, V> extends _SplayTree<K> implements Map<K, V> {
|
|||
}
|
||||
|
||||
bool containsKey(Object key) {
|
||||
return _validKey(key) && _splay(key) == 0;
|
||||
return key is K && _splay(key) == 0;
|
||||
}
|
||||
|
||||
bool containsValue(Object value) {
|
||||
|
|
|
@ -33,8 +33,6 @@ void main() {
|
|||
testNumericKeys(new HashMap<num, String>(equals: identical));
|
||||
testNumericKeys(new LinkedHashMap());
|
||||
testNumericKeys(new LinkedHashMap<num, String>());
|
||||
testNumericKeys(new LinkedHashMap(equals: identical));
|
||||
testNumericKeys(new LinkedHashMap<num, String>(equals: identical));
|
||||
|
||||
testNaNKeys(new Map());
|
||||
testNaNKeys(new Map<num, String>());
|
||||
|
@ -46,40 +44,10 @@ void main() {
|
|||
// NaN is not equal to NaN.
|
||||
|
||||
testIdentityMap(new HashMap(equals: identical));
|
||||
testIdentityMap(new LinkedHashMap(equals: identical));
|
||||
|
||||
testCustomMap(new HashMap(equals: myEquals, hashCode: myHashCode,
|
||||
isValidKey: (v) => v is Customer));
|
||||
testCustomMap(new LinkedHashMap(equals: myEquals, hashCode: myHashCode,
|
||||
isValidKey: (v) => v is Customer));
|
||||
testCustomMap(new HashMap<Customer,dynamic>(equals: myEquals,
|
||||
hashCode: myHashCode));
|
||||
|
||||
testCustomMap(new LinkedHashMap<Customer,dynamic>(equals: myEquals,
|
||||
hashCode: myHashCode));
|
||||
testCustomMap(new HashMap(equals: myEquals, hashCode: myHashCode));
|
||||
|
||||
testIterationOrder(new LinkedHashMap());
|
||||
testIterationOrder(new LinkedHashMap(equals: identical));
|
||||
|
||||
testOtherKeys(new SplayTreeMap<int, int>());
|
||||
testOtherKeys(new SplayTreeMap<int, int>((int a, int b) => a - b,
|
||||
(v) => v is int));
|
||||
testOtherKeys(new SplayTreeMap((int a, int b) => a - b,
|
||||
(v) => v is int));
|
||||
testOtherKeys(new HashMap<int, int>());
|
||||
testOtherKeys(new HashMap<int, int>(equals: identical));
|
||||
testOtherKeys(new HashMap<int, int>(hashCode: (v) => v.hashCode,
|
||||
isValidKey: (v) => v is int));
|
||||
testOtherKeys(new HashMap(equals: (int x, int y) => x == y,
|
||||
hashCode: (int v) => v.hashCode,
|
||||
isValidKey: (v) => v is int));
|
||||
testOtherKeys(new LinkedHashMap<int, int>());
|
||||
testOtherKeys(new LinkedHashMap<int, int>(equals: identical));
|
||||
testOtherKeys(new LinkedHashMap<int, int>(hashCode: (v) => v.hashCode,
|
||||
isValidKey: (v) => v is int));
|
||||
testOtherKeys(new LinkedHashMap(equals: (int x, int y) => x == y,
|
||||
hashCode: (int v) => v.hashCode,
|
||||
isValidKey: (v) => v is int));
|
||||
}
|
||||
|
||||
|
||||
|
@ -674,26 +642,9 @@ class Customer {
|
|||
int myHashCode(Customer c) => c.secondId;
|
||||
bool myEquals(Customer a, Customer b) => a.secondId == b.secondId;
|
||||
|
||||
void testIterationOrder(Map map) {
|
||||
testIterationOrder(Map map) {
|
||||
var order = [0, 6, 4, 2, 7, 9, 7, 1, 2, 5, 3];
|
||||
for (int i = 0; i < order.length; i++) map[order[i]] = i;
|
||||
Expect.listEquals(map.keys.toList(), [0, 6, 4, 2, 7, 9, 1, 5, 3]);
|
||||
Expect.listEquals(map.values.toList(), [0, 1, 2, 8, 6, 5, 7, 9, 10]);
|
||||
}
|
||||
|
||||
void testOtherKeys(Map<int, int> map) {
|
||||
// Test that non-int keys are allowed in containsKey/remove/lookup.
|
||||
// Custom hash sets and tree sets must be constructed so they don't
|
||||
// use the equality/comparator on incompatible objects.
|
||||
|
||||
// This should not throw in either checked or unchecked mode.
|
||||
map[0] = 0;
|
||||
map[1] = 1;
|
||||
map[2] = 2;
|
||||
Expect.isFalse(map.containsKey("not an int"));
|
||||
Expect.isFalse(map.containsKey(1.5));
|
||||
Expect.isNull(map.remove("not an int"));
|
||||
Expect.isNull(map.remove(1.5));
|
||||
Expect.isNull(map["not an int"]);
|
||||
Expect.isNull(map[1.5]);
|
||||
}
|
||||
|
|
|
@ -9,7 +9,7 @@ import "package:expect/expect.dart";
|
|||
|
||||
import 'dart:collection';
|
||||
|
||||
class Foo extends HashSet {
|
||||
class Foo extends LinkedHashMap {
|
||||
}
|
||||
|
||||
main() {
|
||||
|
|
|
@ -8,11 +8,11 @@
|
|||
import "package:expect/expect.dart";
|
||||
import 'dart:collection';
|
||||
|
||||
class Crash extends HashSet<String> {
|
||||
class Crash extends LinkedHashMap<String,String> {
|
||||
Crash(): super();
|
||||
}
|
||||
|
||||
void main() {
|
||||
Crash map = new Crash();
|
||||
Expect.isTrue(map is HashSet);
|
||||
Expect.isTrue(map is LinkedHashMap);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue