/* This file is part of the Joshua Machine Translation System. * * Joshua is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 2.1 * of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free * Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, * MA 02111-1307 USA */ package joshua.util; // Imports import java.util.LinkedHashMap; import java.util.Map; import java.util.logging.Level; import java.util.logging.Logger; /** * Cache is a class that implements a least recently used cache. * It is a straightforward extension of java.util.LinkedHashMap * with its removeEldestEntry method overridden, so that stale * entries are deleted once we reach the specified capacity of the * Cache. * <p> * This class is quite useful for storing the results of computations * that we would do many times over in the FeatureFunctions. * * @author Chris Callison-Burch * @since 14 April 2005 * */ public class Cache<K,V> extends LinkedHashMap<K,V> { /** Logger for this class. */ private static Logger logger = Logger.getLogger(Cache.class.getName()); //=============================================================== // Constants //=============================================================== /** * A constant is used as the default the cache size if none * is specified. */ public static final int DEFAULT_CAPACITY = 100000000; /** Default initial capacity of the cache. */ public static final int INITIAL_CAPACITY = 1000000; /** Default load factor of the cache. */ public static final float LOAD_FACTOR = 0.75f; /** * By default, ordering mode of the cache is access order * (true). */ public static final boolean ACCESS_ORDER = true; //=============================================================== // Member variables //=============================================================== /** Maximum number of items that the cache can contain. */ int maxCapacity; //=============================================================== // Constructor(s) //=============================================================== /** * Creates a Cache with a set capacity. * * @param maxCapacity the maximum capacity of the cache. */ public Cache(int maxCapacity) { super( (maxCapacity < INITIAL_CAPACITY) ? maxCapacity : INITIAL_CAPACITY, LOAD_FACTOR, ACCESS_ORDER); this.maxCapacity = maxCapacity; } /** * Creates a Cache with the DEFAULT_CAPACITY. */ public Cache() { this(DEFAULT_CAPACITY); } //=============================================================== // Public //=============================================================== //=========================================================== // Accessor methods (set/get) //=========================================================== @Override public V get(Object key) { if (logger.isLoggable(Level.FINEST)) { logger.finest("Cache get key: " + key.toString()); } return super.get(key); } @Override public V put(K key, V value) { if (logger.isLoggable(Level.FINEST)) { logger.finest("Cache put key: " + key.toString()); } return super.put(key, value); } //=========================================================== // Methods //=========================================================== @Override public boolean containsKey(Object key) { boolean contains = super.containsKey(key); if (logger.isLoggable(Level.FINEST)) { String message = (contains) ? "Cache has key: " + key.toString() : "Cache lacks key: " + key.toString(); logger.finest(message); } return contains; } //=============================================================== // Protected //=============================================================== //=============================================================== // Methods //=============================================================== /** * This method is invoked by put and putAll after inserting * a new entry into the map. Once we reach the capacity of * the cache, we remove the oldest entry each time a new * entry is added. This reduces memory consumption by * deleting stale entries. * * @param eldest the eldest entry * @return true if the capacity is greater than the maximum * capacity */ protected boolean removeEldestEntry(Map.Entry<K,V> eldest) { boolean removing = size() > maxCapacity; if (removing && logger.isLoggable(Level.FINEST)) { logger.finest("Cache loses key: " + eldest.getKey().toString()); } return removing; } //=============================================================== // Private //=============================================================== //=============================================================== // Methods //=============================================================== //=============================================================== // Static //=============================================================== //=============================================================== // Main //=============================================================== }