public void printDebugStats() { int optimal = 0; int total = 0; int totalSkew = 0; int maxSkew = 0; for (int i = 0; i < table.length; i++) { Entry<K, V> e = table[i]; if (e != null) { total++; int target = index(e.hash, table.length); if (i == target) optimal++; else { int skew = Math.abs(i - target); if (skew > maxSkew) maxSkew = skew; totalSkew += skew; } } } System.out.println(" Size: " + size); System.out.println(" Real Size: " + total); System.out.println(" Optimal: " + optimal + " (" + (float) optimal * 100 / total + "%)"); System.out.println(" Average Distnce: " + ((float) totalSkew / (total - optimal))); System.out.println(" Max Distance: " + maxSkew); }
@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; }
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 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;