@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); } }
@SuppressWarnings("unchecked") private void readObject(java.io.ObjectInputStream s) throws IOException, ClassNotFoundException { s.defaultReadObject(); int size = s.readInt(); init(size, loadFactor); for (int i = 0; i < size; i++) { K key = (K) s.readObject(); V value = (V) s.readObject(); putForCreate(key, value); } }
@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 void putAll(Map<? extends K, ? extends V> map) { int size = map.size(); if (size == 0) return; if (size > threshold) { if (size > MAXIMUM_CAPACITY) size = MAXIMUM_CAPACITY; int length = table.length; while (length < size) length <<= 1; resize(length); } for (Map.Entry<? extends K, ? extends V> e : map.entrySet()) put(e.getKey(), e.getValue()); }
@SuppressWarnings("unchecked") public FastCopyHashMap(Map<? extends K, ? extends V> map) { if (map instanceof FastCopyHashMap) { FastCopyHashMap<? extends K, ? extends V> fast = (FastCopyHashMap<? extends K, ? extends V>) map; this.table = (Entry<K, V>[]) fast.table.clone(); this.loadFactor = fast.loadFactor; this.size = fast.size; this.threshold = fast.threshold; } else { this.loadFactor = DEFAULT_LOAD_FACTOR; init(map.size(), this.loadFactor); putAll(map); } }
@Override public boolean containsValue(Object value) { for (Entry<K, V> e : table) if (e != null && eq(value, e.value)) return true; return false; }
public FastCopyHashMap(int initialCapacity, float loadFactor) { if (initialCapacity < 0) throw new IllegalArgumentException("Can not have a negative size table!"); if (initialCapacity > MAXIMUM_CAPACITY) initialCapacity = MAXIMUM_CAPACITY; if (!(loadFactor > 0F && loadFactor <= 1F)) throw new IllegalArgumentException("Load factor must be greater than 0 and less than or equal to 1"); this.loadFactor = loadFactor; init(initialCapacity, loadFactor); }
@SuppressWarnings("unchecked") public static <K, V> Map<K, V> duplicateMap(Map<K, V> original) { if (original instanceof FastCopyHashMap) return (Map<K, V>) ((FastCopyHashMap<K, V>) original).clone(); if (original instanceof HashMap) return (Map<K, V>) ((HashMap<K, V>) original).clone(); if (original instanceof TreeMap) return (Map<K, V>) ((TreeMap<K, V>) original).clone(); if (original.getClass().equals(Collections.emptyMap().getClass())) return Collections.emptyMap(); if (original.getClass().equals(Collections.singletonMap("", "").getClass())) { Map.Entry<K, V> e = original.entrySet().iterator().next(); return Collections.singletonMap(e.getKey(), e.getValue()); } return attemptClone(original); }
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); }
/** * Returns a string representation of this map. The string representation * consists of a list of key-value mappings in the order returned by the * map's <tt>entrySet</tt> view's iterator, enclosed in braces * (<tt>"{}"</tt>). Adjacent mappings are separated by the characters * <tt>", "</tt> (comma and space). Each key-value mapping is rendered as * the key followed by an equals sign (<tt>"="</tt>) followed by the * associated value. Keys and values are converted to strings as by * {@link String#valueOf(Object)}. * * @return a string representation of this map */ public String toString() { Iterator<java.util.Map.Entry<K, V>> i = entrySet().iterator(); if (! i.hasNext()) return "{}"; StringBuilder sb = new StringBuilder(); sb.append('{'); for (;;) { java.util.Map.Entry<K, V> e = i.next(); K key = e.getKey(); V value = e.getValue(); sb.append(key == this ? "(this Map)" : key); sb.append('='); sb.append(value == this ? "(this Map)" : value); if (! i.hasNext()) return sb.append('}').toString(); sb.append(", "); } }
public void testMapMarshalling() throws Exception { Map<Integer, GlobalTransaction> m1 = new HashMap<>(); Map<Integer, GlobalTransaction> m2 = new TreeMap<>(); Map<Integer, GlobalTransaction> m3 = new HashMap<>(); Map<Integer, GlobalTransaction> m4 = new FastCopyHashMap<>(); for (int i = 0; i < 10; i++) { JGroupsAddress jGroupsAddress = new JGroupsAddress(UUID.randomUUID()); GlobalTransaction gtx = gtf.newGlobalTransaction(jGroupsAddress, false); m1.put(1000 * i, gtx); m2.put(1000 * i, gtx); m4.put(1000 * i, gtx); } Map m5 = Immutables.immutableMapWrap(m3); marshallAndAssertEquality(m1); marshallAndAssertEquality(m2); byte[] bytes = marshaller.objectToByteBuffer(m4); Map<Integer, GlobalTransaction> m4Read = (Map<Integer, GlobalTransaction>) marshaller.objectFromByteBuffer(bytes); for (Map.Entry<Integer, GlobalTransaction> entry : m4.entrySet()) { assert m4Read.get(entry.getKey()).equals(entry.getValue()) : "Writen[" + entry.getValue() + "] and read[" + m4Read.get(entry.getKey()) + "] objects should be the same"; } marshallAndAssertEquality(m5); }
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); } }
@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 @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;
@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; }