package com.limegroup.gnutella.util; import java.util.HashMap; import java.util.Set; /** * This class implements fixed size HashMap. If its get full, no new entry * can be inserted into it, except by removing some entry first. * An attempt to add new entry throws an NoMoreStorageException * @see NoMoreStorageException */ public class FixedsizeHashMap { /** * The number of elements in the underlying storage */ private int count = 0; /** * The max number of elements that can be stored */ private int size = 0; private HashMap hashMap = null; /** * Create a new hashMap that stores only the specified number of entries * * @param size the number of entries to hold * @exception IllegalArgumentException if size is less < 1. */ public FixedsizeHashMap(int size) { hashMap = new HashMap(size * 4/3); //it might throw IllegalArgumentException //in case the size is negative this.size = size; } /** * Maps the given key to the given value. If adding the key * would make this contain more elements than the size given at * construction, the passed entry is not stored and NoMoreStorageException * gets throwned. * @exception NoMoreStorageException when no more space left in the storage * ideally, before calling put method, it should be checked whether the map is * already full or not * @see isfull() */ public synchronized Object put(Object key, Object value) throws NoMoreStorageException { Object retValue = null; //check if the count is less than size, in that case no problem //inserting this new entry if(count < size) { retValue = hashMap.put(key,value); if(retValue != null) //i.e if the mapping already existed { //in that case no new mapping added //and so no need to increment counts } else { //increment the count count++; } } else //if the hashmap is full { //if the entry already existed, we can safely add this new pair //without affecting the size retValue = hashMap.get(key); if(retValue != null) { //mapping existed, so update the mapping retValue = hashMap.put(key,value); } else //no space to enter anything more { //throw an exception throw new NoMoreStorageException(); } } return retValue; } /** * Returns the value mapped to the given key * @param key The given key * @return the value given key maps to */ public synchronized Object get(Object key) { return hashMap.get(key); } /** * Removes the mapping specified by given key from the underlying datastructure * @param key The key to be removed * @return the value associated with the key, or null if the key was not present */ public synchronized Object remove(Object key) { //remove the mapping Object ret = hashMap.remove(key); //if the mapping existed if(ret != null) { //decrement the count count--; } //else do nothing //return the value the key mapped to (or else it'll be null) return ret; } /** * Returns the Set that contains all the entries in the Map * @return the Set that contains all the entries in the Map */ public synchronized Set entrySet() { return hashMap.entrySet(); } /** * checks if the hash Map is full or not (ie if for adding new item we need * to remove some item * This method is not synchronized (it doesnt matter much if the count is 1 off * or so) * @return true if the map is full, false otherwise */ public boolean isFull() { return count >= size ; } /** * clears all entries from the map. */ public synchronized void clear() { hashMap.clear(); } /** * Returns the string representation of the mappings * @return the string representation of the mappings */ public synchronized String toString() { return hashMap.toString(); } }