I decided to add a new category, Codesnipper, to my blog, where I can post small classes, pieces of sample code and other usefull pieces of code. That way I'll be able to find it again and maybe it's usefull to someone else aswell. So without further ado: the Most Recently Used Hashtable.
Hashtable with a fixed capacity; removing the last one touched when inserting a new entry once the capacity has been reached. Returns null for items older then the maximum age.
// ===============================================================================// Copyright (C) 2005 Paul van Brenk// All rights reserved.// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY// OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT// LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR// FITNESS FOR A PARTICULAR PURPOSE.// ==============================================================================// Hashtable with a fixed capacity; removing the last one touched when inserting a // new entry once the capacity has been reached.// Returns null for items older then the maximum age.// ==============================================================================using System;using System.Collections;namespace PaulB.Collections { /// <summary> /// CustomHashtable with a fixad capacity removing the oldest item first. /// </summary> public class MRUHashtable : IEnumerable { /// <summary> /// /// note: no max. caching time. /// </summary> /// <param name="capacity">number of items</param> public MRUHashtable( int capacity ) : this( capacity, TimeSpan.MaxValue ){ //... } /// <summary> /// /// </summary> /// <param name="capacity">number of items</param> /// <param name="maxAge">time to cache items in minutes (0 means no max. caching time)</param> public MRUHashtable( int capacity, int maxAge ) : this ( capacity, new TimeSpan(0, maxAge, 0) ){ ///.... } /// <summary> /// /// </summary> /// <param name="capacity">number of items</param> /// <param name="maxAge">time to cache items</param> public MRUHashtable( int capacity, TimeSpan maxAge ){ this.itemTable = new Hashtable( capacity ); this.timeTable = new Hashtable( capacity ); this.capacity = capacity; this.maxAge = maxAge; } public void Add( object key, object value ){ if( this.Count >= this.capacity ){ this.RemoveOldestItem(); } this.timeTable.Add(key, DateTime.UtcNow); this.itemTable.Add(key, value); } public void Clear(){ this.itemTable.Clear(); this.timeTable.Clear(); } private void RemoveOldestItem(){ object item = null; DateTime lastAccess = DateTime.MinValue; foreach( object key in this.itemTable.Keys ){ if( item != null && (DateTime)this.timeTable[key] > lastAccess ){ continue; } item = this.itemTable[key]; lastAccess = (DateTime)this.timeTable[key]; } this.Remove(item); } public IEnumerator GetEnumerator(){ return itemTable.GetEnumerator(); } public void Remove(object key){ this.timeTable.Remove(key); this.itemTable.Remove(key); } public bool Contains( object key ){ CheckAccessTime(key); this.UpdateAccessTime(key); return this.itemTable.Contains(key); } private void UpdateAccessTime(object key){ if( this.timeTable[key] != null ){ this.timeTable[key] = DateTime.UtcNow; } } private void CheckAccessTime(object key){ //prevent stale information if( timeTable[key] == null || (DateTime.UtcNow - (DateTime)timeTable[key]) > maxAge ){ this.Remove(key); } } public object this[object key]{ get{ CheckAccessTime(key); UpdateAccessTime(key); return this.itemTable[key]; } set{ if( this.itemTable[key] == null ){ this.timeTable.Add(key, value); }else{ this.UpdateAccessTime(key); } this.itemTable[key] = value; } } public int Count{ get{ return this.itemTable.Count; } } public object SyncRoot{ get{ return this.itemTable.SyncRoot; } } public ICollection Values{ get{ return this.itemTable.Values; } } private int capacity; private TimeSpan maxAge; private Hashtable itemTable; private Hashtable timeTable; }}
disclaimer: Use at your own risk. This code is not threatsafe. Bugs, omissions let me know.