diff --git a/platform/util/src/com/intellij/util/containers/ConcurrentHashMap.java b/platform/util/src/com/intellij/util/containers/ConcurrentHashMap.java index e99677e3fe73..e7ad4db868f2 100644 --- a/platform/util/src/com/intellij/util/containers/ConcurrentHashMap.java +++ b/platform/util/src/com/intellij/util/containers/ConcurrentHashMap.java @@ -61,7 +61,7 @@ public class ConcurrentHashMap extends AbstractMap implements Concur /** * The default number of concurrency control segments. - **/ + */ static final int DEFAULT_SEGMENTS = Math.min(2, Runtime.getRuntime().availableProcessors()); // CHANGED FROM 16 /** @@ -83,12 +83,12 @@ public class ConcurrentHashMap extends AbstractMap implements Concur /** * Mask value for indexing into segments. The upper bits of a * key's hash code are used to choose the segment. - **/ + */ final int segmentMask; /** * Shift value for indexing within segments. - **/ + */ final int segmentShift; /** @@ -97,7 +97,7 @@ public class ConcurrentHashMap extends AbstractMap implements Concur final Segment[] segments; transient Set keySet; - transient Set> entrySet; + transient Set> entrySet; transient Collection values; private final TObjectHashingStrategy myHashingStrategy; @@ -105,10 +105,11 @@ public class ConcurrentHashMap extends AbstractMap implements Concur /** * Returns the segment that should be used for key with given hash + * * @param hash the hash code for the key * @return the segment */ - final Segment segmentFor(int hash) { + final Segment segmentFor(int hash) { return segments[(hash >>> segmentShift) & segmentMask]; } @@ -117,7 +118,7 @@ public class ConcurrentHashMap extends AbstractMap implements Concur /** * ConcurrentHashMap list entry. Note that this is never exported * out as a user-visible Map.Entry. - * + *

