/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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. */ using System; using System.Collections; using System.Collections.Generic; namespace Apache.NMS.ActiveMQ.Util { /// /// Implements the basic IDictionary interface and adds functionality for controlling /// the maximum number of entries that can be contained in the Map. When the maximum /// value is reached the oldest entry is removed so that the max size is never exceeded. /// public class LRUCache : IEnumerable> { public const int DEFAULT_MAX_CACHE_SIZE = 10000; private readonly Dictionary dictionary = new Dictionary(); private readonly LinkedList> entries = new LinkedList>(); private int maxCacheSize = DEFAULT_MAX_CACHE_SIZE; public LRUCache() : base() { } public LRUCache(int maxCacheSize) : base() { this.maxCacheSize = maxCacheSize; } public void Clear() { dictionary.Clear(); } public int Count { get { return this.dictionary.Count; } } public int MaxCacheSize { get { return maxCacheSize; } set { this.maxCacheSize = value; } } public TValue this[TKey key] { get { return dictionary[key]; } set { TValue currentValue = default (TValue); // Moved used item to end of list since it been used again. if (dictionary.TryGetValue(key, out currentValue)) { KeyValuePair entry = new KeyValuePair(key, value); entries.Remove(entry); } dictionary[key] = value; entries.AddLast(new KeyValuePair(key, value)); KeyValuePair eldest = entries.First.Value; if(this.RemoveEldestEntry(eldest)) { this.dictionary.Remove(eldest.Key); this.entries.RemoveFirst(); } } } public bool TryGetValue(TKey key, out TValue val) { return dictionary.TryGetValue(key, out val); } public ICollection Keys { get { return dictionary.Keys; } } public ICollection Values { get { return dictionary.Values; } } public void Add(TKey key, TValue val) { dictionary.Add(key, val); entries.AddLast(new KeyValuePair(key, val)); KeyValuePair eldest = entries.First.Value; if(this.RemoveEldestEntry(eldest)) { this.dictionary.Remove(eldest.Key); this.entries.RemoveFirst(); } } public bool Remove(TKey v) { return dictionary.Remove(v); } public bool ContainsKey(TKey key) { return this.dictionary.ContainsKey(key); } public bool ContainsValue(TValue theValue) { return this.dictionary.ContainsValue(theValue); } public IEnumerator> GetEnumerator() { return dictionary.GetEnumerator(); } IEnumerator IEnumerable.GetEnumerator() { return dictionary.GetEnumerator(); } protected virtual bool RemoveEldestEntry(KeyValuePair eldest) { return this.dictionary.Count > this.maxCacheSize; } public void PutAll(LRUCache source) { if (Object.Equals(source, this)) { return; } foreach(KeyValuePair entry in source.entries) { this.Add(entry.Key, entry.Value); } } } }