/* * Message.java * Copyright (c) 2005 by University of Hamburg. All Rights Reserved. * Departament of Informatics. * Distributed Systems and Information Systems. * * Created by walczak on Aug 30, 2005. * Last revision $Revision$ by: * $Author$ on $Date$. */ package jadex.commons.collection; import java.util.AbstractCollection; import java.util.AbstractSet; import java.util.Collection; import java.util.Iterator; import java.util.Map; import java.util.Set; /** * Implements a map from strings to objects as a hash table. * <code>null</code> key is allowed; <code>null</code> values are allowed. * * @author walczak * @since Aug 30, 2005 */ public class FastHashMap implements Map, java.io.Serializable { private static final int START_CAPACITY = 32; private static final double LOAD_FACTOR = 0.75; private static final Object NONE = NONE.class; private static final class NONE implements java.io.Serializable {/**/} private transient Object[] keys; private transient Object[] values; private transient int size; private transient int rehash_limit; private transient int hash_range; private transient Object nvar; /** * Constructor for Message. */ public FastHashMap() { keys = new Object[START_CAPACITY]; values = new Object[START_CAPACITY]; size = 0; rehash_limit = (int) (keys.length * LOAD_FACTOR); hash_range = keys.length - 1; nvar = NONE; } /** * @param key * @param value * @return the old value or null */ public Object put(final Object key, final Object value) { if (key == null) { Object on = nvar == NONE ? null : nvar; nvar = value; return on; } final int hc = key.hashCode(); final int h = hc & hash_range; int i = h; while (i > 0) { if (keys[--i] == null) { keys[i] = key; values[i] = value; if (++size > rehash_limit) rehash(); return null; } if (eq(key, hc, keys[i])) { Object ov = values[i]; values[i] = value; return ov; } } i = keys.length; while (i > h) { if (keys[--i] == null) { keys[i] = key; values[i] = value; if (++size > rehash_limit) rehash(); return null; } if (eq(key, hc, keys[i])) { Object ov = values[i]; values[i] = value; return ov; } } return null; } private final static boolean eq(Object a, int ah, Object b) { return a == b || (ah == b.hashCode() && a.equals(b)); } /** * @param v1 * @param v2 * @return true if both objects are equal */ private final static boolean eq(Object v1, Object v2) { return v1 == v2 || (v1 != null && v1.equals(v2)); } /** * */ private final void rehash() { final Object[] ok = keys; final Object[] ov = values; keys = new Object[keys.length << 1]; values = new Object[keys.length]; size = 0; rehash_limit = (int) (keys.length * LOAD_FACTOR); hash_range = keys.length - 1; int i = ok.length; while (i > 0) { if (ok[--i] != null) put(ok[i], ov[i]); } } /** * @param key * @return the object for this key or null */ public Object get(final Object key) { if (key == null) return nvar == NONE ? null : nvar; final int hc = key.hashCode(); final int h = hc & hash_range; int i = h; while (i > 0) { if (keys[--i] == null) { return null; } if (eq(key, hc, keys[i])) { return values[i]; } } i = keys.length; while (i > h) { if (keys[--i] == null) { return null; } if (eq(key, hc, keys[i])) { return values[i]; } } return null; } /** * @param key * @return true if there is a key of this kind */ public boolean containsKey(final Object key) { if (key == null) return nvar != NONE; final int hc = key.hashCode(); final int h = hc & hash_range; int i = h; while (i > 0) { if (keys[--i] == null) return false; if (eq(key, hc, keys[i])) return true; } i = keys.length; while (i > h) { if (keys[--i] == null) return false; if (eq(key, hc, keys[i])) return true; } return false; } /** * @return the keys from this message */ public Object[] getKeys() { return keys; } /** * @return The size of the map. * @see java.util.Map#size() */ public int size() { return size; } /** * @return True, if the map is empty. * @see java.util.Map#isEmpty() */ public boolean isEmpty() { return size == 0; } /** * @param value * @return True, if the value was found. * @see java.util.Map#containsValue(java.lang.Object) */ public boolean containsValue(Object value) { int i = keys.length; while (i > 0) { if (keys[--i] != null && eq(value, values[i])) return true; } return false; } /** * @param key * @return The object associated to the key. * @see java.util.Map#remove(java.lang.Object) */ public Object remove(Object key) { if (key == null) { Object ov = nvar == NONE ? null : nvar; nvar = NONE; return ov; } final int hc = key.hashCode(); final int h = hc & hash_range; int i = h; while (i > 0) { if (keys[--i] == null) { return null; } if (eq(key, hc, keys[i])) { keys[i] = null; --size; return values[i]; } } i = keys.length; while (i > h) { if (keys[--i] == null) { return null; } if (eq(key, hc, keys[i])) { keys[i] = null; --size; return values[i]; } } return null; } /** * @param map * @see java.util.Map#putAll(java.util.Map) */ public void putAll(Map map) { Iterator ies = map.entrySet().iterator(); while (ies.hasNext()) { Map.Entry entry = (Entry) ies.next(); put(entry.getKey(), entry.getValue()); } } /** * * @see java.util.Map#clear() */ public void clear() { size = 0; int i = keys.length; while (i > 00) { keys[--i] = null; } nvar = NONE; } transient Set key_set = null; /** * @return The key set. * @see java.util.Map#keySet() */ public Set keySet() { if (key_set == null) key_set = new AbstractSet() { public Iterator iterator() { return new Iterator() { int i = 0; public boolean hasNext() { return i < keys.length; } public Object next() { for (; i < keys.length; i++) { if (keys[i] != null) return keys[i]; } return null; } public void remove() { if (keys[i] != null) { keys[i] = null; --size; } } }; } public int size() { return size; } }; return key_set; } transient Collection values_col = null; /** * @return The values. * @see java.util.Map#values() */ public Collection values() { if (values_col == null) values_col = new AbstractCollection() { public Iterator iterator() { return new Iterator() { int i = 0; public boolean hasNext() { return i < keys.length; } public Object next() { for (; i < keys.length; i++) { if (keys[i] != null) return values[i]; } return null; } public void remove() { if (keys[i] != null) { keys[i] = null; --size; } } }; } public int size() { return size; } }; return values_col; } transient Set entry_set = null; /** * @return The set of entries. * @see java.util.Map#entrySet() */ public Set entrySet() { if (entry_set == null) entry_set = new AbstractSet() { public Iterator iterator() { return new Iterator() { int i = 0; public boolean hasNext() { return i < keys.length; } public Object next() { for (; i < keys.length; i++) { if (keys[i] != null) return new Map.Entry() { final int e_index = i; public Object getKey() { return keys[e_index]; } public Object getValue() { return values[e_index]; } public Object setValue(Object arg0) { return values[e_index] = arg0; } }; } return null; } public void remove() { if (keys[i] != null) { keys[i] = null; --size; } } }; } public int size() { return size; } }; return entry_set; } /** * @return the string representation of this message * @see java.lang.Object#toString() */ public String toString() { StringBuffer sb = new StringBuffer(); int i = keys.length; sb.append('{'); while (i > 00) { if (keys[--i] != null) { sb.append(keys[i]); sb.append('='); sb.append(values[i]); sb.append(','); } } sb.append("null="); sb.append(nvar); sb.append('}'); return sb.toString(); } /** */ private void writeObject(java.io.ObjectOutputStream s) throws java.io.IOException { int i = keys.length; s.writeInt(i); s.writeInt(size); while (i > 00) { if (keys[--i] != null) { s.writeObject(keys[i]); s.writeObject(values[i]); } } s.writeObject(nvar); } private void readObject(java.io.ObjectInputStream s) throws java.io.IOException, ClassNotFoundException { int i = s.readInt(); keys = new Object[i]; values = new Object[i]; rehash_limit = (int) (i * LOAD_FACTOR); hash_range = i - 1; size = 0; // Read the keys and values, and put the mappings in the HashMap for (i = s.readInt(); i > 00; i--) { put(s.readObject(), s.readObject()); } nvar = s.readObject(); } private static final long serialVersionUID = 362722346524651265L; }