* Because the value field is volatile, not final, it is legal wrt * the Java Memory Model for an unsynchronized reader to see null * instead of initial value when read via a data race. Although a @@ -126,13 +127,13 @@ public class ConcurrentHashMap extends AbstractMap implements Concur * backup in case a null (pre-initialized) value is ever seen in * an unsynchronized access method. */ - static final class HashEntry { + static final class HashEntry { final K key; final int hash; volatile V value; - final HashEntry next; + final HashEntry next; - HashEntry(K key, int hash, HashEntry next, V value) { + HashEntry(K key, int hash, HashEntry next, V value) { this.key = key; this.hash = hash; this.next = next; @@ -144,8 +145,8 @@ public class ConcurrentHashMap extends AbstractMap implements Concur * Segments are specialized versions of hash tables. This * subclasses from ReentrantLock opportunistically, just to * simplify some locking and avoid separate construction. - **/ - static final class Segment extends ReentrantLock implements Serializable { + */ + static final class Segment extends ReentrantLock implements Serializable { /* * Segments maintain a table of entry lists that are ALWAYS * kept in a consistent state, so can be read without locking. @@ -187,7 +188,7 @@ public class ConcurrentHashMap extends AbstractMap implements Concur /** * The number of elements in this segment's region. - **/ + */ transient volatile int count; /** @@ -217,6 +218,7 @@ public class ConcurrentHashMap extends AbstractMap implements Concur * The load factor for the hash table. Even though this value * is same for all segments, it is replicated to avoid needing * links to outer object. + * * @serial */ final float loadFactor; @@ -231,7 +233,7 @@ public class ConcurrentHashMap extends AbstractMap implements Concur /** * Set table to new HashEntry array. * Call only while holding lock or in constructor. - **/ + */ void setTable(HashEntry[] newTable) { threshold = (int)(newTable.length * loadFactor); table = newTable; @@ -240,9 +242,9 @@ public class ConcurrentHashMap extends AbstractMap implements Concur /** * Return properly casted first entry of bin for given hash */ - HashEntry getFirst(int hash) { + HashEntry getFirst(int hash) { HashEntry[] tab = table; - return (HashEntry) tab[hash & (tab.length - 1)]; + return (HashEntry)tab[hash & (tab.length - 1)]; } /** @@ -252,11 +254,12 @@ public class ConcurrentHashMap extends AbstractMap implements Concur * its table assignment, which is legal under memory model * but is not known to ever occur. */ - V readValueUnderLock(HashEntry e) { + V readValueUnderLock(HashEntry e) { lock(); try { return e.value; - } finally { + } + finally { unlock(); } } @@ -265,12 +268,13 @@ public class ConcurrentHashMap extends AbstractMap implements Concur V get(K key, int hash) { if (count != 0) { // read-volatile - HashEntry e = getFirst(hash); + HashEntry e = getFirst(hash); while (e != null) { - if (e.hash == hash && myHashingStrategy.equals(key,e.key)) { + if (e.hash == hash && myHashingStrategy.equals(key, e.key)) { V v = e.value; - if (v != null) + if (v != null) { return v; + } return readValueUnderLock(e); // recheck } e = e.next; @@ -281,10 +285,11 @@ public class ConcurrentHashMap extends AbstractMap implements Concur boolean containsKey(K key, int hash) { if (count != 0) { // read-volatile - HashEntry e = getFirst(hash); + HashEntry e = getFirst(hash); while (e != null) { - if (e.hash == hash && myHashingStrategy.equals(key,e.key)) + if (e.hash == hash && myHashingStrategy.equals(key, e.key)) { return true; + } e = e.next; } } @@ -295,15 +300,18 @@ public class ConcurrentHashMap extends AbstractMap implements Concur if (count != 0) { // read-volatile HashEntry[] tab = table; int len = tab.length; - for (int i = 0 ; i < len; i++) { - for (HashEntry e = (HashEntry)tab[i]; - e != null ; + for (int i = 0; i < len; i++) { + for (HashEntry e = (HashEntry)tab[i]; + e != null; e = e.next) { V v = e.value; if (v == null) // recheck + { v = readValueUnderLock(e); - if (value.equals(v)) + } + if (value.equals(v)) { return true; + } } } } @@ -313,9 +321,10 @@ public class ConcurrentHashMap extends AbstractMap implements Concur boolean replace(K key, int hash, V oldValue, V newValue) { lock(); try { - HashEntry e = getFirst(hash); - while (e != null && (e.hash != hash || !myHashingStrategy.equals(key,e.key))) + HashEntry e = getFirst(hash); + while (e != null && (e.hash != hash || !myHashingStrategy.equals(key, e.key))) { e = e.next; + } boolean replaced = false; if (e != null && oldValue.equals(e.value)) { @@ -323,7 +332,8 @@ public class ConcurrentHashMap extends AbstractMap implements Concur e.value = newValue; } return replaced; - } finally { + } + finally { unlock(); } } @@ -331,9 +341,10 @@ public class ConcurrentHashMap extends AbstractMap implements Concur V replace(K key, int hash, V newValue) { lock(); try { - HashEntry e = getFirst(hash); - while (e != null && (e.hash != hash || !myHashingStrategy.equals(key,e.key))) + HashEntry e = getFirst(hash); + while (e != null && (e.hash != hash || !myHashingStrategy.equals(key, e.key))) { e = e.next; + } V oldValue = null; if (e != null) { @@ -341,7 +352,8 @@ public class ConcurrentHashMap extends AbstractMap implements Concur e.value = newValue; } return oldValue; - } finally { + } + finally { unlock(); } } @@ -352,28 +364,33 @@ public class ConcurrentHashMap extends AbstractMap implements Concur try { int c = count; if (c++ > threshold) // ensure capacity + { rehash(); + } HashEntry[] tab = table; int index = hash & (tab.length - 1); - HashEntry first = (HashEntry) tab[index]; - HashEntry e = first; - while (e != null && (e.hash != hash || !myHashingStrategy.equals(key,e.key))) + HashEntry first = (HashEntry)tab[index]; + HashEntry e = first; + while (e != null && (e.hash != hash || !myHashingStrategy.equals(key, e.key))) { e = e.next; + } V oldValue; if (e != null) { oldValue = e.value; - if (!onlyIfAbsent) + if (!onlyIfAbsent) { e.value = value; + } } else { oldValue = null; ++modCount; - tab[index] = new HashEntry(key, hash, first, value); + tab[index] = new HashEntry(key, hash, first, value); count = c; // write-volatile } return oldValue; - } finally { + } + finally { unlock(); } } @@ -381,8 +398,9 @@ public class ConcurrentHashMap extends AbstractMap implements Concur void rehash() { HashEntry[] oldTable = table; int oldCapacity = oldTable.length; - if (oldCapacity >= MAXIMUM_CAPACITY) + if (oldCapacity >= MAXIMUM_CAPACITY) { return; + } /* * Reclassify nodes in each list to new Map. Because we are @@ -401,24 +419,25 @@ public class ConcurrentHashMap extends AbstractMap implements Concur HashEntry[] newTable = new HashEntry[oldCapacity << 1]; threshold = (int)(newTable.length * loadFactor); int sizeMask = newTable.length - 1; - for (int i = 0; i < oldCapacity ; i++) { + for (int i = 0; i < oldCapacity; i++) { // We need to guarantee that any existing reads of old Map can // proceed. So we cannot yet null out each bin. - HashEntry e = (HashEntry)oldTable[i]; + HashEntry e = (HashEntry)oldTable[i]; if (e != null) { - HashEntry next = e.next; + HashEntry next = e.next; int idx = e.hash & sizeMask; // Single node on list - if (next == null) + if (next == null) { newTable[idx] = e; + } else { // Reuse trailing consecutive sequence at same slot - HashEntry lastRun = e; + HashEntry lastRun = e; int lastIdx = idx; - for (HashEntry last = next; + for (HashEntry last = next; last != null; last = last.next) { int k = last.hash & sizeMask; @@ -430,11 +449,11 @@ public class ConcurrentHashMap extends AbstractMap implements Concur newTable[lastIdx] = lastRun; // Clone all remaining nodes - for (HashEntry p = e; p != lastRun; p = p.next) { + for (HashEntry p = e; p != lastRun; p = p.next) { int k = p.hash & sizeMask; - HashEntry n = (HashEntry)newTable[k]; - newTable[k] = new HashEntry(p.key, p.hash, - n, p.value); + HashEntry n = (HashEntry)newTable[k]; + newTable[k] = new HashEntry(p.key, p.hash, + n, p.value); } } } @@ -451,10 +470,11 @@ public class ConcurrentHashMap extends AbstractMap implements Concur int c = count - 1; HashEntry[] tab = table; int index = hash & (tab.length - 1); - HashEntry first = (HashEntry)tab[index]; - HashEntry e = first; - while (e != null && (e.hash != hash || !myHashingStrategy.equals(key,e.key))) + HashEntry first = (HashEntry)tab[index]; + HashEntry e = first; + while (e != null && (e.hash != hash || !myHashingStrategy.equals(key, e.key))) { e = e.next; + } V oldValue = null; if (e != null) { @@ -465,15 +485,17 @@ public class ConcurrentHashMap extends AbstractMap implements Concur // in list, but all preceding ones need to be // cloned. ++modCount; - HashEntry newFirst = e.next; - for (HashEntry p = first; p != e; p = p.next) - newFirst = new HashEntry(p.key, p.hash, newFirst, p.value); + HashEntry newFirst = e.next; + for (HashEntry p = first; p != e; p = p.next) { + newFirst = new HashEntry(p.key, p.hash, newFirst, p.value); + } tab[index] = newFirst; count = c; // write-volatile } } return oldValue; - } finally { + } + finally { unlock(); } } @@ -483,11 +505,13 @@ public class ConcurrentHashMap extends AbstractMap implements Concur lock(); try { HashEntry[] tab = table; - for (int i = 0; i < tab.length ; i++) + for (int i = 0; i < tab.length; i++) { tab[i] = null; + } ++modCount; count = 0; // write-volatile - } finally { + } + finally { unlock(); } } @@ -499,35 +523,38 @@ public class ConcurrentHashMap extends AbstractMap implements Concur /* ---------------- Public operations -------------- */ public ConcurrentHashMap(TObjectHashingStrategy hashingStrategy) { - this(DEFAULT_INITIAL_CAPACITY, DEFAULT_LOAD_FACTOR, DEFAULT_SEGMENTS,hashingStrategy); + this(DEFAULT_INITIAL_CAPACITY, DEFAULT_LOAD_FACTOR, DEFAULT_SEGMENTS, hashingStrategy); } /** * Creates a new, empty map with the specified initial * capacity, load factor, and concurrency level. * - * @param initialCapacity the initial capacity. The implementation - * performs internal sizing to accommodate this many elements. - * @param loadFactor the load factor threshold, used to control resizing. - * Resizing may be performed when the average number of elements per - * bin exceeds this threshold. + * @param initialCapacity the initial capacity. The implementation + * performs internal sizing to accommodate this many elements. + * @param loadFactor the load factor threshold, used to control resizing. + * Resizing may be performed when the average number of elements per + * bin exceeds this threshold. * @param concurrencyLevel the estimated number of concurrently - * updating threads. The implementation performs internal sizing - * to try to accommodate this many threads. + * updating threads. The implementation performs internal sizing + * to try to accommodate this many threads. * @throws IllegalArgumentException if the initial capacity is - * negative or the load factor or concurrencyLevel are - * nonpositive. + * negative or the load factor or concurrencyLevel are + * nonpositive. */ public ConcurrentHashMap(int initialCapacity, float loadFactor, int concurrencyLevel) { - this(initialCapacity,loadFactor, concurrencyLevel,null); + this(initialCapacity, loadFactor, concurrencyLevel, null); } - public ConcurrentHashMap(int initialCapacity, float loadFactor, int concurrencyLevel, TObjectHashingStrategy hashingStrategy) { - if (!(loadFactor > 0) || initialCapacity < 0 || concurrencyLevel <= 0) - throw new IllegalArgumentException(); - if (concurrencyLevel > MAX_SEGMENTS) + public ConcurrentHashMap(int initialCapacity, float loadFactor, int concurrencyLevel, TObjectHashingStrategy hashingStrategy) { + if (!(loadFactor > 0) || initialCapacity < 0 || concurrencyLevel <= 0) { + throw new IllegalArgumentException(); + } + + if (concurrencyLevel > MAX_SEGMENTS) { concurrencyLevel = MAX_SEGMENTS; + } // Find power-of-two sizes best matching arguments int sshift = 0; @@ -536,22 +563,27 @@ public class ConcurrentHashMap extends AbstractMap implements Concur ++sshift; ssize <<= 1; } - segmentShift = 12; // the middle of the hash is much more random that its HSB. Especially when we use TObjectHashingStrategy.CANONICAl as a hash provider + segmentShift = + 12; // the middle of the hash is much more random that its HSB. Especially when we use TObjectHashingStrategy.CANONICAl as a hash provider segmentMask = ssize - 1; segments = new Segment[ssize]; - if (initialCapacity > MAXIMUM_CAPACITY) + if (initialCapacity > MAXIMUM_CAPACITY) { initialCapacity = MAXIMUM_CAPACITY; + } int c = initialCapacity / ssize; - if (c * ssize < initialCapacity) + if (c * ssize < initialCapacity) { ++c; + } int cap = 1; - while (cap < c) + while (cap < c) { cap <<= 1; + } hashingStrategy = hashingStrategy == null ? this : hashingStrategy; - for (int i = 0; i < segments.length; ++i) - segments[i] = new Segment(cap, loadFactor,hashingStrategy); + for (int i = 0; i < segments.length; ++i) { + segments[i] = new Segment(cap, loadFactor, hashingStrategy); + } myHashingStrategy = hashingStrategy; } @@ -560,9 +592,9 @@ public class ConcurrentHashMap extends AbstractMap implements Concur * capacity, and with default load factor and concurrencyLevel. * * @param initialCapacity the initial capacity. The implementation - * performs internal sizing to accommodate this many elements. + * performs internal sizing to accommodate this many elements. * @throws IllegalArgumentException if the initial capacity of - * elements is negative. + * elements is negative. */ public ConcurrentHashMap(int initialCapacity) { this(initialCapacity, DEFAULT_LOAD_FACTOR, DEFAULT_SEGMENTS); @@ -581,10 +613,11 @@ public class ConcurrentHashMap extends AbstractMap implements Concur * map is created with a capacity of twice the number of mappings in * the given map or 11 (whichever is greater), and a default load factor * and concurrencyLevel. + * * @param t the map */ public ConcurrentHashMap(Map t) { - this(Math.max((int) (t.size() / DEFAULT_LOAD_FACTOR) + 1, + this(Math.max((int)(t.size() / DEFAULT_LOAD_FACTOR) + 1, 11), DEFAULT_LOAD_FACTOR, DEFAULT_SEGMENTS); putAll(t); @@ -606,10 +639,12 @@ public class ConcurrentHashMap extends AbstractMap implements Concur int[] mc = new int[segments.length]; int mcsum = 0; for (int i = 0; i < segments.length; ++i) { - if (segments[i].count != 0) + if (segments[i].count != 0) { return false; - else + } + else { mcsum += mc[i] = segments[i].modCount; + } } // If mcsum happens to be zero, then we know we got a snapshot // before any modifications at all were made. This is @@ -617,8 +652,9 @@ public class ConcurrentHashMap extends AbstractMap implements Concur if (mcsum != 0) { for (int i = 0; i < segments.length; ++i) { if (segments[i].count != 0 || - mc[i] != segments[i].modCount) + mc[i] != segments[i].modCount) { return false; + } } } return true; @@ -650,8 +686,9 @@ public class ConcurrentHashMap extends AbstractMap implements Concur } } } - if (check == sum) + if (check == sum) { break; + } } if (check != sum) { // Resort to locking all segments sum = 0; @@ -666,12 +703,12 @@ public class ConcurrentHashMap extends AbstractMap implements Concur /** * Returns the value to which the specified key is mapped in this table. * - * @param key a key in the table. - * @return the value to which the key is mapped in this table; - * null if the key is not mapped to any value in - * this table. - * @throws NullPointerException if the key is - * null. + * @param key a key in the table. + * @return the value to which the key is mapped in this table; + * null if the key is not mapped to any value in + * this table. + * @throws NullPointerException if the key is + * null. */ @Override public V get(Object key) { @@ -682,12 +719,12 @@ public class ConcurrentHashMap extends AbstractMap implements Concur /** * Tests if the specified object is a key in this table. * - * @param key possible key. - * @return true if and only if the specified object - * is a key in this table, as determined by the - * equals method; false otherwise. - * @throws NullPointerException if the key is - * null. + * @param key possible key. + * @return true if and only if the specified object + * is a key in this table, as determined by the + * equals method; false otherwise. + * @throws NullPointerException if the key is + * null. */ @Override public boolean containsKey(Object key) { @@ -704,7 +741,7 @@ public class ConcurrentHashMap extends AbstractMap implements Concur * @param value value whose presence in this map is to be tested. * @return true if this map maps one or more keys to the * specified value. - * @throws NullPointerException if the value is null. + * @throws NullPointerException if the value is null. */ @Override public boolean containsValue(@NotNull Object value) { @@ -721,8 +758,9 @@ public class ConcurrentHashMap extends AbstractMap implements Concur for (int i = 0; i < segments.length; ++i) { int c = segments[i].count; mcsum += mc[i] = segments[i].modCount; - if (segments[i].containsValue(value)) + if (segments[i].containsValue(value)) { return true; + } } boolean cleanSweep = true; if (mcsum != 0) { @@ -734,12 +772,14 @@ public class ConcurrentHashMap extends AbstractMap implements Concur } } } - if (cleanSweep) + if (cleanSweep) { return false; + } } // Resort to locking all segments - for (int i = 0; i < segments.length; ++i) + for (int i = 0; i < segments.length; ++i) { segments[i].lock(); + } boolean found = false; try { for (int i = 0; i < segments.length; ++i) { @@ -748,9 +788,11 @@ public class ConcurrentHashMap extends AbstractMap implements Concur break; } } - } finally { - for (int i = 0; i < segments.length; ++i) + } + finally { + for (int i = 0; i < segments.length; ++i) { segments[i].unlock(); + } } return found; } @@ -762,13 +804,13 @@ public class ConcurrentHashMap extends AbstractMap implements Concur * full compatibility with class {@link java.util.Hashtable}, * which supported this method prior to introduction of the * Java Collections framework. - - * @param value a value to search for. - * @return true if and only if some key maps to the - * value argument in this table as - * determined by the equals method; - * false otherwise. - * @throws NullPointerException if the value is null. + * + * @param value a value to search for. + * @return true if and only if some key maps to the + * value argument in this table as + * determined by the equals method; + * false otherwise. + * @throws NullPointerException if the value is null. */ public boolean contains(Object value) { return containsValue(value); @@ -778,16 +820,16 @@ public class ConcurrentHashMap extends AbstractMap implements Concur * Maps the specified key to the specified * value in this table. Neither the key nor the * value can be null. - * + *

*

The value can be retrieved by calling the get method * with a key that is equal to the original key. * - * @param key the table key. - * @param value the value. - * @return the previous value of the specified key in this table, - * or null if it did not have one. - * @throws NullPointerException if the key or value is - * null. + * @param key the table key. + * @param value the value. + * @return the previous value of the specified key in this table, + * or null if it did not have one. + * @throws NullPointerException if the key or value is + * null. */ @Override public V put(K key, @NotNull V value) { @@ -806,12 +848,13 @@ public class ConcurrentHashMap extends AbstractMap implements Concur * return map.get(key); * * Except that the action is performed atomically. - * @param key key with which the specified value is to be associated. + * + * @param key key with which the specified value is to be associated. * @param value value to be associated with the specified key. * @return previous value associated with specified key, or null - * if there was no mapping for key. + * if there was no mapping for key. * @throws NullPointerException if the specified key or value is - * null. + * null. */ @Override public V putIfAbsent(@NotNull K key, @NotNull V value) { @@ -822,7 +865,7 @@ public class ConcurrentHashMap extends AbstractMap implements Concur /** * Copies all of the mappings from the specified map to this one. - * + *

* These mappings replace any mappings that this map had for any of the * keys currently in the specified Map. * @@ -830,7 +873,9 @@ public class ConcurrentHashMap extends AbstractMap implements Concur */ @Override public void putAll(Map t) { - for (Iterator> it = (Iterator>) t.entrySet().iterator(); it.hasNext(); ) { + for ( + Iterator> it = (Iterator>)t.entrySet().iterator(); + it.hasNext(); ) { Entry e = it.next(); put(e.getKey(), e.getValue()); } @@ -840,11 +885,11 @@ public class ConcurrentHashMap extends AbstractMap implements Concur * Removes the key (and its corresponding value) from this * table. This method does nothing if the key is not in the table. * - * @param key the key that needs to be removed. - * @return the value to which the key had been mapped in this table, - * or null if the key did not have a mapping. - * @throws NullPointerException if the key is - * null. + * @param key the key that needs to be removed. + * @return the value to which the key had been mapped in this table, + * or null if the key did not have a mapping. + * @throws NullPointerException if the key is + * null. */ @Override public V remove(Object key) { @@ -862,11 +907,12 @@ public class ConcurrentHashMap extends AbstractMap implements Concur * } else return false; * * except that the action is performed atomically. - * @param key key with which the specified value is associated. + * + * @param key key with which the specified value is associated. * @param value value associated with the specified key. * @return true if the value was removed * @throws NullPointerException if the specified key is - * null. + * null. */ @Override public boolean remove(@NotNull Object key, Object value) { @@ -888,12 +934,13 @@ public class ConcurrentHashMap extends AbstractMap implements Concur * } else return false; * * except that the action is performed atomically. - * @param key key with which the specified value is associated. + * + * @param key key with which the specified value is associated. * @param oldValue value expected to be associated with the specified key. * @param newValue value to be associated with the specified key. * @return true if the value was replaced * @throws NullPointerException if the specified key or values are - * null. + * null. */ @Override public boolean replace(@NotNull K key, @NotNull V oldValue, @NotNull V newValue) { @@ -910,12 +957,13 @@ public class ConcurrentHashMap extends AbstractMap implements Concur * } else return null; * * except that the action is performed atomically. - * @param key key with which the specified value is associated. + * + * @param key key with which the specified value is associated. * @param value value to be associated with the specified key. * @return previous value associated with specified key, or null - * if there was no mapping for key. + * if there was no mapping for key. * @throws NullPointerException if the specified key or value is - * null. + * null. */ @Override public V replace(@NotNull K key, @NotNull V value) { @@ -996,17 +1044,17 @@ public class ConcurrentHashMap extends AbstractMap implements Concur * @return a collection view of the mappings contained in this map. */ @Override - public Set> entrySet() { - Set> es = entrySet; - return (es != null) ? es : (entrySet = (Set>) (Set) new EntrySet()); + public Set> entrySet() { + Set> es = entrySet; + return (es != null) ? es : (entrySet = (Set>)(Set)new EntrySet()); } /** * Returns an enumeration of the keys in this table. * - * @return an enumeration of the keys in this table. - * @see #keySet + * @return an enumeration of the keys in this table. + * @see #keySet */ public Enumeration keys() { return new KeyIterator(); @@ -1015,8 +1063,8 @@ public class ConcurrentHashMap extends AbstractMap implements Concur /** * Returns an enumeration of the values in this table. * - * @return an enumeration of the values in this table. - * @see #values + * @return an enumeration of the values in this table. + * @see #values */ public Enumeration elements() { return new ValueIterator(); @@ -1037,15 +1085,19 @@ public class ConcurrentHashMap extends AbstractMap implements Concur advance(); } - public boolean hasMoreElements() { return hasNext(); } + public boolean hasMoreElements() { + return hasNext(); + } final void advance() { - if (nextEntry != null && (nextEntry = nextEntry.next) != null) + if (nextEntry != null && (nextEntry = nextEntry.next) != null) { return; + } while (nextTableIndex >= 0) { - if ( (nextEntry = (HashEntry)currentTable[nextTableIndex--]) != null) + if ((nextEntry = (HashEntry)currentTable[nextTableIndex--]) != null) { return; + } } while (nextSegmentIndex >= 0) { @@ -1053,7 +1105,7 @@ public class ConcurrentHashMap extends AbstractMap implements Concur if (seg.count != 0) { currentTable = seg.table; for (int j = currentTable.length - 1; j >= 0; --j) { - if ( (nextEntry = (HashEntry)currentTable[j]) != null) { + if ((nextEntry = (HashEntry)currentTable[j]) != null) { nextTableIndex = j - 1; return; } @@ -1062,19 +1114,23 @@ public class ConcurrentHashMap extends AbstractMap implements Concur } } - public boolean hasNext() { return nextEntry != null; } + public boolean hasNext() { + return nextEntry != null; + } - HashEntry nextEntry() { - if (nextEntry == null) + HashEntry nextEntry() { + if (nextEntry == null) { throw new NoSuchElementException(); + } lastReturned = nextEntry; advance(); return lastReturned; } public void remove() { - if (lastReturned == null) + if (lastReturned == null) { throw new IllegalStateException(); + } ConcurrentHashMap.this.remove(lastReturned.key); lastReturned = null; } @@ -1082,18 +1138,27 @@ public class ConcurrentHashMap extends AbstractMap implements Concur final class KeyIterator extends HashIterator implements Iterator, Enumeration { @Override - public K next() { return super.nextEntry().key; } + public K next() { + return super.nextEntry().key; + } + @Override - public K nextElement() { return super.nextEntry().key; } + public K nextElement() { + return super.nextEntry().key; + } } final class ValueIterator extends HashIterator implements Iterator, Enumeration { @Override - public V next() { return super.nextEntry().value; } - @Override - public V nextElement() { return super.nextEntry().value; } - } + public V next() { + return super.nextEntry().value; + } + @Override + public V nextElement() { + return super.nextEntry().value; + } + } /** @@ -1102,50 +1167,56 @@ public class ConcurrentHashMap extends AbstractMap implements Concur * cannot return internal HashEntry objects. Instead, the iterator * itself acts as a forwarding pseudo-entry. */ - final class EntryIterator extends HashIterator implements Entry, Iterator> { + final class EntryIterator extends HashIterator implements Entry, Iterator> { @Override - public Entry next() { + public Entry next() { nextEntry(); return this; } @Override public K getKey() { - if (lastReturned == null) + if (lastReturned == null) { throw new IllegalStateException("Entry was removed"); + } return lastReturned.key; } @Override public V getValue() { - if (lastReturned == null) + if (lastReturned == null) { throw new IllegalStateException("Entry was removed"); + } return get(lastReturned.key); } @Override public V setValue(V value) { - if (lastReturned == null) + if (lastReturned == null) { throw new IllegalStateException("Entry was removed"); + } return put(lastReturned.key, value); } public boolean equals(Object o) { // If not acting as entry, just use default. - if (lastReturned == null) + if (lastReturned == null) { return super.equals(o); - if (!(o instanceof Entry)) + } + if (!(o instanceof Entry)) { return false; + } Entry e = (Entry)o; K o1 = getKey(); K o2 = (K)e.getKey(); - return (o1 == null ? o2 == null : myHashingStrategy.equals(o1,o2)) && eq(getValue(), e.getValue()); + return (o1 == null ? o2 == null : myHashingStrategy.equals(o1, o2)) && eq(getValue(), e.getValue()); } public int hashCode() { // If not acting as entry, just use default. - if (lastReturned == null) + if (lastReturned == null) { return super.hashCode(); + } Object k = getKey(); Object v = getValue(); @@ -1155,16 +1226,17 @@ public class ConcurrentHashMap extends AbstractMap implements Concur public String toString() { // If not acting as entry, just use default. - if (lastReturned == null) + if (lastReturned == null) { return super.toString(); - else + } + else { return getKey() + "=" + getValue(); + } } boolean eq(Object o1, Object o2) { return (o1 == null ? o2 == null : o1.equals(o2)); } - } final class KeySet extends AbstractSet { @@ -1172,34 +1244,42 @@ public class ConcurrentHashMap extends AbstractMap implements Concur public Iterator iterator() { return new KeyIterator(); } + @Override public int size() { return ConcurrentHashMap.this.size(); } + @Override public boolean contains(Object o) { return containsKey(o); } + @Override public boolean remove(Object o) { return ConcurrentHashMap.this.remove(o) != null; } + @Override public void clear() { ConcurrentHashMap.this.clear(); } + @Override public Object[] toArray() { Collection c = new ArrayList(); - for (Iterator i = iterator(); i.hasNext(); ) + for (Iterator i = iterator(); i.hasNext(); ) { c.add(i.next()); + } return c.toArray(); } + @Override public T[] toArray(T[] a) { Collection c = new ArrayList(); - for (Iterator i = iterator(); i.hasNext(); ) + for (Iterator i = iterator(); i.hasNext(); ) { c.add(i.next()); + } return c.toArray(a); } } @@ -1209,95 +1289,111 @@ public class ConcurrentHashMap extends AbstractMap implements Concur public Iterator iterator() { return new ValueIterator(); } + @Override public int size() { return ConcurrentHashMap.this.size(); } + @Override public boolean contains(Object o) { return containsValue(o); } + @Override public void clear() { ConcurrentHashMap.this.clear(); } + @Override public Object[] toArray() { Collection c = new ArrayList(); - for (Iterator i = iterator(); i.hasNext(); ) + for (Iterator i = iterator(); i.hasNext(); ) { c.add(i.next()); + } return c.toArray(); } + @Override public T[] toArray(T[] a) { Collection c = new ArrayList(); - for (Iterator i = iterator(); i.hasNext(); ) + for (Iterator i = iterator(); i.hasNext(); ) { c.add(i.next()); + } return c.toArray(a); } } - final class EntrySet extends AbstractSet> { + final class EntrySet extends AbstractSet> { @Override - public Iterator> iterator() { + public Iterator> iterator() { return new EntryIterator(); } + @Override public boolean contains(Object o) { - if (!(o instanceof Entry)) + if (!(o instanceof Entry)) { return false; - Entry e = (Entry)o; + } + Entry e = (Entry)o; V v = get(e.getKey()); return v != null && v.equals(e.getValue()); } + @Override public boolean remove(Object o) { - if (!(o instanceof Entry)) + if (!(o instanceof Entry)) { return false; - Entry e = (Entry)o; + } + Entry e = (Entry)o; return ConcurrentHashMap.this.remove(e.getKey(), e.getValue()); } + @Override public int size() { return ConcurrentHashMap.this.size(); } + @Override public void clear() { ConcurrentHashMap.this.clear(); } + @Override public Object[] toArray() { // Since we don't ordinarily have distinct Entry objects, we // must pack elements using exportable SimpleEntry - Collection> c = new ArrayList>(size()); - for (Iterator> i = iterator(); i.hasNext(); ) + Collection> c = new ArrayList>(size()); + for (Iterator> i = iterator(); i.hasNext(); ) { c.add(new SimpleEntry(i.next())); + } return c.toArray(); } + @Override public T[] toArray(T[] a) { - Collection> c = new ArrayList>(size()); - for (Iterator> i = iterator(); i.hasNext(); ) + Collection> c = new ArrayList>(size()); + for (Iterator> i = iterator(); i.hasNext(); ) { c.add(new SimpleEntry(i.next())); + } return c.toArray(a); } - } /** * This duplicates java.util.AbstractMap.SimpleEntry until this class * is made accessible. */ - final class SimpleEntry implements Entry { + final class SimpleEntry implements Entry { K key; V value; public SimpleEntry(K key, V value) { - this.key = key; + this.key = key; this.value = value; } - public SimpleEntry(Entry e) { + public SimpleEntry(Entry e) { key = e.getKey(); value = e.getValue(); } @@ -1320,16 +1416,17 @@ public class ConcurrentHashMap extends AbstractMap implements Concur } public boolean equals(Object o) { - if (!(o instanceof Entry)) + if (!(o instanceof Entry)) { return false; + } Entry e = (Entry)o; K o2 = (K)e.getKey(); - return (key == null ? o2 == null : myHashingStrategy.equals(key,o2)) && eq(value, e.getValue()); + return (key == null ? o2 == null : myHashingStrategy.equals(key, o2)) && eq(value, e.getValue()); } public int hashCode() { - return ((key == null) ? 0 : key.hashCode()) ^ - ((value == null) ? 0 : value.hashCode()); + return ((key == null) ? 0 : key.hashCode()) ^ + ((value == null) ? 0 : value.hashCode()); } public String toString() { @@ -1347,9 +1444,9 @@ public class ConcurrentHashMap extends AbstractMap implements Concur * Save the state of the ConcurrentHashMap * instance to a stream (i.e., * serialize it). + * * @param s the stream - * @serialData - * the key (Object) and value (Object) + * @serialData the key (Object) and value (Object) * for each key-value mapping, followed by a null pair. * The key-value mappings are emitted in no particular order. */ @@ -1362,12 +1459,13 @@ public class ConcurrentHashMap extends AbstractMap implements Concur try { HashEntry[] tab = seg.table; for (int i = 0; i < tab.length; ++i) { - for (HashEntry e = (HashEntry)tab[i]; e != null; e = e.next) { + for (HashEntry e = (HashEntry)tab[i]; e != null; e = e.next) { s.writeObject(e.key); s.writeObject(e.value); } } - } finally { + } + finally { seg.unlock(); } } @@ -1379,10 +1477,11 @@ public class ConcurrentHashMap extends AbstractMap implements Concur * Reconstitute the ConcurrentHashMap * instance from a stream (i.e., * deserialize it). + * * @param s the stream */ private void readObject(java.io.ObjectInputStream s) - throws IOException, ClassNotFoundException { + throws IOException, ClassNotFoundException { s.defaultReadObject(); // Initialize each segment to be minimally sized, and let grow. @@ -1391,11 +1490,12 @@ public class ConcurrentHashMap extends AbstractMap implements Concur } // Read the keys and values, and put the mappings in the table - for (;;) { - K key = (K) s.readObject(); - V value = (V) s.readObject(); - if (key == null) + for (; ; ) { + K key = (K)s.readObject(); + V value = (V)s.readObject(); + if (key == null) { break; + } put(key, value); } } @@ -1404,9 +1504,9 @@ public class ConcurrentHashMap extends AbstractMap implements Concur public int computeHashCode(final K object) { int h = object.hashCode(); h += ~(h << 9); - h ^= (h >>> 14); - h += (h << 4); - h ^= (h >>> 10); + h ^= (h >>> 14); + h += (h << 4); + h ^= (h >>> 10); return h; } diff --git a/platform/util/src/com/intellij/util/containers/ConcurrentRefHashMap.java b/platform/util/src/com/intellij/util/containers/ConcurrentRefHashMap.java index c795bd5f6750..8d7e0f74533b 100644 --- a/platform/util/src/com/intellij/util/containers/ConcurrentRefHashMap.java +++ b/platform/util/src/com/intellij/util/containers/ConcurrentRefHashMap.java @@ -33,19 +33,22 @@ import java.util.concurrent.ConcurrentMap; /** * Fully copied from java.util.WeakHashMap except "get" method optimization. */ -abstract class ConcurrentRefHashMap extends AbstractMap implements ConcurrentMap { - public interface Key{ +abstract class ConcurrentRefHashMap extends AbstractMap implements ConcurrentMap { + public interface Key { K get(); + V getValue(); + // MUST work even with gced references for the code in processQueue to work boolean equals(Object o); + int hashCode(); } protected abstract Key createKey(@NotNull K key, V value); - private static class HardKey implements Key { + private static class HardKey implements Key { private K myKey; private int myHash; private final V value; @@ -88,17 +91,22 @@ abstract class ConcurrentRefHashMap extends AbstractMap implements Con private final ConcurrentHashMap, V> myMap; private static final Key NULL_KEY = new Key() { @Override - public Object get() { return null; } + public Object get() { + return null; + } + @Override - public Object getValue() { return null; } + public Object getValue() { + return null; + } }; protected final ReferenceQueue myReferenceQueue = new ReferenceQueue(); boolean processQueue() { - Key wk; + Key wk; boolean processed = false; - while((wk = (Key)myReferenceQueue.poll()) != null){ + while ((wk = (Key)myReferenceQueue.poll()) != null) { V value = wk.getValue(); myMap.remove(wk, wk.hashCode(), value); processed = true; @@ -118,8 +126,12 @@ abstract class ConcurrentRefHashMap extends AbstractMap implements Con myMap = new ConcurrentHashMap, V>(); } - public ConcurrentRefHashMap(int initialCapacity, float loadFactor, int concurrencyLevel, @NotNull TObjectHashingStrategy hashingStrategy) { - myMap = new ConcurrentHashMap, V>(initialCapacity, loadFactor, concurrencyLevel, ConcurrentRefHashMap.convertKToKeyK(hashingStrategy)); + public ConcurrentRefHashMap(int initialCapacity, + float loadFactor, + int concurrencyLevel, + @NotNull TObjectHashingStrategy hashingStrategy) { + myMap = new ConcurrentHashMap, V>(initialCapacity, loadFactor, concurrencyLevel, + ConcurrentRefHashMap.convertKToKeyK(hashingStrategy)); } public ConcurrentRefHashMap(Map t) { @@ -128,11 +140,11 @@ abstract class ConcurrentRefHashMap extends AbstractMap implements Con } public ConcurrentRefHashMap(@NotNull final TObjectHashingStrategy hashingStrategy) { - myMap = new ConcurrentHashMap, V>(ConcurrentRefHashMap.convertKToKeyK(hashingStrategy)); + myMap = new ConcurrentHashMap, V>(ConcurrentRefHashMap.convertKToKeyK(hashingStrategy)); } @NotNull - private static TObjectHashingStrategy> convertKToKeyK(@NotNull final TObjectHashingStrategy hashingStrategy) { + private static TObjectHashingStrategy> convertKToKeyK(@NotNull final TObjectHashingStrategy hashingStrategy) { return new TObjectHashingStrategy>() { @Override public int computeHashCode(final Key object) { @@ -160,23 +172,23 @@ abstract class ConcurrentRefHashMap extends AbstractMap implements Con @Override public boolean containsKey(Object key) { // optimization: - if (key == null){ + if (key == null) { return myMap.containsKey(NULL_KEY); } - HardKey hardKey = createHardKey((K)key); + HardKey hardKey = createHardKey((K)key); boolean result = myMap.containsKey(hardKey); releaseHardKey(hardKey); return result; } - private static final ThreadLocal HARD_KEY = new ThreadLocal(){ + private static final ThreadLocal HARD_KEY = new ThreadLocal() { @Override protected HardKey initialValue() { return new HardKey(null, null); } }; - private static HardKey createHardKey(K key) { + private static HardKey createHardKey(K key) { HardKey hardKey = HARD_KEY.get(); hardKey.setKey(key); return hardKey; @@ -190,10 +202,10 @@ abstract class ConcurrentRefHashMap extends AbstractMap implements Con public V get(Object key) { //return myMap.get(WeakKey.create(key)); // optimization: - if (key == null){ + if (key == null) { return myMap.get(NULL_KEY); } - HardKey hardKey = createHardKey((K)key); + HardKey hardKey = createHardKey((K)key); V result = myMap.get(hardKey); releaseHardKey(hardKey); return result; @@ -211,7 +223,7 @@ abstract class ConcurrentRefHashMap extends AbstractMap implements Con processQueue(); // optimization: - if (key == null){ + if (key == null) { return myMap.remove(NULL_KEY); } HardKey hardKey = createHardKey(key); @@ -226,13 +238,13 @@ abstract class ConcurrentRefHashMap extends AbstractMap implements Con myMap.clear(); } - private static class Entry implements Map.Entry { - private final Map.Entry ent; + private static class Entry implements Map.Entry { + private final Map.Entry ent; private final K key; /* Strong reference to key, so that the GC will leave it alone as long as this Entry exists */ - Entry(Map.Entry ent, K key) { + Entry(Map.Entry ent, K key) { this.ent = ent; this.key = key; } @@ -269,27 +281,27 @@ abstract class ConcurrentRefHashMap extends AbstractMap implements Con } /* Internal class for entry sets */ - private class EntrySet extends AbstractSet> { - Set,V>> hashEntrySet = myMap.entrySet(); + private class EntrySet extends AbstractSet> { + Set, V>> hashEntrySet = myMap.entrySet(); @NotNull @Override - public Iterator> iterator() { - return new Iterator>() { - Iterator,V>> hashIterator = hashEntrySet.iterator(); - Entry next = null; + public Iterator> iterator() { + return new Iterator>() { + Iterator, V>> hashIterator = hashEntrySet.iterator(); + Entry next = null; @Override public boolean hasNext() { - while(hashIterator.hasNext()){ + while (hashIterator.hasNext()) { Map.Entry, V> ent = hashIterator.next(); Key wk = ent.getKey(); K k = null; - if (wk != null && (k = wk.get()) == null){ + if (wk != null && (k = wk.get()) == null) { /* Weak key has been cleared by GC */ continue; } - next = new Entry(ent, k); + next = new Entry(ent, k); return true; } return false; @@ -300,7 +312,7 @@ abstract class ConcurrentRefHashMap extends AbstractMap implements Con if (next == null && !hasNext()) { throw new NoSuchElementException(); } - Entry e = next; + Entry e = next; next = null; return e; } @@ -320,7 +332,7 @@ abstract class ConcurrentRefHashMap extends AbstractMap implements Con @Override public int size() { int j = 0; - for(Iterator i = iterator(); i.hasNext(); i.next()) j++; + for (Iterator i = iterator(); i.hasNext(); i.next()) j++; return j; } @@ -335,7 +347,7 @@ abstract class ConcurrentRefHashMap extends AbstractMap implements Con V hv = myMap.get(key); boolean toRemove = hv == null ? ev == null && myMap.containsKey(key) : hv.equals(ev); - if (toRemove){ + if (toRemove) { myMap.remove(key); } @@ -354,14 +366,13 @@ abstract class ConcurrentRefHashMap extends AbstractMap implements Con } return h; } - } - private Set> entrySet = null; + private Set> entrySet = null; @NotNull @Override - public Set> entrySet() { + public Set> entrySet() { if (entrySet == null) entrySet = new EntrySet(); return entrySet; } @@ -381,7 +392,7 @@ abstract class ConcurrentRefHashMap extends AbstractMap implements Con @Override public boolean replace(@NotNull final K key, @NotNull final V oldValue, @NotNull final V newValue) { processQueue(); - return myMap.replace(createKey(key, oldValue), oldValue,newValue); + return myMap.replace(createKey(key, oldValue), oldValue, newValue); } @Override diff --git a/platform/util/src/com/intellij/util/containers/ConcurrentRefValueHashMap.java b/platform/util/src/com/intellij/util/containers/ConcurrentRefValueHashMap.java index 61a3556d4172..e8bfd7d2577e 100644 --- a/platform/util/src/com/intellij/util/containers/ConcurrentRefValueHashMap.java +++ b/platform/util/src/com/intellij/util/containers/ConcurrentRefValueHashMap.java @@ -25,8 +25,8 @@ import java.util.*; import java.util.HashSet; import java.util.concurrent.ConcurrentMap; -abstract class ConcurrentRefValueHashMap implements ConcurrentMap { - private final ConcurrentHashMap> myMap; +abstract class ConcurrentRefValueHashMap implements ConcurrentMap { + private final ConcurrentHashMap> myMap; protected final ReferenceQueue myQueue = new ReferenceQueue(); public ConcurrentRefValueHashMap(@NotNull Map map) { @@ -37,21 +37,27 @@ abstract class ConcurrentRefValueHashMap implements ConcurrentMap { public ConcurrentRefValueHashMap() { myMap = new ConcurrentHashMap>(); } + public ConcurrentRefValueHashMap(int initialCapacity, float loadFactor, int concurrencyLevel) { myMap = new ConcurrentHashMap>(initialCapacity, loadFactor, concurrencyLevel); } - public ConcurrentRefValueHashMap(int initialCapacity, float loadFactor, int concurrencyLevel, @NotNull TObjectHashingStrategy hashingStrategy) { + + public ConcurrentRefValueHashMap(int initialCapacity, + float loadFactor, + int concurrencyLevel, + @NotNull TObjectHashingStrategy hashingStrategy) { myMap = new ConcurrentHashMap>(initialCapacity, loadFactor, concurrencyLevel, hashingStrategy); } protected interface MyValueReference { @NotNull K getKey(); + V get(); } private void processQueue() { - while(true){ + while (true) { MyValueReference ref = (MyValueReference)myQueue.poll(); if (ref == null) break; myMap.remove(ref.getKey(), ref); @@ -210,7 +216,7 @@ abstract class ConcurrentRefValueHashMap implements ConcurrentMap { @NonNls String s = "map size:" + size() + " ["; for (K k : myMap.keySet()) { Object v = get(k); - s += "'"+k + "': '" +v+"', "; + s += "'" + k + "': '" + v + "', "; } s += "] "; return s; diff --git a/platform/util/src/com/intellij/util/containers/ConcurrentSoftHashMap.java b/platform/util/src/com/intellij/util/containers/ConcurrentSoftHashMap.java index a32ca42d5295..bd7954fab5b0 100644 --- a/platform/util/src/com/intellij/util/containers/ConcurrentSoftHashMap.java +++ b/platform/util/src/com/intellij/util/containers/ConcurrentSoftHashMap.java @@ -29,7 +29,7 @@ import java.lang.ref.ReferenceQueue; import java.lang.ref.SoftReference; import java.util.Map; -public final class ConcurrentSoftHashMap extends ConcurrentRefHashMap { +public final class ConcurrentSoftHashMap extends ConcurrentRefHashMap { private static class SoftKey extends SoftReference implements ConcurrentRefHashMap.Key { private final int myHash; // Hashcode of key, stored here since the key may be tossed by the GC private final V value; diff --git a/platform/util/src/com/intellij/util/containers/ConcurrentWeakHashMap.java b/platform/util/src/com/intellij/util/containers/ConcurrentWeakHashMap.java index 93cc863a107f..4ae668421808 100644 --- a/platform/util/src/com/intellij/util/containers/ConcurrentWeakHashMap.java +++ b/platform/util/src/com/intellij/util/containers/ConcurrentWeakHashMap.java @@ -32,7 +32,7 @@ import java.util.Map; /** * Fully copied from java.util.WeakHashMap except "get" method optimization. */ -public final class ConcurrentWeakHashMap extends ConcurrentRefHashMap { +public final class ConcurrentWeakHashMap extends ConcurrentRefHashMap { private static class WeakKey extends WeakReference implements Key { private final int myHash; /* Hashcode of key, stored here since the key may be tossed by the GC */ private final V value;