private void relocate(int start) { Entry<K, V>[] table = this.table; int length = table.length; int current = nextIndex(start, length); for (; ;) { Entry<K, V> e = table[current]; if (e == null) return; // A Doug Lea variant of Knuth's Section 6.4 Algorithm R. // This provides a non-recursive method of relocating // entries to their optimal positions once a gap is created. int prefer = index(e.hash, length); if ((current < prefer && (prefer <= start || start <= current)) || (prefer <= start && start <= current)) { table[start] = e; table[current] = null; start = current; } current = nextIndex(current, length); } }
@SuppressWarnings("unchecked") private void resize(int from) { int newLength = from << 1; // Can't get any bigger if (newLength > MAXIMUM_CAPACITY || newLength <= from) return; Entry<K, V>[] newTable = new Entry[newLength]; Entry<K, V>[] old = table; for (Entry<K, V> e : old) { if (e == null) continue; int index = index(e.hash, newLength); while (newTable[index] != null) index = nextIndex(index, newLength); newTable[index] = e; } threshold = (int) (loadFactor * newLength); table = newTable; }
@SuppressWarnings("unchecked") private void putForCreate(K key, V value) { Entry<K, V>[] table = this.table; int hash = hash(key); int length = table.length; int index = index(hash, length); Entry<K, V> e = table[index]; while (e != null) { index = nextIndex(index, length); e = table[index]; } table[index] = new Entry<K, V>(key, hash, value); }
@Override public V get(Object key) { assertKeyNotNull(key); int hash = hash(key); int length = table.length; int index = index(hash, length); for (; ;) { Entry<K, V> e = table[index]; if (e == null) return null; if (e.hash == hash && eq(key, e.key)) return e.value; index = nextIndex(index, length); } }
@Override public boolean containsKey(Object key) { assertKeyNotNull(key); int hash = hash(key); int length = table.length; int index = index(hash, length); for (; ;) { Entry<K, V> e = table[index]; if (e == null) return false; if (e.hash == hash && eq(key, e.key)) return true; index = nextIndex(index, length); } }
@Override public V put(K key, V value) { assertKeyNotNull(key); Entry<K, V>[] table = this.table; int hash = hash(key); int length = table.length; int start = index(hash, length); int index = start; for (; ;) { Entry<K, V> e = table[index]; if (e == null) break; if (e.hash == hash && eq(key, e.key)) { table[index] = new Entry<K, V>(e.key, e.hash, value); return e.value; } index = nextIndex(index, length); if (index == start) throw new IllegalStateException("Table is full!"); } modCount++; table[index] = new Entry<K, V>(key, hash, value); if (++size >= threshold) resize(length); return null; }
@Override @SuppressWarnings("unchecked") public void remove() { if (modCount != expectedCount) throw new ConcurrentModificationException(); int current = this.current; int delete = current; if (current == -1) throw new IllegalStateException(); // Invalidate current (prevents multiple remove) this.current = -1; // Start were we relocate next = delete; Entry<K, V>[] table = this.table; if (table != FastCopyHashMap.this.table) { FastCopyHashMap.this.remove(table[delete].key); table[delete] = null; expectedCount = modCount; return; } int length = table.length; int i = delete;