/*
* Written by Doug Lea with assistance from members of JCP JSR-166
* Expert Group and released to the public domain, as explained at
* http://creativecommons.org/publicdomain/zero/1.0/
*/
package jsr166e;
import jsr166e.LongAdder;
import java.util.Map;
import java.util.Set;
import java.io.Serializable;
/**
* A keyed table of adders, that may be useful in computing frequency
* counts and histograms, or may be used as a form of multiset. A
* {@link LongAdder} is associated with each key. Keys are added to
* the table implicitly upon any attempt to update, or may be added
* explicitly using method {@link #install}.
*
*
jsr166e note: This class is targeted to be placed in
* java.util.concurrent.atomic.
*
* @since 1.8
* @author Doug Lea
*/
public class LongAdderTable implements Serializable {
/** Relies on default serialization */
private static final long serialVersionUID = 7249369246863182397L;
/** The underlying map */
private final ConcurrentHashMapV8 map;
static final class CreateAdder
implements ConcurrentHashMapV8.Fun {
public LongAdder apply(Object unused) { return new LongAdder(); }
}
private static final CreateAdder createAdder = new CreateAdder();
/**
* Creates a new empty table.
*/
public LongAdderTable() {
map = new ConcurrentHashMapV8();
}
/**
* If the given key does not already exist in the table, inserts
* the key with initial sum of zero; in either case returning the
* adder associated with this key.
*
* @param key the key
* @return the adder associated with the key
*/
public LongAdder install(K key) {
return map.computeIfAbsent(key, createAdder);
}
/**
* Adds the given value to the sum associated with the given
* key. If the key does not already exist in the table, it is
* inserted.
*
* @param key the key
* @param x the value to add
*/
public void add(K key, long x) {
map.computeIfAbsent(key, createAdder).add(x);
}
/**
* Increments the sum associated with the given key. If the key
* does not already exist in the table, it is inserted.
*
* @param key the key
*/
public void increment(K key) { add(key, 1L); }
/**
* Decrements the sum associated with the given key. If the key
* does not already exist in the table, it is inserted.
*
* @param key the key
*/
public void decrement(K key) { add(key, -1L); }
/**
* Returns the sum associated with the given key, or zero if the
* key does not currently exist in the table.
*
* @param key the key
* @return the sum associated with the key, or zero if the key is
* not in the table
*/
public long sum(K key) {
LongAdder a = map.get(key);
return a == null ? 0L : a.sum();
}
/**
* Resets the sum associated with the given key to zero if the key
* exists in the table. This method does NOT add or
* remove the key from the table (see {@link #remove}).
*
* @param key the key
*/
public void reset(K key) {
LongAdder a = map.get(key);
if (a != null)
a.reset();
}
/**
* Resets the sum associated with the given key to zero if the key
* exists in the table. This method does NOT add or
* remove the key from the table (see {@link #remove}).
*
* @param key the key
* @return the previous sum, or zero if the key is not
* in the table
*/
public long sumThenReset(K key) {
LongAdder a = map.get(key);
return a == null ? 0L : a.sumThenReset();
}
/**
* Returns the sum totalled across all keys.
*
* @return the sum totalled across all keys
*/
public long sumAll() {
long sum = 0L;
for (LongAdder a : map.values())
sum += a.sum();
return sum;
}
/**
* Resets the sum associated with each key to zero.
*/
public void resetAll() {
for (LongAdder a : map.values())
a.reset();
}
/**
* Totals, then resets, the sums associated with all keys.
*
* @return the sum totalled across all keys
*/
public long sumThenResetAll() {
long sum = 0L;
for (LongAdder a : map.values())
sum += a.sumThenReset();
return sum;
}
/**
* Removes the given key from the table.
*
* @param key the key
*/
public void remove(K key) { map.remove(key); }
/**
* Removes all keys from the table.
*/
public void removeAll() { map.clear(); }
/**
* Returns the current set of keys.
*
* @return the current set of keys
*/
public Set keySet() {
return map.keySet();
}
/**
* Returns the current set of key-value mappings.
*
* @return the current set of key-value mappings
*/
public Set> entrySet() {
return map.entrySet();
}
}