package java.util; public class HashMap implements Map { private int size; private Cell[] array; private final CellFactory factory; HashMap(int capacity, CellFactory factory) { if (capacity > 0) { array = new Cell[nextPowerOfTwo(capacity)]; } this.factory = factory; } public HashMap(int capacity) { this(capacity, new MyCellFactory()); } public HashMap() { this(0); } private static int nextPowerOfTwo(int n) { int r = 1; while (r < n) r <<= 1; return r; } public int size() { return size; } private static int hash(Object a) { return (a == null ? 0 : a.hashCode()); } private static boolean equal(Object a, Object b) { return (a == null && b == null) || (a != null && a.equals(b)); } private void resize() { if (array == null || size >= array.length * 2) { resize(array == null ? 16 : array.length * 2); } else if (size <= array.length / 3) { resize(array.length / 2); } } private void resize(int capacity) { Cell[] newArray = null; if (capacity != 0) { capacity = nextPowerOfTwo(capacity); if (array != null && array.length == capacity) { return; } newArray = new Cell[capacity]; if (array != null) { for (int i = 0; i < array.length; ++i) { Cell next; for (Cell c = array[i]; c != null; c = next) { next = c.next(); int index = c.getKey().hashCode() & (capacity - 1); c.setNext(array[index]); array[index] = c; } } } } array = newArray; } private Cell find(K key) { if (array != null) { int index = hash(key) & (array.length - 1); for (Cell c = array[index]; c != null; c = c.next()) { if (equal(key, c.getKey())) { return c; } } } return null; } private void insert(Cell cell) { ++ size; resize(); int index = cell.hashCode() & (array.length - 1); cell.setNext(array[index]); array[index] = cell; } // primarily for use by WeakHashMap: void remove(Cell cell) { int index = cell.hashCode() & (array.length - 1); Cell p = null; for (Cell c = array[index]; c != null; c = c.next()) { if (c == cell) { if (p == null) { array[index] = c.next(); } else { p.setNext(c.next()); } -- size; break; } } resize(); } private Cell putCell(K key, V value) { Cell c = find(key); if (c == null) { insert(factory.make(key, value, null)); } else { V old = c.getValue(); c.setValue(value); } return c; } public boolean containsKey(K key) { return find(key) != null; } public boolean containsValue(V value) { return values().contains(value); } public V get(K key) { Cell c = find(key); return (c == null ? null : c.getValue()); } public Cell removeCell(K key) { Cell old = null; if (array != null) { int index = hash(key) & (array.length - 1); Cell p = null; for (Cell c = array[index]; c != null; c = c.next()) { if (equal(key, c.getKey())) { old = c; if (p == null) { array[index] = c.next(); } else { p.setNext(c.next()); } -- size; break; } } resize(); } return old; } public V put(K key, V value) { Cell c = putCell(key, value); return (c == null ? null : c.getValue()); } public V remove(K key) { Cell c = removeCell(key); return (c == null ? null : c.getValue()); } public void clear() { array = null; size = 0; } public Set> entrySet() { return new EntrySet(); } public Set keySet() { return new KeySet(); } public Collection values() { return new Values(); } Iterator> iterator() { return new MyIterator(); } interface Cell extends Entry { public HashMap.Cell next(); public void setNext(HashMap.Cell next); } interface CellFactory { public Cell make(K key, V value, Cell next); } private static class MyCell implements Cell { public final K key; public V value; public Cell next; public MyCell(K key, V value, Cell next) { this.key = key; this.value = value; this.next = next; } public K getKey() { return key; } public V getValue() { return value; } public void setValue(V value) { this.value = value; } public HashMap.Cell next() { return next; } public void setNext(HashMap.Cell next) { this.next = next; } public int hashCode() { return (key == null ? 0 : key.hashCode()); } } private static class MyCellFactory implements CellFactory { public Cell make(K key, V value, Cell next) { return new MyCell(key, value, next); } } private class EntrySet implements Set> { public int size() { return HashMap.this.size(); } public boolean contains(Entry e) { return containsKey(e.getKey()); } public boolean add(Entry e) { return putCell(e.getKey(), e.getValue()) != null; } public boolean remove(Entry e) { return removeCell(e.getKey()) != null; } public void clear() { HashMap.this.clear(); } public Iterator> iterator() { return new MyIterator(); } } private class KeySet implements Set { public int size() { return HashMap.this.size(); } public boolean contains(K key) { return containsKey(key); } public boolean add(K key) { return putCell(key, null) != null; } public boolean remove(K key) { return removeCell(key) != null; } public void clear() { HashMap.this.clear(); } public Iterator iterator() { return new KeyIterator(new MyIterator()); } } private class Values implements Collection { public int size() { return HashMap.this.size(); } public boolean contains(V value) { return containsValue(value); } public boolean add(V value) { throw new UnsupportedOperationException(); } public boolean remove(V value) { throw new UnsupportedOperationException(); } public void clear() { HashMap.this.clear(); } public Iterator iterator() { return new ValueIterator(new MyIterator()); } } private class MyIterator implements Iterator> { private int currentIndex = -1; private int nextIndex = -1; private Cell previousCell; private Cell currentCell; private Cell nextCell; public MyIterator() { hasNext(); } public Entry next() { if (hasNext()) { if (currentCell != null && currentCell.next() != null) { previousCell = currentCell; } else { previousCell = null; } currentCell = nextCell; currentIndex = nextIndex; nextCell = nextCell.next(); return currentCell; } else { throw new NoSuchElementException(); } } public boolean hasNext() { if (array != null) { while (nextCell == null && ++ nextIndex < array.length) { if (array[nextIndex] != null) { nextCell = array[nextIndex]; return true; } } } return false; } public void remove() { if (currentCell != null) { if (previousCell == null) { array[currentIndex] = currentCell.next(); } else { previousCell.setNext(currentCell.next()); if (previousCell.next() == null) { previousCell = null; } } currentCell = null; } else { throw new IllegalStateException(); } } } private static class KeyIterator implements Iterator { private final Iterator> it; public KeyIterator(Iterator> it) { this.it = it; } public K next() { return it.next().getKey(); } public boolean hasNext() { return it.hasNext(); } public void remove() { it.remove(); } } private static class ValueIterator implements Iterator { private final Iterator> it; public ValueIterator(Iterator> it) { this.it = it; } public V next() { return it.next().getValue(); } public boolean hasNext() { return it.hasNext(); } public void remove() { it.remove(); } } }