| // 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. | |
| /** | |
| * This class represents a pair of two objects, used by LinkedHashMap | |
| * to store a {key, value} in a list. | |
| */ | |
| class KeyValuePair<K, V> { | |
| KeyValuePair(this.key, this.value) {} | |
| 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 LinkedHashMapImplementation<K, V> | |
| implements LinkedHashMap<K, V> { | |
| DoubleLinkedQueue<KeyValuePair<K, V>> _list; | |
| HashMap<K, DoubleLinkedQueueEntry<KeyValuePair<K, V>>> _map; | |
| LinkedHashMapImplementation() { | |
| _map = new HashMap<K, DoubleLinkedQueueEntry<KeyValuePair<K, V>>>(); | |
| _list = new DoubleLinkedQueue<KeyValuePair<K, V>>(); | |
| } | |
| factory LinkedHashMapImplementation.from(Map<K, V> other) { | |
| Map<K, V> result = new LinkedHashMapImplementation<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; | |
| } | |
| Collection<K> getKeys() { | |
| List<K> list = new List<K>(length); | |
| int index = 0; | |
| _list.forEach(void _(KeyValuePair<K, V> entry) { | |
| list[index++] = entry.key; | |
| }); | |
| assert(index == length); | |
| return list; | |
| } | |
| Collection<V> getValues() { | |
| List<V> list = new List<V>(length); | |
| int index = 0; | |
| _list.forEach(void _(KeyValuePair<K, V> entry) { | |
| list[index++] = entry.value; | |
| }); | |
| assert(index == length); | |
| return list; | |
| } | |
| void forEach(void f(K key, V value)) { | |
| _list.forEach(void _(KeyValuePair<K, V> entry) { | |
| f(entry.key, entry.value); | |
| }); | |
| } | |
| bool containsKey(K key) { | |
| return _map.containsKey(key); | |
| } | |
| bool containsValue(V value) { | |
| return _list.some(bool _(KeyValuePair<K, V> entry) { | |
| return (entry.value == value); | |
| }); | |
| } | |
| int get length { | |
| return _map.length; | |
| } | |
| bool isEmpty() { | |
| return length == 0; | |
| } | |
| void clear() { | |
| _map.clear(); | |
| _list.clear(); | |
| } | |
| String toString() { | |
| return Maps.mapToString(this); | |
| } | |
| } |