Collections Data Structure Java

//package net.ontopia.utils;
import java.util.AbstractCollection;
import java.util.AbstractMap;
import java.util.AbstractSet;
import java.util.Collection;
import java.util.Iterator;
import java.util.NoSuchElementException;
import java.util.Set;
public class CompactHashMap extends AbstractMap {
  protected final static int INITIAL_SIZE = 3;
  protected final static double LOAD_FACTOR = 0.6;
  /**
   * This object is used to represent null, should clients use that as a key.
   */
  protected final static Object nullObject = new Object();
  /**
   * When a key is deleted this object is put into the hashtable in its place,
   * so that other entries with the same key (collisions) further down the
   * hashtable are not lost after we delete an object in the collision chain.
   */
  protected final static Object deletedObject = new Object();
  protected int elements;
  protected int freecells;
  protected K[] keys;
  protected V[] values; // object at pos x corresponds to key at pos x
  protected int modCount;
  /**
   * Constructs a new, empty set.
   */
  public CompactHashMap() {
    this(INITIAL_SIZE);
  }
  /**
   * Constructs a new, empty set.
   */
  public CompactHashMap(int size) {
    // NOTE: If array size is 0, we get a
    // "java.lang.ArithmeticException: / by zero" in add(Object).
    keys = (K[]) new Object[(size == 0 ? 1 : size)];
    values = (V[]) new Object[(size == 0 ? 1 : size)];
    elements = 0;
    freecells = keys.length;
    modCount = 0;
  }
  // MAP IMPLEMENTATION 
  /**
   * Returns the number of key/value mappings in this map.
   */
  public int size() {
    return elements;
  }
  /**
   * Returns true if this map contains no mappings.
   */
  public boolean isEmpty() {
    return elements == 0;
  }
  /**
   * Removes all key/value mappings in the map.
   */
  public void clear() {
    elements = 0;
    for (int ix = 0; ix < keys.length; ix++) {
      keys[ix] = null;
      values[ix] = null;
    }
    freecells = values.length;
    modCount++;
  }
  /**
   * Returns true if this map contains the specified key.
   */
  public boolean containsKey(Object k) {
    return keys[findKeyIndex(k)] != null;
  }
  /**
   * Returns true if this map contains the specified value.
   */
  public boolean containsValue(Object v) {
    if (v == null)
      v = (V) nullObject;
    for (int ix = 0; ix < values.length; ix++)
      if (values[ix] != null && values[ix].equals(v))
        return true;
    return false;
  }
  /**
   * Returns a read-only set view of the map's keys.
   */
  public Set> entrySet() {
    throw new UnsupportedOperationException();
  }
  /**
   * Removes the mapping with key k, if there is one, and returns its value,
   * if there is one, and null if there is none.
   */
  public V remove(Object k) {
    int index = findKeyIndex(k);
    // we found the right position, now do the removal
    if (keys[index] != null) {
      // we found the object
      // same problem here as with put
      V v = values[index];
      keys[index] = (K) deletedObject;
      values[index] = (V) deletedObject;
      modCount++;
      elements--;
      return v;
    } else
      // we did not find the key
      return null;
  }
  /**
   * Adds the specified mapping to this map, returning the old value for the
   * mapping, if there was one.
   */
  public V put(K k, V v) {
    if (k == null)
      k = (K) nullObject;
    int hash = k.hashCode();
    int index = (hash & 0x7FFFFFFF) % keys.length;
    int offset = 1;
    int deletedix = -1;
    // search for the key (continue while !null and !this key)
    while (keys[index] != null
        && !(keys[index].hashCode() == hash && keys[index].equals(k))) {
      // if there's a deleted mapping here we can put this mapping here,
      // provided it's not in here somewhere else already
      if (keys[index] == deletedObject)
        deletedix = index;
      index = ((index + offset) & 0x7FFFFFFF) % keys.length;
      offset = offset * 2 + 1;
      if (offset == -1)
        offset = 2;
    }
    if (keys[index] == null) { // wasn't present already
      if (deletedix != -1) // reusing a deleted cell
        index = deletedix;
      else
        freecells--;
      modCount++;
      elements++;
      keys[index] = (K) k;
      values[index] = (V) v;
      // rehash with increased capacity
      if (1 - (freecells / (double) keys.length) > LOAD_FACTOR)
        rehash(keys.length * 2 + 1);
      return null;
    } else { // was there already
      modCount++;
      V oldv = values[index];
      values[index] = (V) v;
      return oldv;
    }
  }
  /**
   * INTERNAL: Rehashes the hashmap to a bigger size.
   */
  protected void rehash(int newCapacity) {
    int oldCapacity = keys.length;
    K[] newKeys = (K[]) new Object[newCapacity];
    V[] newValues = (V[]) new Object[newCapacity];
    for (int ix = 0; ix < oldCapacity; ix++) {
      Object k = keys[ix];
      if (k == null || k == deletedObject)
        continue;
      int hash = k.hashCode();
      int index = (hash & 0x7FFFFFFF) % newCapacity;
      int offset = 1;
      // search for the key
      while (newKeys[index] != null) { // no need to test for duplicates
        index = ((index + offset) & 0x7FFFFFFF) % newCapacity;
        offset = offset * 2 + 1;
        if (offset == -1)
          offset = 2;
      }
      newKeys[index] = (K) k;
      newValues[index] = values[ix];
    }
    keys = newKeys;
    values = newValues;
    freecells = keys.length - elements;
  }
  /**
   * Returns the value for the key k, if there is one, and null if there is
   * none.
   */
  public V get(Object k) {
    return values[findKeyIndex(k)];
  }
  /**
   * Returns a virtual read-only collection containing all the values in the
   * map.
   */
  public Collection values() {
    return new ValueCollection();
  }
  /**
   * Returns a virtual read-only set of all the keys in the map.
   */
  public Set keySet() {
    return new KeySet();
  }
  // --- Internal utilities
  private final int findKeyIndex(Object k) {
    if (k == null)
      k = nullObject;
    int hash = k.hashCode();
    int index = (hash & 0x7FFFFFFF) % keys.length;
    int offset = 1;
    // search for the key (continue while !null and !this key)
    while (keys[index] != null
        && !(keys[index].hashCode() == hash && keys[index].equals(k))) {
      index = ((index + offset) & 0x7FFFFFFF) % keys.length;
      offset = offset * 2 + 1;
      if (offset == -1)
        offset = 2;
    }
    return index;
  }
  // --- Key set
  private class KeySet extends AbstractSet {
    public int size() {
      return elements;
    }
    public boolean contains(Object k) {
      return containsKey(k);
    }
    public Iterator iterator() {
      return new KeyIterator();
    }
  }
  private class KeyIterator implements Iterator {
    private int ix;
    private KeyIterator() {
      // walk up to first value, so that hasNext() and next() return
      // correct results
      for (; ix < keys.length; ix++)
        if (values[ix] != null && keys[ix] != deletedObject)
          break;
    }
    public boolean hasNext() {
      return ix < keys.length;
    }
    public void remove() {
      throw new UnsupportedOperationException("Collection is read-only");
    }
    public K next() {
      if (ix >= keys.length)
        throw new NoSuchElementException();
      K key = (K) keys[ix++];
      // walk up to next value
      for (; ix < keys.length; ix++)
        if (keys[ix] != null && keys[ix] != deletedObject)
          break;
      // ix now either points to next key, or outside array (if no next)
      return key;
    }
  }
  // --- Value collection
  private class ValueCollection extends AbstractCollection {
    public int size() {
      return elements;
    }
    public Iterator iterator() {
      return new ValueIterator();
    }
    public boolean contains(Object v) {
      return containsValue(v);
    }
  }
  private class ValueIterator implements Iterator {
    private int ix;
    private ValueIterator() {
      // walk up to first value, so that hasNext() and next() return
      // correct results
      for (; ix < values.length; ix++)
        if (values[ix] != null && values[ix] != deletedObject)
          break;
    }
    public boolean hasNext() {
      return ix < values.length;
    }
    public void remove() {
      throw new UnsupportedOperationException("Collection is read-only");
    }
    public V next() {
      if (ix >= values.length)
        throw new NoSuchElementException();
      V value = (V) values[ix++];
      // walk up to next value
      for (; ix < values.length; ix++)
        if (values[ix] != null && values[ix] != deletedObject)
          break;
      // ix now either points to next value, or outside array (if no next)
      return value;
    }
  }
}