HCOLL-119 removed the use of " public <K, V> SharedHashMap<K, V> create(File file, Class<K> kClass, Class<V> vClass) "

This commit is contained in:
Rob Austin
2014-07-24 16:59:53 +01:00
parent 9e98bcc4ed
commit 15a6608842
6 changed files with 688 additions and 823 deletions
@@ -106,7 +106,6 @@ public interface ChronicleMap<K, V> extends SharedHashMap<K, V>, ConcurrentMapLa
*/
default void replaceAll(BiFunction<? super K, ? super V, ? extends V> function) {
Objects.requireNonNull(function);
final BiConsumer<K, V> action = (k, v) -> {
while (!replace(k, v, function.apply(k, v))) {
// v changed or k is gone
@@ -88,9 +88,9 @@ import java.util.stream.Stream;
* same {@code hashCode()} is a sure way to slow down performance of any hash table. To ameliorate impact,
* when keys are {@link Comparable}, this class may use comparison order among keys to help break ties.
*
* <p>A {@link Set} projection of a ConcurrentHashMap may be created (using {@link #newKeySet()} or {@link
* #newKeySet(int)}), or viewed (using {@link #keySet(Object)} when only keys are of interest, and the mapped
* values are (perhaps transiently) not used or all take the same mapping value.
* <p>A {@link Set} projection of a ConcurrentHashMap may be created (using {@link )} or {@link # (int)}), or
* viewed (using {@link # (Object)} when only keys are of interest, and the mapped values are (perhaps
* transiently) not used or all take the same mapping value.
*
* <p>A ConcurrentHashMap can be used as scalable frequency map (a form of histogram or multiset) by using
* {@link java.util.concurrent.atomic.LongAdder} values and initializing via {@link #computeIfAbsent
@@ -183,7 +183,7 @@ import java.util.stream.Stream;
* @author Doug Lea
* @since 1.5
*/
public class ConcurrentHashMap<K, V> extends AbstractMap<K, V>
public abstract class ConcurrentHashMap<K, V> extends AbstractMap<K, V>
implements ConcurrentMap<K, V>, Serializable {
private static final long serialVersionUID = 7249069246763182397L;
@@ -722,10 +722,6 @@ public class ConcurrentHashMap<K, V> extends AbstractMap<K, V>
*/
private transient volatile CounterCell[] counterCells;
// views
private transient KeySetView<K, V> keySet;
private transient ValuesView<K, V> values;
private transient EntrySetView<K, V> entrySet;
/* ---------------- Public operations -------------- */
@@ -822,7 +818,6 @@ public class ConcurrentHashMap<K, V> extends AbstractMap<K, V>
}*/
/**
* Returns the value to which the specified key is mapped, or {@code null} if this map contains no mapping
* for the key.
@@ -910,7 +905,7 @@ public class ConcurrentHashMap<K, V> extends AbstractMap<K, V>
/**
* Implementation for put and putIfAbsent
*/
final V putVal(K key, V value, boolean onlyIfAbsent) {
V putVal(K key, V value, boolean onlyIfAbsent) {
if (key == null || value == null) throw new NullPointerException();
int hash = spread(key.hashCode());
int binCount = 0;
@@ -1107,64 +1102,6 @@ public class ConcurrentHashMap<K, V> extends AbstractMap<K, V>
addCount(delta, -1);
}
/**
* Returns a {@link Set} view of the keys contained in this map. The set is backed by the map, so changes
* to the map are reflected in the set, and vice-versa. The set supports element removal, which removes
* the corresponding mapping from this map, via the {@code Iterator.remove}, {@code Set.remove}, {@code
* removeAll}, {@code retainAll}, and {@code clear} operations. It does not support the {@code add} or
* {@code addAll} operations.
*
* <p>The view's iterators and spliterators are <a href="package-summary.html#Weakly"><i>weakly
* consistent</i></a>.
*
* <p>The view's {@code spliterator} reports {@link Spliterator#CONCURRENT}, {@link Spliterator#DISTINCT},
* and {@link Spliterator#NONNULL}.
*
* @return the set view
*/
public KeySetView<K, V> keySet() {
KeySetView<K, V> ks;
return (ks = keySet) != null ? ks : (keySet = new KeySetView<K, V>(this, null));
}
/**
* Returns a {@link Collection} view of the values contained in this map. The collection is backed by the
* map, so changes to the map are reflected in the collection, and vice-versa. The collection supports
* element removal, which removes the corresponding mapping from this map, via the {@code
* Iterator.remove}, {@code Collection.remove}, {@code removeAll}, {@code retainAll}, and {@code clear}
* operations. It does not support the {@code add} or {@code addAll} operations.
*
* <p>The view's iterators and spliterators are <a href="package-summary.html#Weakly"><i>weakly
* consistent</i></a>.
*
* <p>The view's {@code spliterator} reports {@link Spliterator#CONCURRENT} and {@link
* Spliterator#NONNULL}.
*
* @return the collection view
*/
public Collection<V> values() {
ValuesView<K, V> vs;
return (vs = values) != null ? vs : (values = new ValuesView<K, V>(this));
}
/**
* Returns a {@link Set} view of the mappings contained in this map. The set is backed by the map, so
* changes to the map are reflected in the set, and vice-versa. The set supports element removal, which
* removes the corresponding mapping from the map, via the {@code Iterator.remove}, {@code Set.remove},
* {@code removeAll}, {@code retainAll}, and {@code clear} operations.
*
* <p>The view's iterators and spliterators are <a href="package-summary.html#Weakly"><i>weakly
* consistent</i></a>.
*
* <p>The view's {@code spliterator} reports {@link Spliterator#CONCURRENT}, {@link Spliterator#DISTINCT},
* and {@link Spliterator#NONNULL}.
*
* @return the set view
*/
public Set<Map.Entry<K, V>> entrySet() {
EntrySetView<K, V> es;
return (es = entrySet) != null ? es : (entrySet = new EntrySetView<K, V>(this));
}
/**
* Returns the hash code value for this {@link Map}, i.e., the sum of, for each key-value pair in the map,
@@ -1471,10 +1408,6 @@ public class ConcurrentHashMap<K, V> extends AbstractMap<K, V>
}
/**
* If the value for the specified key is present, attempts to compute a new mapping given the key and its
* current mapped value. The entire method invocation is performed atomically. Some attempted update
@@ -1560,226 +1493,6 @@ public class ConcurrentHashMap<K, V> extends AbstractMap<K, V>
return val;
}
/**
* Attempts to compute a mapping for the specified key and its current mapped value (or {@code null} if
* there is no current mapping). The entire method invocation is performed atomically. Some attempted
* update operations on this map by other threads may be blocked while computation is in progress, so the
* computation should be short and simple, and must not attempt to update any other mappings of this Map.
*
* @param key key with which the specified value is to be associated
* @param remappingFunction the function to compute a value
* @return the new value associated with the specified key, or null if none
* @throws NullPointerException if the specified key or remappingFunction is null
* @throws IllegalStateException if the computation detectably attempts a recursive update to this map
* that would otherwise never complete
* @throws RuntimeException or Error if the remappingFunction does so, in which case the mapping is
* unchanged
*/
public V compute(K key,
BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
if (key == null || remappingFunction == null)
throw new NullPointerException();
int h = spread(key.hashCode());
V val = null;
int delta = 0;
int binCount = 0;
for (Node<K, V>[] tab = table; ; ) {
Node<K, V> f;
int n, i, fh;
if (tab == null || (n = tab.length) == 0)
tab = initTable();
else if ((f = tabAt(tab, i = (n - 1) & h)) == null) {
Node<K, V> r = new ReservationNode<K, V>();
synchronized (r) {
if (casTabAt(tab, i, null, r)) {
binCount = 1;
Node<K, V> node = null;
try {
if ((val = remappingFunction.apply(key, null)) != null) {
delta = 1;
node = new Node<K, V>(h, key, val, null);
}
} finally {
setTabAt(tab, i, node);
}
}
}
if (binCount != 0)
break;
} else if ((fh = f.hash) == MOVED)
tab = helpTransfer(tab, f);
else {
synchronized (f) {
if (tabAt(tab, i) == f) {
if (fh >= 0) {
binCount = 1;
for (Node<K, V> e = f, pred = null; ; ++binCount) {
K ek;
if (e.hash == h &&
((ek = e.key) == key ||
(ek != null && key.equals(ek)))) {
val = remappingFunction.apply(key, e.val);
if (val != null)
e.val = val;
else {
delta = -1;
Node<K, V> en = e.next;
if (pred != null)
pred.next = en;
else
setTabAt(tab, i, en);
}
break;
}
pred = e;
if ((e = e.next) == null) {
val = remappingFunction.apply(key, null);
if (val != null) {
delta = 1;
pred.next =
new Node<K, V>(h, key, val, null);
}
break;
}
}
} else if (f instanceof TreeBin) {
binCount = 1;
TreeBin<K, V> t = (TreeBin<K, V>) f;
TreeNode<K, V> r, p;
if ((r = t.root) != null)
p = r.findTreeNode(h, key, null);
else
p = null;
V pv = (p == null) ? null : p.val;
val = remappingFunction.apply(key, pv);
if (val != null) {
if (p != null)
p.val = val;
else {
delta = 1;
t.putTreeVal(h, key, val);
}
} else if (p != null) {
delta = -1;
if (t.removeTreeNode(p))
setTabAt(tab, i, untreeify(t.first));
}
}
}
}
if (binCount != 0) {
if (binCount >= TREEIFY_THRESHOLD)
treeifyBin(tab, i);
break;
}
}
}
if (delta != 0)
addCount((long) delta, binCount);
return val;
}
/**
* If the specified key is not already associated with a (non-null) value, associates it with the given
* value. Otherwise, replaces the value with the results of the given remapping function, or removes if
* {@code null}. The entire method invocation is performed atomically. Some attempted update operations
* on this map by other threads may be blocked while computation is in progress, so the computation should
* be short and simple, and must not attempt to update any other mappings of this Map.
*
* @param key key with which the specified value is to be associated
* @param value the value to use if absent
* @param remappingFunction the function to recompute a value if present
* @return the new value associated with the specified key, or null if none
* @throws NullPointerException if the specified key or the remappingFunction is null
* @throws RuntimeException or Error if the remappingFunction does so, in which case the mapping is
* unchanged
*/
public V merge(K key, V value, BiFunction<? super V, ? super V, ? extends V> remappingFunction) {
if (key == null || value == null || remappingFunction == null)
throw new NullPointerException();
int h = spread(key.hashCode());
V val = null;
int delta = 0;
int binCount = 0;
for (Node<K, V>[] tab = table; ; ) {
Node<K, V> f;
int n, i, fh;
if (tab == null || (n = tab.length) == 0)
tab = initTable();
else if ((f = tabAt(tab, i = (n - 1) & h)) == null) {
if (casTabAt(tab, i, null, new Node<K, V>(h, key, value, null))) {
delta = 1;
val = value;
break;
}
} else if ((fh = f.hash) == MOVED)
tab = helpTransfer(tab, f);
else {
synchronized (f) {
if (tabAt(tab, i) == f) {
if (fh >= 0) {
binCount = 1;
for (Node<K, V> e = f, pred = null; ; ++binCount) {
K ek;
if (e.hash == h &&
((ek = e.key) == key ||
(ek != null && key.equals(ek)))) {
val = remappingFunction.apply(e.val, value);
if (val != null)
e.val = val;
else {
delta = -1;
Node<K, V> en = e.next;
if (pred != null)
pred.next = en;
else
setTabAt(tab, i, en);
}
break;
}
pred = e;
if ((e = e.next) == null) {
delta = 1;
val = value;
pred.next =
new Node<K, V>(h, key, val, null);
break;
}
}
} else if (f instanceof TreeBin) {
binCount = 2;
TreeBin<K, V> t = (TreeBin<K, V>) f;
TreeNode<K, V> r = t.root;
TreeNode<K, V> p = (r == null) ? null :
r.findTreeNode(h, key, null);
val = (p == null) ? value :
remappingFunction.apply(p.val, value);
if (val != null) {
if (p != null)
p.val = val;
else {
delta = 1;
t.putTreeVal(h, key, val);
}
} else if (p != null) {
delta = -1;
if (t.removeTreeNode(p))
setTabAt(tab, i, untreeify(t.first));
}
}
}
}
if (binCount != 0) {
if (binCount >= TREEIFY_THRESHOLD)
treeifyBin(tab, i);
break;
}
}
}
if (delta != 0)
addCount((long) delta, binCount);
return val;
}
// Hashtable legacy methods
@@ -1837,46 +1550,7 @@ public class ConcurrentHashMap<K, V> extends AbstractMap<K, V>
return (n < 0L) ? 0L : n; // ignore transient negative values
}
/**
* Creates a new {@link Set} backed by a ConcurrentHashMap from the given type to {@code Boolean.TRUE}.
*
* @param <K> the element type of the returned set
* @return the new set
* @since 1.8
*/
public static <K> KeySetView<K, Boolean> newKeySet() {
return new KeySetView<K, Boolean>
(new ConcurrentHashMap<K, Boolean>(), Boolean.TRUE);
}
/**
* Creates a new {@link Set} backed by a ConcurrentHashMap from the given type to {@code Boolean.TRUE}.
*
* @param initialCapacity The implementation performs internal sizing to accommodate this many elements.
* @param <K> the element type of the returned set
* @return the new set
* @throws IllegalArgumentException if the initial capacity of elements is negative
* @since 1.8
*/
public static <K> KeySetView<K, Boolean> newKeySet(int initialCapacity) {
return new KeySetView<K, Boolean>
(new ConcurrentHashMap<K, Boolean>(initialCapacity), Boolean.TRUE);
}
/**
* Returns a {@link Set} view of the keys in this map, using the given common mapped value for any
* additions (i.e., {@link Collection#add} and {@link Collection#addAll(Collection)}). This is of course
* only appropriate if it is acceptable to use the same value for all additions from this view.
*
* @param mappedValue the mapped value to use for any additions
* @return the set view
* @throws NullPointerException if the mappedValue is null
*/
public KeySetView<K, V> keySet(V mappedValue) {
if (mappedValue == null)
throw new NullPointerException();
return new KeySetView<K, V>(this, mappedValue);
}
/* ---------------- Special Nodes -------------- */
@@ -3412,464 +3086,6 @@ public class ConcurrentHashMap<K, V> extends AbstractMap<K, V>
// Parallel bulk operations
/* ----------------Views -------------- */
/**
* Base class for views.
*/
abstract static class CollectionView<K, V, E>
implements Collection<E>, java.io.Serializable {
private static final long serialVersionUID = 7249069246763182397L;
final ConcurrentHashMap<K, V> map;
CollectionView(ConcurrentHashMap<K, V> map) {
this.map = map;
}
/**
* Returns the map backing this view.
*
* @return the map backing this view
*/
public ConcurrentHashMap<K, V> getMap() {
return map;
}
/**
* Removes all of the elements from this view, by removing all the mappings from the map backing this
* view.
*/
public final void clear() {
map.clear();
}
public final int size() {
return map.size();
}
public final boolean isEmpty() {
return map.isEmpty();
}
// implementations below rely on concrete classes supplying these
// abstract methods
/**
* Returns an iterator over the elements in this collection.
*
* <p>The returned iterator is <a href="package-summary.html#Weakly"><i>weakly consistent</i></a>.
*
* @return an iterator over the elements in this collection
*/
public abstract Iterator<E> iterator();
public abstract boolean contains(Object o);
public abstract boolean remove(Object o);
private static final String oomeMsg = "Required array size too large";
public final Object[] toArray() {
long sz = map.mappingCount();
if (sz > MAX_ARRAY_SIZE)
throw new OutOfMemoryError(oomeMsg);
int n = (int) sz;
Object[] r = new Object[n];
int i = 0;
for (E e : this) {
if (i == n) {
if (n >= MAX_ARRAY_SIZE)
throw new OutOfMemoryError(oomeMsg);
if (n >= MAX_ARRAY_SIZE - (MAX_ARRAY_SIZE >>> 1) - 1)
n = MAX_ARRAY_SIZE;
else
n += (n >>> 1) + 1;
r = Arrays.copyOf(r, n);
}
r[i++] = e;
}
return (i == n) ? r : Arrays.copyOf(r, i);
}
@SuppressWarnings("unchecked")
public final <T> T[] toArray(T[] a) {
long sz = map.mappingCount();
if (sz > MAX_ARRAY_SIZE)
throw new OutOfMemoryError(oomeMsg);
int m = (int) sz;
T[] r = (a.length >= m) ? a :
(T[]) java.lang.reflect.Array
.newInstance(a.getClass().getComponentType(), m);
int n = r.length;
int i = 0;
for (E e : this) {
if (i == n) {
if (n >= MAX_ARRAY_SIZE)
throw new OutOfMemoryError(oomeMsg);
if (n >= MAX_ARRAY_SIZE - (MAX_ARRAY_SIZE >>> 1) - 1)
n = MAX_ARRAY_SIZE;
else
n += (n >>> 1) + 1;
r = Arrays.copyOf(r, n);
}
r[i++] = (T) e;
}
if (a == r && i < n) {
r[i] = null; // null-terminate
return r;
}
return (i == n) ? r : Arrays.copyOf(r, i);
}
/**
* Returns a string representation of this collection. The string representation consists of the
* string representations of the collection's elements in the order they are returned by its iterator,
* enclosed in square brackets ({@code "[]"}). Adjacent elements are separated by the characters
* {@code ", "} (comma and space). Elements are converted to strings as by {@link
* String#valueOf(Object)}.
*
* @return a string representation of this collection
*/
public final String toString() {
StringBuilder sb = new StringBuilder();
sb.append('[');
Iterator<E> it = iterator();
if (it.hasNext()) {
for (; ; ) {
Object e = it.next();
sb.append(e == this ? "(this Collection)" : e);
if (!it.hasNext())
break;
sb.append(',').append(' ');
}
}
return sb.append(']').toString();
}
public final boolean containsAll(Collection<?> c) {
if (c != this) {
for (Object e : c) {
if (e == null || !contains(e))
return false;
}
}
return true;
}
public final boolean removeAll(Collection<?> c) {
if (c == null) throw new NullPointerException();
boolean modified = false;
for (Iterator<E> it = iterator(); it.hasNext(); ) {
if (c.contains(it.next())) {
it.remove();
modified = true;
}
}
return modified;
}
public final boolean retainAll(Collection<?> c) {
if (c == null) throw new NullPointerException();
boolean modified = false;
for (Iterator<E> it = iterator(); it.hasNext(); ) {
if (!c.contains(it.next())) {
it.remove();
modified = true;
}
}
return modified;
}
}
/**
* A view of a ConcurrentHashMap as a {@link Set} of keys, in which additions may optionally be enabled by
* mapping to a common value. This class cannot be directly instantiated. See {@link #keySet() keySet()},
* {@link #keySet(Object) keySet(V)}, {@link #newKeySet() newKeySet()}, {@link #newKeySet(int)
* newKeySet(int)}.
*
* @since 1.8
*/
public static class KeySetView<K, V> extends CollectionView<K, V, K>
implements Set<K>, java.io.Serializable {
private static final long serialVersionUID = 7249069246763182397L;
private final V value;
KeySetView(ConcurrentHashMap<K, V> map, V value) { // non-public
super(map);
this.value = value;
}
/**
* Returns the default mapped value for additions, or {@code null} if additions are not supported.
*
* @return the default mapped value for additions, or {@code null} if not supported
*/
public V getMappedValue() {
return value;
}
/**
* {@inheritDoc}
*
* @throws NullPointerException if the specified key is null
*/
public boolean contains(Object o) {
return map.containsKey(o);
}
/**
* Removes the key from this map view, by removing the key (and its corresponding value) from the
* backing map. This method does nothing if the key is not in the map.
*
* @param o the key to be removed from the backing map
* @return {@code true} if the backing map contained the specified key
* @throws NullPointerException if the specified key is null
*/
public boolean remove(Object o) {
return map.remove(o) != null;
}
/**
* @return an iterator over the keys of the backing map
*/
public Iterator<K> iterator() {
Node<K, V>[] t;
ConcurrentHashMap<K, V> m = map;
int f = (t = m.table) == null ? 0 : t.length;
return new KeyIterator<K, V>(t, f, 0, f, m);
}
/**
* Adds the specified key to this set view by mapping the key to the default mapped value in the
* backing map, if defined.
*
* @param e key to be added
* @return {@code true} if this set changed as a result of the call
* @throws NullPointerException if the specified key is null
* @throws UnsupportedOperationException if no default mapped value for additions was provided
*/
public boolean add(K e) {
V v;
if ((v = value) == null)
throw new UnsupportedOperationException();
return map.putVal(e, v, true) == null;
}
/**
* Adds all of the elements in the specified collection to this set, as if by calling {@link #add} on
* each one.
*
* @param c the elements to be inserted into this set
* @return {@code true} if this set changed as a result of the call
* @throws NullPointerException if the collection or any of its elements are {@code null}
* @throws UnsupportedOperationException if no default mapped value for additions was provided
*/
public boolean addAll(Collection<? extends K> c) {
boolean added = false;
V v;
if ((v = value) == null)
throw new UnsupportedOperationException();
for (K e : c) {
if (map.putVal(e, v, true) == null)
added = true;
}
return added;
}
public int hashCode() {
int h = 0;
for (K e : this)
h += e.hashCode();
return h;
}
public boolean equals(Object o) {
Set<?> c;
return ((o instanceof Set) &&
((c = (Set<?>) o) == this ||
(containsAll(c) && c.containsAll(this))));
}
public Spliterator<K> spliterator() {
Node<K, V>[] t;
ConcurrentHashMap<K, V> m = map;
long n = m.sumCount();
int f = (t = m.table) == null ? 0 : t.length;
return new KeySpliterator<K, V>(t, f, 0, f, n < 0L ? 0L : n);
}
public void forEach(Consumer<? super K> action) {
if (action == null) throw new NullPointerException();
Node<K, V>[] t;
if ((t = map.table) != null) {
Traverser<K, V> it = new Traverser<K, V>(t, t.length, 0, t.length);
for (Node<K, V> p; (p = it.advance()) != null; )
action.accept(p.key);
}
}
}
/**
* A view of a ConcurrentHashMap as a {@link Collection} of values, in which additions are disabled. This
* class cannot be directly instantiated. See {@link #values()}.
*/
static final class ValuesView<K, V> extends CollectionView<K, V, V>
implements Collection<V>, java.io.Serializable {
private static final long serialVersionUID = 2249069246763182397L;
ValuesView(ConcurrentHashMap<K, V> map) {
super(map);
}
public final boolean contains(Object o) {
return map.containsValue(o);
}
public final boolean remove(Object o) {
if (o != null) {
for (Iterator<V> it = iterator(); it.hasNext(); ) {
if (o.equals(it.next())) {
it.remove();
return true;
}
}
}
return false;
}
public final Iterator<V> iterator() {
ConcurrentHashMap<K, V> m = map;
Node<K, V>[] t;
int f = (t = m.table) == null ? 0 : t.length;
return new ValueIterator<K, V>(t, f, 0, f, m);
}
public final boolean add(V e) {
throw new UnsupportedOperationException();
}
public final boolean addAll(Collection<? extends V> c) {
throw new UnsupportedOperationException();
}
public Spliterator<V> spliterator() {
Node<K, V>[] t;
ConcurrentHashMap<K, V> m = map;
long n = m.sumCount();
int f = (t = m.table) == null ? 0 : t.length;
return new ValueSpliterator<K, V>(t, f, 0, f, n < 0L ? 0L : n);
}
public void forEach(Consumer<? super V> action) {
if (action == null) throw new NullPointerException();
Node<K, V>[] t;
if ((t = map.table) != null) {
Traverser<K, V> it = new Traverser<K, V>(t, t.length, 0, t.length);
for (Node<K, V> p; (p = it.advance()) != null; )
action.accept(p.val);
}
}
}
/**
* A view of a ConcurrentHashMap as a {@link Set} of (key, value) entries. This class cannot be directly
* instantiated. See {@link #entrySet()}.
*/
static final class EntrySetView<K, V> extends CollectionView<K, V, Map.Entry<K, V>>
implements Set<Map.Entry<K, V>>, java.io.Serializable {
private static final long serialVersionUID = 2249069246763182397L;
EntrySetView(ConcurrentHashMap<K, V> map) {
super(map);
}
public boolean contains(Object o) {
Object k, v, r;
Map.Entry<?, ?> e;
return ((o instanceof Map.Entry) &&
(k = (e = (Map.Entry<?, ?>) o).getKey()) != null &&
(r = map.get(k)) != null &&
(v = e.getValue()) != null &&
(v == r || v.equals(r)));
}
public boolean remove(Object o) {
Object k, v;
Map.Entry<?, ?> e;
return ((o instanceof Map.Entry) &&
(k = (e = (Map.Entry<?, ?>) o).getKey()) != null &&
(v = e.getValue()) != null &&
map.remove(k, v));
}
/**
* @return an iterator over the entries of the backing map
*/
public Iterator<Map.Entry<K, V>> iterator() {
ConcurrentHashMap<K, V> m = map;
Node<K, V>[] t;
int f = (t = m.table) == null ? 0 : t.length;
return new EntryIterator<K, V>(t, f, 0, f, m);
}
public boolean add(Entry<K, V> e) {
return map.putVal(e.getKey(), e.getValue(), false) == null;
}
public boolean addAll(Collection<? extends Entry<K, V>> c) {
boolean added = false;
for (Entry<K, V> e : c) {
if (add(e))
added = true;
}
return added;
}
public final int hashCode() {
int h = 0;
Node<K, V>[] t;
if ((t = map.table) != null) {
Traverser<K, V> it = new Traverser<K, V>(t, t.length, 0, t.length);
for (Node<K, V> p; (p = it.advance()) != null; ) {
h += p.hashCode();
}
}
return h;
}
public final boolean equals(Object o) {
Set<?> c;
return ((o instanceof Set) &&
((c = (Set<?>) o) == this ||
(containsAll(c) && c.containsAll(this))));
}
public Spliterator<Map.Entry<K, V>> spliterator() {
Node<K, V>[] t;
ConcurrentHashMap<K, V> m = map;
long n = m.sumCount();
int f = (t = m.table) == null ? 0 : t.length;
return new EntrySpliterator<K, V>(t, f, 0, f, n < 0L ? 0L : n, m);
}
public void forEach(Consumer<? super Map.Entry<K, V>> action) {
if (action == null) throw new NullPointerException();
Node<K, V>[] t;
if ((t = map.table) != null) {
Traverser<K, V> it = new Traverser<K, V>(t, t.length, 0, t.length);
for (Node<K, V> p; (p = it.advance()) != null; )
action.accept(new MapEntry<K, V>(p.key, p.val, map));
}
}
}
// -------------------------------------------------------
/**
@@ -4384,7 +3600,6 @@ public class ConcurrentHashMap<K, V> extends AbstractMap<K, V>
}
@SuppressWarnings("serial")
static final class ReduceKeysTask<K, V>
extends BulkTask<K, V, K> {
@@ -42,12 +42,12 @@ public interface ConcurrentMapLamdadSupport<K, V> {
*
* @return the set view
*/
public net.openhft.collections.ConcurrentHashMap.KeySetView<K, V> keySet();
AbstractVanillaSharedMap.KeySetView<K, V> keySet();
long mappingCount();
net.openhft.collections.ConcurrentHashMap.KeySetView<K, V> keySet(V mappedValue);
net.openhft.collections.KeySetView<K, V> keySet(V mappedValue);
void forEach(long parallelismThreshold,
BiConsumer<? super K, ? super V> action);
@@ -0,0 +1,89 @@
/*
* Copyright 2014 Higher Frequency Trading
* <p/>
* http://www.higherfrequencytrading.com
* <p/>
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* <p/>
* http://www.apache.org/licenses/LICENSE-2.0
* <p/>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.openhft.collections;
import java.util.Collection;
import java.util.Iterator;
import java.util.Set;
import java.util.Spliterator;
import java.util.function.Consumer;
/**
* @author Rob Austin.
*/
public interface KeySetView<K, V> extends Collection<K>, java.io.Serializable, Set<K> {
/**
* Returns the default mapped value for additions, or {@code null} if additions are not supported.
*
* @return the default mapped value for additions, or {@code null} if not supported
*/
V getMappedValue();
/**
* {@inheritDoc}
*
* @throws NullPointerException if the specified key is null
*/
boolean contains(Object o);
/**
* Removes the key from this map view, by removing the key (and its corresponding value) from the backing
* map. This method does nothing if the key is not in the map.
*
* @param o the key to be removed from the backing map
* @return {@code true} if the backing map contained the specified key
* @throws NullPointerException if the specified key is null
*/
boolean remove(Object o);
/**
* @return an iterator over the keys of the backing map
*/
Iterator<K> iterator();
/**
* Adds the specified key to this set view by mapping the key to the default mapped value in the backing
* map, if defined.
*
* @param e key to be added
* @return {@code true} if this set changed as a result of the call
* @throws NullPointerException if the specified key is null
* @throws UnsupportedOperationException if no default mapped value for additions was provided
*/
boolean add(K e);
/**
* Adds all of the elements in the specified collection to this set, as if by calling {@link #add} on each
* one.
*
* @param c the elements to be inserted into this set
* @return {@code true} if this set changed as a result of the call
* @throws NullPointerException if the collection or any of its elements are {@code null}
* @throws UnsupportedOperationException if no default mapped value for additions was provided
*/
boolean addAll(Collection<? extends K> c);
int hashCode();
boolean equals(Object o);
Spliterator<K> spliterator();
void forEach(Consumer<? super K> action);
}
@@ -28,7 +28,6 @@ import net.openhft.lang.io.serialization.ObjectSerializer;
import net.openhft.lang.io.serialization.impl.VanillaBytesMarshallerFactory;
import net.openhft.lang.model.Byteable;
import net.openhft.lang.model.DataValueClasses;
import net.openhft.lang.model.constraints.NotNull;
import net.openhft.lang.model.constraints.Nullable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -72,11 +71,542 @@ abstract class AbstractVanillaSharedMap<K, V> extends net.openhft.collections.Co
private SharedHashMapBuilder builder;
// views
transient ValuesView<K, V> values;
transient EntrySetView<K, V> entrySet;
transient KeySetView<K, V> keySet;
/* ----------------Views -------------- */
/**
* Base class for views.
*/
abstract static class CollectionView<K, V, E>
implements Collection<E>, java.io.Serializable {
private static final long serialVersionUID = 7249069246763182397L;
final AbstractVanillaSharedMap<K, V> map;
CollectionView(AbstractVanillaSharedMap<K, V> map) {
this.map = map;
}
/**
* Returns the map backing this view.
*
* @return the map backing this view
*/
public AbstractVanillaSharedMap<K, V> getMap() {
return map;
}
/**
* Removes all of the elements from this view, by removing all the mappings from the map backing this
* view.
*/
public final void clear() {
map.clear();
}
public final int size() {
return map.size();
}
public final boolean isEmpty() {
return map.isEmpty();
}
// implementations below rely on concrete classes supplying these
// abstract methods
/**
* Returns an iterator over the elements in this collection.
*
* <p>The returned iterator is <a href="package-summary.html#Weakly"><i>weakly consistent</i></a>.
*
* @return an iterator over the elements in this collection
*/
public abstract Iterator<E> iterator();
public abstract boolean contains(Object o);
public abstract boolean remove(Object o);
private static final String oomeMsg = "Required array size too large";
public final Object[] toArray() {
long sz = map.mappingCount();
if (sz > MAX_ARRAY_SIZE)
throw new OutOfMemoryError(oomeMsg);
int n = (int) sz;
Object[] r = new Object[n];
int i = 0;
for (E e : this) {
if (i == n) {
if (n >= MAX_ARRAY_SIZE)
throw new OutOfMemoryError(oomeMsg);
if (n >= MAX_ARRAY_SIZE - (MAX_ARRAY_SIZE >>> 1) - 1)
n = MAX_ARRAY_SIZE;
else
n += (n >>> 1) + 1;
r = Arrays.copyOf(r, n);
}
r[i++] = e;
}
return (i == n) ? r : Arrays.copyOf(r, i);
}
@SuppressWarnings("unchecked")
public final <T> T[] toArray(T[] a) {
long sz = map.mappingCount();
if (sz > MAX_ARRAY_SIZE)
throw new OutOfMemoryError(oomeMsg);
int m = (int) sz;
T[] r = (a.length >= m) ? a :
(T[]) java.lang.reflect.Array
.newInstance(a.getClass().getComponentType(), m);
int n = r.length;
int i = 0;
for (E e : this) {
if (i == n) {
if (n >= MAX_ARRAY_SIZE)
throw new OutOfMemoryError(oomeMsg);
if (n >= MAX_ARRAY_SIZE - (MAX_ARRAY_SIZE >>> 1) - 1)
n = MAX_ARRAY_SIZE;
else
n += (n >>> 1) + 1;
r = Arrays.copyOf(r, n);
}
r[i++] = (T) e;
}
if (a == r && i < n) {
r[i] = null; // null-terminate
return r;
}
return (i == n) ? r : Arrays.copyOf(r, i);
}
/**
* Returns a string representation of this collection. The string representation consists of the
* string representations of the collection's elements in the order they are returned by its iterator,
* enclosed in square brackets ({@code "[]"}). Adjacent elements are separated by the characters
* {@code ", "} (comma and space). Elements are converted to strings as by {@link
* String#valueOf(Object)}.
*
* @return a string representation of this collection
*/
public final String toString() {
StringBuilder sb = new StringBuilder();
sb.append('[');
Iterator<E> it = iterator();
if (it.hasNext()) {
for (; ; ) {
Object e = it.next();
sb.append(e == this ? "(this Collection)" : e);
if (!it.hasNext())
break;
sb.append(',').append(' ');
}
}
return sb.append(']').toString();
}
public final boolean containsAll(Collection<?> c) {
if (c != this) {
for (Object e : c) {
if (e == null || !contains(e))
return false;
}
}
return true;
}
public final boolean removeAll(Collection<?> c) {
if (c == null) throw new NullPointerException();
boolean modified = false;
for (Iterator<E> it = iterator(); it.hasNext(); ) {
if (c.contains(it.next())) {
it.remove();
modified = true;
}
}
return modified;
}
public final boolean retainAll(Collection<?> c) {
if (c == null) throw new NullPointerException();
boolean modified = false;
for (Iterator<E> it = iterator(); it.hasNext(); ) {
if (!c.contains(it.next())) {
it.remove();
modified = true;
}
}
return modified;
}
}
/**
* A view of a ConcurrentHashMap as a {@link Collection} of values, in which additions are disabled. This
* class cannot be directly instantiated. See {@link #values()}.
*/
static final class ValuesView<K, V> extends CollectionView<K, V, V>
implements Collection<V>, java.io.Serializable {
private static final long serialVersionUID = 2249069246763182397L;
ValuesView(AbstractVanillaSharedMap<K, V> map) {
super(map);
}
public final boolean contains(Object o) {
return map.containsValue(o);
}
public final boolean remove(Object o) {
if (o != null) {
for (Iterator<V> it = iterator(); it.hasNext(); ) {
if (o.equals(it.next())) {
it.remove();
return true;
}
}
}
return false;
}
public final Iterator<V> iterator() {
ConcurrentHashMap<K, V> m = map;
Node<K, V>[] t;
int f = (t = m.table) == null ? 0 : t.length;
return new ValueIterator<K, V>(t, f, 0, f, m);
}
public final boolean add(V e) {
throw new UnsupportedOperationException();
}
public final boolean addAll(Collection<? extends V> c) {
throw new UnsupportedOperationException();
}
public Spliterator<V> spliterator() {
Node<K, V>[] t;
ConcurrentHashMap<K, V> m = map;
long n = m.sumCount();
int f = (t = m.table) == null ? 0 : t.length;
return new ValueSpliterator<K, V>(t, f, 0, f, n < 0L ? 0L : n);
}
public void forEach(Consumer<? super V> action) {
if (action == null) throw new NullPointerException();
Node<K, V>[] t;
if ((t = map.table) != null) {
Traverser<K, V> it = new Traverser<K, V>(t, t.length, 0, t.length);
for (Node<K, V> p; (p = it.advance()) != null; )
action.accept(p.val);
}
}
}
/**
* A view of a ConcurrentHashMap as a {@link Set} of (key, value) entries. This class cannot be directly
* instantiated. See {@link #entrySet()}.
*/
static final class EntrySetView<K, V> extends CollectionView<K, V, Map.Entry<K, V>>
implements Set<Map.Entry<K, V>>, java.io.Serializable {
private static final long serialVersionUID = 2249069246763182397L;
EntrySetView(AbstractVanillaSharedMap<K, V> map) {
super(map);
}
public boolean contains(Object o) {
Object k, v, r;
Map.Entry<?, ?> e;
return ((o instanceof Map.Entry) &&
(k = (e = (Map.Entry<?, ?>) o).getKey()) != null &&
(r = map.get(k)) != null &&
(v = e.getValue()) != null &&
(v == r || v.equals(r)));
}
public boolean remove(Object o) {
Object k, v;
Map.Entry<?, ?> e;
return ((o instanceof Map.Entry) &&
(k = (e = (Map.Entry<?, ?>) o).getKey()) != null &&
(v = e.getValue()) != null &&
map.remove(k, v));
}
/**
* @return an iterator over the entries of the backing map
*/
public Iterator<Map.Entry<K, V>> iterator() {
return new EntryIterator<K, V>(map);
}
public boolean add(Entry<K, V> e) {
return map.putVal(e.getKey(), e.getValue(), false) == null;
}
public boolean addAll(Collection<? extends Entry<K, V>> c) {
boolean added = false;
for (Entry<K, V> e : c) {
if (add(e))
added = true;
}
return added;
}
public final int hashCode() {
int h = 0;
Node<K, V>[] t;
if ((t = map.table) != null) {
Traverser<K, V> it = new Traverser<K, V>(t, t.length, 0, t.length);
for (Node<K, V> p; (p = it.advance()) != null; ) {
h += p.hashCode();
}
}
return h;
}
public final boolean equals(Object o) {
Set<?> c;
return ((o instanceof Set) &&
((c = (Set<?>) o) == this ||
(containsAll(c) && c.containsAll(this))));
}
public Spliterator<Map.Entry<K, V>> spliterator() {
Node<K, V>[] t;
ConcurrentHashMap<K, V> m = map;
long n = m.sumCount();
int f = (t = m.table) == null ? 0 : t.length;
return new EntrySpliterator<K, V>(t, f, 0, f, n < 0L ? 0L : n, m);
}
public void forEach(Consumer<? super Map.Entry<K, V>> action) {
if (action == null) throw new NullPointerException();
Node<K, V>[] t;
if ((t = map.table) != null) {
Traverser<K, V> it = new Traverser<K, V>(t, t.length, 0, t.length);
for (Node<K, V> p; (p = it.advance()) != null; )
action.accept(new MapEntry<K, V>(p.key, p.val, map));
}
}
}
/**
* Creates a new {@link Set} backed by a ConcurrentHashMap from the given type to {@code Boolean.TRUE}.
*
* @param <K> the element type of the returned set
* @return the new set
* @since 1.8
*/
public static <K> KeySetView<K, Boolean> newKeySet() {
final SharedHashMapBuilder<Integer, String> builder = SharedHashMapBuilder.of(Integer.class,
String.class);
try {
final AbstractVanillaSharedMap chronicleMap = (AbstractVanillaSharedMap) builder.clone().vClass(Boolean.class).file(null)
.create();
return new KeySetView<K, Boolean>
(chronicleMap, Boolean.TRUE);
} catch (IOException e) {
throw new IllegalStateException(e);
}
}
/**
* Creates a new {@link Set} backed by a ConcurrentHashMap from the given type to {@code Boolean.TRUE}.
*
* @param initialCapacity The implementation performs internal sizing to accommodate this many elements.
* @param <K> the element type of the returned set
* @return the new set
* @throws IllegalArgumentException if the initial capacity of elements is negative
* @since 1.8
*/
public static <K> KeySetView<K, Boolean> newKeySet(int initialCapacity) {
return newKeySet();
}
/**
* Returns a {@link Set} view of the keys in this map, using the given common mapped value for any
* additions (i.e., {@link Collection#add} and {@link Collection#addAll(Collection)}). This is of course
* only appropriate if it is acceptable to use the same value for all additions from this view.
*
* @param mappedValue the mapped value to use for any additions
* @return the set view
* @throws NullPointerException if the mappedValue is null
*/
public KeySetView<K, V> keySet(V mappedValue) {
if (mappedValue == null)
throw new NullPointerException();
return new KeySetView<K, V>(this, mappedValue);
}
/**
* A view of a ConcurrentHashMap as a {@link Set} of keys, in which additions may optionally be enabled by
* mapping to a common value. This class cannot be directly instantiated. See {@link #keySet() keySet()},
* {@link #keySet(Object) keySet(V)}, {@link #newKeySet() newKeySet()}, {@link #newKeySet(int)
* newKeySet(int)}.
*
* @since 1.8
*/
public static class KeySetView<K, V> extends CollectionView<K, V, K>
implements Set<K>, java.io.Serializable, net.openhft.collections.KeySetView<K, V> {
private static final long serialVersionUID = 7249069246763182397L;
private final V value;
KeySetView(AbstractVanillaSharedMap<K, V> map, V value) { // non-public
super(map);
this.value = value;
}
/**
* Returns the default mapped value for additions, or {@code null} if additions are not supported.
*
* @return the default mapped value for additions, or {@code null} if not supported
*/
public V getMappedValue() {
return value;
}
/**
* {@inheritDoc}
*
* @throws NullPointerException if the specified key is null
*/
public boolean contains(Object o) {
return map.containsKey(o);
}
/**
* Removes the key from this map view, by removing the key (and its corresponding value) from the
* backing map. This method does nothing if the key is not in the map.
*
* @param o the key to be removed from the backing map
* @return {@code true} if the backing map contained the specified key
* @throws NullPointerException if the specified key is null
*/
public boolean remove(Object o) {
return map.remove(o) != null;
}
/**
* @return an iterator over the keys of the backing map
*/
public Iterator<K> iterator() {
Node<K, V>[] t;
ConcurrentHashMap<K, V> m = map;
int f = (t = m.table) == null ? 0 : t.length;
return new KeyIterator<K, V>(t, f, 0, f, m);
}
/**
* Adds the specified key to this set view by mapping the key to the default mapped value in the
* backing map, if defined.
*
* @param e key to be added
* @return {@code true} if this set changed as a result of the call
* @throws NullPointerException if the specified key is null
* @throws UnsupportedOperationException if no default mapped value for additions was provided
*/
public boolean add(K e) {
V v;
if ((v = value) == null)
throw new UnsupportedOperationException();
return map.putVal(e, v, true) == null;
}
/**
* Adds all of the elements in the specified collection to this set, as if by calling {@link #add} on
* each one.
*
* @param c the elements to be inserted into this set
* @return {@code true} if this set changed as a result of the call
* @throws NullPointerException if the collection or any of its elements are {@code null}
* @throws UnsupportedOperationException if no default mapped value for additions was provided
*/
public boolean addAll(Collection<? extends K> c) {
boolean added = false;
V v;
if ((v = value) == null)
throw new UnsupportedOperationException();
for (K e : c) {
if (map.putVal(e, v, true) == null)
added = true;
}
return added;
}
public int hashCode() {
int h = 0;
for (K e : this)
h += e.hashCode();
return h;
}
public boolean equals(Object o) {
Set<?> c;
return ((o instanceof Set) &&
((c = (Set<?>) o) == this ||
(containsAll(c) && c.containsAll(this))));
}
public Spliterator<K> spliterator() {
Node<K, V>[] t;
ConcurrentHashMap<K, V> m = map;
long n = m.sumCount();
int f = (t = m.table) == null ? 0 : t.length;
return new KeySpliterator<K, V>(t, f, 0, f, n < 0L ? 0L : n);
}
public void forEach(Consumer<? super K> action) {
if (action == null) throw new NullPointerException();
Node<K, V>[] t;
if ((t = map.table) != null) {
Traverser<K, V> it = new Traverser<K, V>(t, t.length, 0, t.length);
for (Node<K, V> p; (p = it.advance()) != null; )
action.accept(p.key);
}
}
}
/**
* Returns a {@link Set} view of the keys contained in this map. The set is backed by the map, so changes
* to the map are reflected in the set, and vice-versa. The set supports element removal, which removes
* the corresponding mapping from this map, via the {@code Iterator.remove}, {@code Set.remove}, {@code
* removeAll}, {@code retainAll}, and {@code clear} operations. It does not support the {@code add} or
* {@code addAll} operations.
*
* <p>The view's iterators and spliterators are <a href="package-summary.html#Weakly"><i>weakly
* consistent</i></a>.
*
* <p>The view's {@code spliterator} reports {@link Spliterator#CONCURRENT}, {@link Spliterator#DISTINCT},
* and {@link Spliterator#NONNULL}.
*
* @return the set view
*/
public AbstractVanillaSharedMap.KeySetView<K, V> keySet() {
KeySetView<K, V> ks;
return (ks = keySet) != null ? ks : (keySet = new KeySetView<K, V>(this, null));
}
// todo consider a better way to do this so that is is not creating an entry object each time
public void forEach(BiConsumer<? super K, ? super V> action) {
if (action == null) throw new NullPointerException();
final EntryIterator entryIterator = new EntryIterator();
final EntryIterator entryIterator = new EntryIterator(this);
for (Entry<K, V> e = entryIterator.next(); entryIterator.hasNext(); e = entryIterator.next()) {
action.accept(e.getKey(), e.getValue());
@@ -887,8 +1417,6 @@ abstract class AbstractVanillaSharedMap<K, V> extends net.openhft.collections.Co
final boolean putReturnsNull;
final boolean removeReturnsNull;
transient Set<Map.Entry<K, V>> entrySet;
public AbstractVanillaSharedMap(SharedHashMapBuilder builder,
Class<K> kClass, Class<V> vClass) throws IOException {
@@ -1099,7 +1627,7 @@ abstract class AbstractVanillaSharedMap<K, V> extends net.openhft.collections.Co
@Override
public V put(K key, V value) {
super.put(key, value);
return put0(key, value, true);
return putVal(key, value, true);
}
@@ -1108,10 +1636,11 @@ abstract class AbstractVanillaSharedMap<K, V> extends net.openhft.collections.Co
*/
@Override
public V putIfAbsent(K key, V value) {
return put0(key, value, false);
return putVal(key, value, false);
}
private V put0(K key, V value, boolean replaceIfPresent) {
V putVal(K key, V value, boolean replaceIfPresent) {
super.putVal(key, value, replaceIfPresent);
checkKey(key);
checkValue(value);
Bytes keyBytes = getKeyAsBytes(key);
@@ -1170,6 +1699,7 @@ abstract class AbstractVanillaSharedMap<K, V> extends net.openhft.collections.Co
return segments[segmentNum].acquire(keyBytes, key, value, segmentHash, create);
}
/**
* {@inheritDoc}
*/
@@ -1190,15 +1720,45 @@ abstract class AbstractVanillaSharedMap<K, V> extends net.openhft.collections.Co
segment.clear();
}
/**
* {@inheritDoc}
* Returns a {@link Collection} view of the values contained in this map. The collection is backed by the
* map, so changes to the map are reflected in the collection, and vice-versa. The collection supports
* element removal, which removes the corresponding mapping from this map, via the {@code
* Iterator.remove}, {@code Collection.remove}, {@code removeAll}, {@code retainAll}, and {@code clear}
* operations. It does not support the {@code add} or {@code addAll} operations.
*
* <p>The view's iterators and spliterators are <a href="package-summary.html#Weakly"><i>weakly
* consistent</i></a>.
*
* <p>The view's {@code spliterator} reports {@link Spliterator#CONCURRENT} and {@link
* Spliterator#NONNULL}.
*
* @return the collection view
*/
@NotNull
@Override
public Set<Entry<K, V>> entrySet() {
return (entrySet != null) ? entrySet : (entrySet = new EntrySet());
public Collection<V> values() {
ValuesView<K, V> vs;
return (vs = values) != null ? vs : (values = new ValuesView<K, V>(this));
}
/**
* Returns a {@link Set} view of the mappings contained in this map. The set is backed by the map, so
* changes to the map are reflected in the set, and vice-versa. The set supports element removal, which
* removes the corresponding mapping from the map, via the {@code Iterator.remove}, {@code Set.remove},
* {@code removeAll}, {@code retainAll}, and {@code clear} operations.
*
* <p>The view's iterators and spliterators are <a href="package-summary.html#Weakly"><i>weakly
* consistent</i></a>.
*
* <p>The view's {@code spliterator} reports {@link Spliterator#CONCURRENT}, {@link Spliterator#DISTINCT},
* and {@link Spliterator#NONNULL}.
*
* @return the set view
*/
public Set<Map.Entry<K, V>> entrySet() {
EntrySetView<K, V> es;
return (es = entrySet) != null ? es : (entrySet = new EntrySetView<K, V>(this));
}
/**
* {@inheritDoc}
@@ -2139,16 +2699,19 @@ abstract class AbstractVanillaSharedMap<K, V> extends net.openhft.collections.Co
}
}
final class EntryIterator implements Iterator<Entry<K, V>>, IntIntMultiMap.EntryConsumer {
static final class EntryIterator<K, V> implements Iterator<Entry<K, V>>, IntIntMultiMap.EntryConsumer {
int segmentIndex = segments.length;
private final AbstractVanillaSharedMap map;
private int segmentIndex;
Entry<K, V> nextEntry, lastReturned;
Deque<Integer> segmentPositions = new ArrayDeque<Integer>(); //todo: replace with a more efficient, auto resizing int[]
EntryIterator() {
EntryIterator(AbstractVanillaSharedMap map) {
nextEntry = nextSegmentEntry();
this.map = map;
segmentIndex = map.segments.length;
}
public boolean hasNext() {
@@ -2157,7 +2720,7 @@ abstract class AbstractVanillaSharedMap<K, V> extends net.openhft.collections.Co
public void remove() {
if (lastReturned == null) throw new IllegalStateException();
AbstractVanillaSharedMap.this.remove(lastReturned.getKey());
map.remove(lastReturned.getKey());
lastReturned = null;
}
@@ -2175,17 +2738,17 @@ abstract class AbstractVanillaSharedMap<K, V> extends net.openhft.collections.Co
if (segmentPositions.isEmpty()) {
switchToNextSegment();
} else {
final Segment segment = segments[segmentIndex];
segment.lock();
map.segments[segmentIndex].lock();
try {
while (!segmentPositions.isEmpty()) {
Entry<K, V> entry = segment.getEntry(segmentPositions.removeFirst());
final Entry<K, V> entry = (Entry<K, V>) map.segments[segmentIndex].getEntry(segmentPositions.removeFirst());
if (entry != null) {
return entry;
}
}
} finally {
segment.unlock();
map.segments[segmentIndex].unlock();
}
}
}
@@ -2196,12 +2759,12 @@ abstract class AbstractVanillaSharedMap<K, V> extends net.openhft.collections.Co
segmentPositions.clear();
segmentIndex--;
if (segmentIndex >= 0) {
final Segment segment = segments[segmentIndex];
segment.lock();
map.segments[segmentIndex].lock();
try {
segments[segmentIndex].visit(this);
map.segments[segmentIndex].visit(this);
} finally {
segment.unlock();
map.segments[segmentIndex].unlock();
}
}
}
@@ -2214,7 +2777,7 @@ abstract class AbstractVanillaSharedMap<K, V> extends net.openhft.collections.Co
final class EntrySet extends AbstractSet<Map.Entry<K, V>> {
public Iterator<Map.Entry<K, V>> iterator() {
return new EntryIterator();
return new EntryIterator(AbstractVanillaSharedMap.this);
}
public boolean contains(Object o) {