| Index: sdk/lib/collection/map.dart
|
| diff --git a/pkg/serialization/lib/src/polyfill_identity_set.dart b/sdk/lib/collection/map.dart
|
| similarity index 57%
|
| copy from pkg/serialization/lib/src/polyfill_identity_set.dart
|
| copy to sdk/lib/collection/map.dart
|
| index 56a78651d5649eafea8ccb6d4707d95bc24bf2e8..1beaf2b9aa785770b43daa6fd446f035c46c595e 100644
|
| --- a/pkg/serialization/lib/src/polyfill_identity_set.dart
|
| +++ b/sdk/lib/collection/map.dart
|
| @@ -1,14 +1,47 @@
|
| -// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
|
| +// Copyright (c) 2013, 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.
|
|
|
| -// TODO(alanknight): Replace with proper identity collection. Issue 4161
|
| -library identity_set;
|
| +part of dart.collection;
|
| +
|
| +
|
| +/**
|
| + * Hash map version of the [Map] interface. A [HashMap] does not
|
| + * provide any guarantees on the order of keys and values in [keys]
|
| + * and [values].
|
| + */
|
| +abstract class HashMap<K, V> extends Map<K, V> {
|
| + /**
|
| + * Creates a map with the default implementation.
|
| + */
|
| + factory HashMap() => new _HashMapImpl<K, V>();
|
| +
|
| + /**
|
| + * Creates a [HashMap] that contains all key value pairs of [other].
|
| + */
|
| + factory HashMap.from(Map<K, V> other) => new _HashMapImpl<K, V>.from(other);
|
| +}
|
| +
|
| +/**
|
| + * Hash map version of the [Map] interface that preserves insertion
|
| + * order.
|
| + */
|
| +abstract class LinkedHashMap<K, V> extends HashMap<K, V> {
|
| + /**
|
| + * Creates a map with the default implementation.
|
| + */
|
| + factory LinkedHashMap() => new _LinkedHashMapImpl<K, V>();
|
| +
|
| + /**
|
| + * Creates a [LinkedHashMap] that contains all key value pairs of [other].
|
| + */
|
| + factory LinkedHashMap.from(Map<K, V> other)
|
| + => new _LinkedHashMapImpl<K, V>.from(other);
|
| +}
|
|
|
| -import 'dart:collection';
|
|
|
| // Hash map implementation with open addressing and quadratic probing.
|
| -class IdentityMap<K, V> implements HashMap<K, V> {
|
| +class _HashMapImpl<K, V> implements HashMap<K, V> {
|
|
|
| // The [_keys] list contains the keys inserted in the map.
|
| // The [_keys] list must be a raw list because it
|
| @@ -47,16 +80,16 @@ class IdentityMap<K, V> implements HashMap<K, V> {
|
| // The initial capacity of a hash map.
|
| static const int _INITIAL_CAPACITY = 8; // must be power of 2
|
|
|
| - IdentityMap() {
|
| + _HashMapImpl() {
|
| _numberOfEntries = 0;
|
| _numberOfDeleted = 0;
|
| _loadLimit = _computeLoadLimit(_INITIAL_CAPACITY);
|
| - _keys = new List(_INITIAL_CAPACITY);
|
| - _values = new List<V>(_INITIAL_CAPACITY);
|
| + _keys = new List.fixedLength(_INITIAL_CAPACITY);
|
| + _values = new List<V>.fixedLength(_INITIAL_CAPACITY);
|
| }
|
|
|
| - factory IdentityMap.from(Map<K, V> other) {
|
| - Map<K, V> result = new IdentityMap<K, V>();
|
| + factory _HashMapImpl.from(Map<K, V> other) {
|
| + Map<K, V> result = new _HashMapImpl<K, V>();
|
| other.forEach((K key, V value) { result[key] = value; });
|
| return result;
|
| }
|
| @@ -90,7 +123,7 @@ class IdentityMap<K, V> implements HashMap<K, V> {
|
| if (insertionIndex < 0) return hash;
|
| // If we did find an insertion slot before, return it.
|
| return insertionIndex;
|
| - } else if (identical(existingKey, key)) {
|
| + } else if (existingKey == key) {
|
| // The key is already in the map. Return its slot.
|
| return hash;
|
| } else if ((insertionIndex < 0) &&
|
| @@ -120,7 +153,7 @@ class IdentityMap<K, V> implements HashMap<K, V> {
|
| // contain a deleted key), we know the key is not in the map.
|
| if (existingKey == null) return -1;
|
| // The key is in the map, return its index.
|
| - if (identical(existingKey, key)) return hash;
|
| + if (existingKey == key) return hash;
|
| // Go to the next probe.
|
| hash = _nextProbe(hash, numberOfProbes++, _keys.length);
|
| // _ensureCapacity has guaranteed the following cannot happen.
|
| @@ -158,8 +191,8 @@ class IdentityMap<K, V> implements HashMap<K, V> {
|
| _loadLimit = _computeLoadLimit(newCapacity);
|
| List oldKeys = _keys;
|
| List<V> oldValues = _values;
|
| - _keys = new List(newCapacity);
|
| - _values = new List<V>(newCapacity);
|
| + _keys = new List.fixedLength(newCapacity);
|
| + _values = new List<V>.fixedLength(newCapacity);
|
| for (int i = 0; i < capacity; i++) {
|
| // [key] can be either of type [K] or [_DeletedKeySentinel].
|
| Object key = oldKeys[i];
|
| @@ -234,54 +267,93 @@ class IdentityMap<K, V> implements HashMap<K, V> {
|
| }
|
|
|
| void forEach(void f(K key, V value)) {
|
| - int length = _keys.length;
|
| - for (int i = 0; i < length; i++) {
|
| - var key = _keys[i];
|
| - if ((key != null) && (!identical(key, _DELETED_KEY))) {
|
| - f(key, _values[i]);
|
| - }
|
| + Iterator<int> it = new _HashMapImplIndexIterator(this);
|
| + while (it.moveNext()) {
|
| + f(_keys[it.current], _values[it.current]);
|
| }
|
| }
|
|
|
| + Iterable<K> get keys => new _HashMapImplKeyIterable<K>(this);
|
|
|
| - Collection<K> get keys {
|
| - List<K> list = new List<K>(length);
|
| - int i = 0;
|
| - forEach((K key, V value) {
|
| - list[i++] = key;
|
| - });
|
| - return list;
|
| - }
|
| -
|
| - Collection<V> get values {
|
| - List<V> list = new List<V>(length);
|
| - int i = 0;
|
| - forEach((K key, V value) {
|
| - list[i++] = value;
|
| - });
|
| - return list;
|
| - }
|
| + Iterable<V> get values => new _HashMapImplValueIterable<V>(this);
|
|
|
| bool containsKey(K key) {
|
| return (_probeForLookup(key) != -1);
|
| }
|
|
|
| - bool containsValue(V value) {
|
| - int length = _values.length;
|
| - for (int i = 0; i < length; i++) {
|
| - var key = _keys[i];
|
| - if ((key != null) && (!identical(key, _DELETED_KEY))) {
|
| - if (_values[i] == value) return true;
|
| + bool containsValue(V value) => values.contains(value);
|
| +
|
| + String toString() {
|
| + return Maps.mapToString(this);
|
| + }
|
| +}
|
| +
|
| +class _HashMapImplKeyIterable<E> extends Iterable<E> {
|
| + final _HashMapImpl _map;
|
| + _HashMapImplKeyIterable(this._map);
|
| +
|
| + Iterator<E> get iterator => new _HashMapImplKeyIterator<E>(_map);
|
| +}
|
| +
|
| +class _HashMapImplValueIterable<E> extends Iterable<E> {
|
| + final _HashMapImpl _map;
|
| + _HashMapImplValueIterable(this._map);
|
| +
|
| + Iterator<E> get iterator => new _HashMapImplValueIterator<E>(_map);
|
| +}
|
| +
|
| +abstract class _HashMapImplIterator<E> implements Iterator<E> {
|
| + final _HashMapImpl _map;
|
| + int _index = -1;
|
| + E _current;
|
| +
|
| + _HashMapImplIterator(this._map);
|
| +
|
| + E _computeCurrentFromIndex(int index, List keys, List values);
|
| +
|
| + bool moveNext() {
|
| + int length = _map._keys.length;
|
| + int newIndex = _index + 1;
|
| + while (newIndex < length) {
|
| + var key = _map._keys[newIndex];
|
| + if ((key != null) && (!identical(key, _HashMapImpl._DELETED_KEY))) {
|
| + _current = _computeCurrentFromIndex(newIndex, _map._keys, _map._values);
|
| + _index = newIndex;
|
| + return true;
|
| }
|
| + newIndex++;
|
| }
|
| + _index = length;
|
| + _current = null;
|
| return false;
|
| }
|
|
|
| - String toString() {
|
| - return Maps.mapToString(this);
|
| + E get current => _current;
|
| +}
|
| +
|
| +class _HashMapImplKeyIterator<E> extends _HashMapImplIterator<E> {
|
| + _HashMapImplKeyIterator(_HashMapImpl map) : super(map);
|
| +
|
| + E _computeCurrentFromIndex(int index, List keys, List values) {
|
| + return keys[index];
|
| }
|
| }
|
|
|
| +class _HashMapImplValueIterator<E> extends _HashMapImplIterator<E> {
|
| + _HashMapImplValueIterator(_HashMapImpl map) : super(map);
|
| +
|
| + E _computeCurrentFromIndex(int index, List keys, List values) {
|
| + return values[index];
|
| + }
|
| +}
|
| +
|
| +class _HashMapImplIndexIterator extends _HashMapImplIterator<int> {
|
| + _HashMapImplIndexIterator(_HashMapImpl map) : super(map);
|
| +
|
| + int _computeCurrentFromIndex(int index, List keys, List values) {
|
| + return index;
|
| + }
|
| +}
|
|
|
| /**
|
| * A singleton sentinel used to represent when a key is deleted from the map.
|
| @@ -303,4 +375,100 @@ class _KeyValuePair<K, V> {
|
|
|
| final K key;
|
| V value;
|
| -}
|
| +}
|
| +
|
| +/**
|
| + * A LinkedHashMap is a hash map that preserves the insertion order
|
| + * when iterating over the keys or the values. Updating the value of a
|
| + * key does not change the order.
|
| + */
|
| +class _LinkedHashMapImpl<K, V> implements LinkedHashMap<K, V> {
|
| + DoubleLinkedQueue<_KeyValuePair<K, V>> _list;
|
| + HashMap<K, DoubleLinkedQueueEntry<_KeyValuePair<K, V>>> _map;
|
| +
|
| + _LinkedHashMapImpl() {
|
| + _map = new HashMap<K, DoubleLinkedQueueEntry<_KeyValuePair<K, V>>>();
|
| + _list = new DoubleLinkedQueue<_KeyValuePair<K, V>>();
|
| + }
|
| +
|
| + factory _LinkedHashMapImpl.from(Map<K, V> other) {
|
| + Map<K, V> result = new _LinkedHashMapImpl<K, V>();
|
| + other.forEach((K key, V value) { result[key] = value; });
|
| + return result;
|
| + }
|
| +
|
| + void operator []=(K key, V value) {
|
| + if (_map.containsKey(key)) {
|
| + _map[key].element.value = value;
|
| + } else {
|
| + _list.addLast(new _KeyValuePair<K, V>(key, value));
|
| + _map[key] = _list.lastEntry();
|
| + }
|
| + }
|
| +
|
| + V operator [](K key) {
|
| + DoubleLinkedQueueEntry<_KeyValuePair<K, V>> entry = _map[key];
|
| + if (entry == null) return null;
|
| + return entry.element.value;
|
| + }
|
| +
|
| + V remove(K key) {
|
| + DoubleLinkedQueueEntry<_KeyValuePair<K, V>> entry = _map.remove(key);
|
| + if (entry == null) return null;
|
| + entry.remove();
|
| + return entry.element.value;
|
| + }
|
| +
|
| + V putIfAbsent(K key, V ifAbsent()) {
|
| + V value = this[key];
|
| + if ((this[key] == null) && !(containsKey(key))) {
|
| + value = ifAbsent();
|
| + this[key] = value;
|
| + }
|
| + return value;
|
| + }
|
| +
|
| + Iterable<K> get keys {
|
| + return new MappedIterable<_KeyValuePair<K, V>, K>(
|
| + _list, (_KeyValuePair<K, V> entry) => entry.key);
|
| + }
|
| +
|
| +
|
| + Iterable<V> get values {
|
| + return new MappedIterable<_KeyValuePair<K, V>, V>(
|
| + _list, (_KeyValuePair<K, V> entry) => entry.value);
|
| + }
|
| +
|
| + void forEach(void f(K key, V value)) {
|
| + _list.forEach((_KeyValuePair<K, V> entry) {
|
| + f(entry.key, entry.value);
|
| + });
|
| + }
|
| +
|
| + bool containsKey(K key) {
|
| + return _map.containsKey(key);
|
| + }
|
| +
|
| + bool containsValue(V value) {
|
| + return _list.any((_KeyValuePair<K, V> entry) {
|
| + return (entry.value == value);
|
| + });
|
| + }
|
| +
|
| + int get length {
|
| + return _map.length;
|
| + }
|
| +
|
| + bool get isEmpty {
|
| + return length == 0;
|
| + }
|
| +
|
| + void clear() {
|
| + _map.clear();
|
| + _list.clear();
|
| + }
|
| +
|
| + String toString() {
|
| + return Maps.mapToString(this);
|
| + }
|
| +}
|
|
|