| Index: quiver/lib/src/collection/lru_map.dart
|
| diff --git a/quiver/lib/src/collection/lru_map.dart b/quiver/lib/src/collection/lru_map.dart
|
| deleted file mode 100644
|
| index 13e094ac066e3229ffc6dac28cb9ccf25d6b0acc..0000000000000000000000000000000000000000
|
| --- a/quiver/lib/src/collection/lru_map.dart
|
| +++ /dev/null
|
| @@ -1,303 +0,0 @@
|
| -// Copyright 2014 Google Inc. All Rights Reserved.
|
| -//
|
| -// Licensed under the Apache License, Version 2.0 (the "License");
|
| -// you may not use this file except in compliance with the License.
|
| -// You may obtain a copy of the License at
|
| -//
|
| -// http://www.apache.org/licenses/LICENSE-2.0
|
| -//
|
| -// Unless required by applicable law or agreed to in writing, software
|
| -// distributed under the License is distributed on an "AS IS" BASIS,
|
| -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| -// See the License for the specific language governing permissions and
|
| -// limitations under the License.
|
| -
|
| -part of quiver.collection;
|
| -
|
| -/**
|
| - * An implementation of a [Map] which has a maximum size and uses a (Least
|
| - * Recently Used)[http://en.wikipedia.org/wiki/Cache_algorithms#LRU] algorithm
|
| - * to remove items from the [Map] when the [maximumSize] is reached and new
|
| - * items are added.
|
| - *
|
| - * It is safe to access the [keys] and [values] collections without affecting
|
| - * the "used" ordering - as well as using [forEach]. Other types of access,
|
| - * including bracket, and [putIfAbsent], promotes the key-value pair to the MRU
|
| - * position.
|
| - */
|
| -abstract class LruMap<K, V> implements Map<K, V> {
|
| - /**
|
| - * Creates a [LruMap] instance with the default implementation.
|
| - */
|
| - factory LruMap({int maximumSize}) = LinkedLruHashMap;
|
| -
|
| - /**
|
| - * Maximum size of the [Map]. If [length] exceeds this value at any time,
|
| - * n entries accessed the earliest are removed, where n is [length] -
|
| - * [maximumSize].
|
| - */
|
| - int maximumSize;
|
| -}
|
| -
|
| -/**
|
| - * Simple implementation of a linked-list entry that contains a [key] and
|
| - * [value].
|
| - */
|
| -class _LinkedEntry<K, V> {
|
| - K key;
|
| - V value;
|
| -
|
| - _LinkedEntry<K, V> next;
|
| - _LinkedEntry<K, V> previous;
|
| -
|
| - _LinkedEntry([this.key, this.value]);
|
| -}
|
| -
|
| -/**
|
| - * A linked hash-table based implementation of [LruMap].
|
| - */
|
| -class LinkedLruHashMap<K, V> implements LruMap<K, V> {
|
| - static const _DEFAULT_MAXIMUM_SIZE = 100;
|
| -
|
| - final Map<K, _LinkedEntry<K, V>> _entries;
|
| -
|
| - int _maximumSize;
|
| -
|
| - _LinkedEntry<K, V> _head;
|
| - _LinkedEntry<K, V> _tail;
|
| -
|
| - /**
|
| - * Create a new LinkedLruHashMap with a [maximumSize].
|
| - */
|
| - factory LinkedLruHashMap({int maximumSize}) =>
|
| - new LinkedLruHashMap._fromMap(new HashMap<K, _LinkedEntry<K, V>>(),
|
| - maximumSize: maximumSize);
|
| -
|
| - LinkedLruHashMap._fromMap(
|
| - this._entries, {
|
| - int maximumSize})
|
| - // This pattern is used instead of a default value because we want to
|
| - // be able to respect null values coming in from MapCache.lru.
|
| - : _maximumSize = firstNonNull(maximumSize, _DEFAULT_MAXIMUM_SIZE);
|
| -
|
| - /**
|
| - * Adds all key-value pairs of [other] to this map.
|
| - *
|
| - * The operation is equivalent to doing this[key] = value for each key and
|
| - * associated value in other. It iterates over other, which must therefore not
|
| - * change during the iteration.
|
| - *
|
| - * If a key of [other] is already in this map, its value is overwritten. If
|
| - * the number of unique keys is greater than [maximumSize] then the least
|
| - * recently use keys are evicted. For keys written to by [other], the least
|
| - * recently user order is determined by [other]'s iteration order.
|
| - */
|
| - @override
|
| - void addAll(Map<K, V> other) => other.forEach((k, v) => this[k] = v);
|
| -
|
| - @override
|
| - void clear() {
|
| - _entries.clear();
|
| - _head = _tail = null;
|
| - }
|
| -
|
| - @override
|
| - bool containsKey(K key) => _entries.containsKey(key);
|
| -
|
| - @override
|
| - bool containsValue(V value) => values.contains(value);
|
| -
|
| - /**
|
| - * Applies [action] to each key-value pair of the map in order of MRU to LRU.
|
| - *
|
| - * Calling `action` must not add or remove keys from the map.
|
| - */
|
| - @override
|
| - void forEach(void action(K key, V value)) {
|
| - var head = _head;
|
| - while (head != null) {
|
| - action(head.key, head.value);
|
| - head = head.next;
|
| - }
|
| - }
|
| -
|
| - @override
|
| - int get length => _entries.length;
|
| -
|
| - @override
|
| - bool get isEmpty => _entries.isEmpty;
|
| -
|
| - @override
|
| - bool get isNotEmpty => _entries.isNotEmpty;
|
| -
|
| - /**
|
| - * Creates an [Iterable] around the entries of the map.
|
| - */
|
| - Iterable<_LinkedEntry<K, V>> _iterable() {
|
| - return new GeneratingIterable<_LinkedEntry<K, V>>(
|
| - () => _head, (n) => n.next);
|
| - }
|
| -
|
| - /**
|
| - * The keys of [this] - in order of MRU to LRU.
|
| - *
|
| - * The returned iterable does *not* have efficient `length` or `contains`.
|
| - */
|
| - @override
|
| - Iterable<K> get keys => _iterable().map((e) => e.key);
|
| -
|
| - /**
|
| - * The values of [this] - in order of MRU to LRU.
|
| - *
|
| - * The returned iterable does *not* have efficient `length` or `contains`.
|
| - */
|
| - @override
|
| - Iterable<V> get values => _iterable().map((e) => e.value);
|
| -
|
| - @override
|
| - int get maximumSize => _maximumSize;
|
| -
|
| - @override
|
| - void set maximumSize(int maximumSize) {
|
| - if (maximumSize == null) throw new ArgumentError.notNull('maximumSize');
|
| - while (length > maximumSize) {
|
| - _removeLru();
|
| - }
|
| - _maximumSize = maximumSize;
|
| - }
|
| -
|
| - /**
|
| - * Look up the value associated with [key], or add a new value if it isn't
|
| - * there. The pair is promoted to the MRU position.
|
| - *
|
| - * Otherwise calls [ifAbsent] to get a new value, associates [key] to that
|
| - * [value], and then returns the new [value], with the key-value pair in the
|
| - * MRU position. If this causes [length] to exceed [maximumSize], then the
|
| - * LRU position is removed.
|
| - */
|
| - @override
|
| - V putIfAbsent(K key, V ifAbsent()) {
|
| - final entry = _entries.putIfAbsent(
|
| - key, () => _createEntry(key, ifAbsent()));
|
| - if (length > maximumSize) {
|
| - _removeLru();
|
| - }
|
| - _promoteEntry(entry);
|
| - return entry.value;
|
| - }
|
| -
|
| - /**
|
| - * Get the value for a [key] in the [Map]. The [key] will be promoted to the
|
| - * 'Most Recently Used' position. *NOTE*: Calling [] inside an iteration over
|
| - * keys/values is currently unsupported; use [keys] or [values] if you
|
| - * need information about entries without modifying their position.
|
| - */
|
| - @override
|
| - V operator[](K key) {
|
| - final entry = _entries[key];
|
| - if (entry != null) {
|
| - _promoteEntry(entry);
|
| - return entry.value;
|
| - } else {
|
| - return null;
|
| - }
|
| - }
|
| -
|
| - /**
|
| - * If [key] already exists, promotes it to the MRU position & assigns [value].
|
| - *
|
| - * Otherwise, adds [key] and [value] to the MRU position.
|
| - * If [length] exceeds [maximumSize] while adding, removes the LRU position.
|
| - */
|
| - @override
|
| - void operator []=(K key, V value) {
|
| - // Add this item to the MRU position.
|
| - _insertMru(_createEntry(key, value));
|
| -
|
| - // Remove the LRU item if the size would be exceeded by adding this item.
|
| - if (length > maximumSize) {
|
| - assert(length == maximumSize + 1);
|
| - _removeLru();
|
| - }
|
| - }
|
| -
|
| - @override
|
| - V remove(K key) {
|
| - final entry = _entries.remove(key);
|
| - if (entry != null) {
|
| - if (entry == _head) {
|
| - _head = _head.next;
|
| - } else if (entry == _tail) {
|
| - _tail.previous.next = null;
|
| - _tail = _tail.previous;
|
| - } else {
|
| - entry.previous.next = entry.next;
|
| - }
|
| - return entry.value;
|
| - }
|
| - return null;
|
| - }
|
| -
|
| - @override
|
| - String toString() => Maps.mapToString(this);
|
| -
|
| - /**
|
| - * Moves [entry] to the MRU position, shifting the linked list if necessary.
|
| - */
|
| - void _promoteEntry(_LinkedEntry<K, V> entry) {
|
| - if (entry.previous != null) {
|
| - // If already existed in the map, link previous to next.
|
| - entry.previous.next = entry.next;
|
| -
|
| - // If this was the tail element, assign a new tail.
|
| - if (_tail == entry) {
|
| - _tail = entry.previous;
|
| - }
|
| - }
|
| -
|
| - // Replace head with this element.
|
| - if (_head != null) {
|
| - _head.previous = entry;
|
| - }
|
| - entry.previous = null;
|
| - entry.next = _head;
|
| - _head = entry;
|
| -
|
| - // Add a tail if this is the first element.
|
| - if (_tail == null) {
|
| - assert(length == 1);
|
| - _tail = _head;
|
| - }
|
| - }
|
| -
|
| - /**
|
| - * Creates and returns an entry from [key] and [value].
|
| - */
|
| - _LinkedEntry<K, V> _createEntry(K key, V value) {
|
| - return new _LinkedEntry<K, V>(key, value);
|
| - }
|
| -
|
| - /**
|
| - * If [entry] does not exist, inserts it into the backing map.
|
| - * If it does, replaces the existing [_LinkedEntry.value] with [entry.value].
|
| - * Then, in either case, promotes [entry] to the MRU position.
|
| - */
|
| - void _insertMru(_LinkedEntry<K, V> entry) {
|
| - // Insert a new entry if necessary (only 1 hash lookup in entire function).
|
| - // Otherwise, just updates the existing value.
|
| - final value = entry.value;
|
| - _promoteEntry(_entries.putIfAbsent(entry.key, () => entry)..value = value);
|
| - }
|
| -
|
| - /**
|
| - * Removes the LRU position, shifting the linked list if necessary.
|
| - */
|
| - void _removeLru() {
|
| - // Remove the tail from the internal map.
|
| - _entries.remove(_tail.key);
|
| -
|
| - // Remove the tail element itself.
|
| - _tail = _tail.previous;
|
| - _tail.next = null;
|
| - }
|
| -}
|
|
|