11d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert// Copyright 2011 Google Inc. All Rights Reserved. 21d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 31d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertpackage com.google.common.util.concurrent; 41d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 51d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport static com.google.common.base.Preconditions.checkNotNull; 61d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 71d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport com.google.common.annotations.Beta; 81d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport com.google.common.base.Function; 91d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport com.google.common.collect.Maps; 101d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 111d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport java.util.Collections; 121d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport java.util.Map; 131d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport java.util.concurrent.ConcurrentHashMap; 141d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport java.util.concurrent.atomic.AtomicLong; 151d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 161d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert/** 171d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * A map containing {@code long} values that can be atomically updated. While writes to a 181d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * traditional {@code Map} rely on {@code put(K, V)}, the typical mechanism for writing to this map 191d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * is {@code addAndGet(K, long)}, which adds a {@code long} to the value currently associated with 201d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * {@code K}. If a key has not yet been associated with a value, its implicit value is zero. 211d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * 221d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * <p>Most methods in this class treat absent values and zero values identically, as individually 231d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * documented. Exceptions to this are {@link #containsKey}, {@link #size}, {@link #isEmpty}, 241d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * {@link #asMap}, and {@link #toString}. 251d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * 261d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * <p>Instances of this class may be used by multiple threads concurrently. All operations are 271d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * atomic unless otherwise noted. 281d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * 291d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * <p><b>Note:</b> If your values are always positive and less than 2^31, you may wish to use a 301d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * {@link com.google.common.collect.Multiset} such as 311d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * {@link com.google.common.collect.ConcurrentHashMultiset} instead. 321d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * 331d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * <b>Warning:</b> Unlike {@code Multiset}, entries whose values are zero are not automatically 341d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * removed from the map. Instead they must be removed manually with {@link #removeAllZeros}. 351d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * 361d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * @author Charles Fry 371d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * @since 11.0 381d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert */ 391d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert@Beta 401d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertpublic final class AtomicLongMap<K> { 411d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert private final ConcurrentHashMap<K, AtomicLong> map; 421d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 431d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert private AtomicLongMap(ConcurrentHashMap<K, AtomicLong> map) { 441d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert this.map = checkNotNull(map); 451d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 461d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 471d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert /** 481d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * Creates an {@code AtomicLongMap}. 491d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert */ 501d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert public static <K> AtomicLongMap<K> create() { 511d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert return new AtomicLongMap<K>(new ConcurrentHashMap<K, AtomicLong>()); 521d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 531d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 541d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert /** 551d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * Creates an {@code AtomicLongMap} with the same mappings as the specified {@code Map}. 561d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert */ 571d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert public static <K> AtomicLongMap<K> create(Map<? extends K, ? extends Long> m) { 581d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert AtomicLongMap<K> result = create(); 591d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert result.putAll(m); 601d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert return result; 611d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 621d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 631d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert /** 641d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * Returns the value associated with {@code key}, or zero if there is no value associated with 651d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * {@code key}. 661d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert */ 671d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert public long get(K key) { 681d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert AtomicLong atomic = map.get(key); 691d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert return atomic == null ? 0L : atomic.get(); 701d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 711d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 721d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert /** 731d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * Increments by one the value currently associated with {@code key}, and returns the new value. 741d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert */ 751d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert public long incrementAndGet(K key) { 761d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert return addAndGet(key, 1); 771d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 781d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 791d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert /** 801d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * Decrements by one the value currently associated with {@code key}, and returns the new value. 811d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert */ 821d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert public long decrementAndGet(K key) { 831d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert return addAndGet(key, -1); 841d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 851d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 861d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert /** 871d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * Adds {@code delta} to the value currently associated with {@code key}, and returns the new 881d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * value. 891d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert */ 901d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert public long addAndGet(K key, long delta) { 911d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert outer: for (;;) { 921d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert AtomicLong atomic = map.get(key); 931d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert if (atomic == null) { 941d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert atomic = map.putIfAbsent(key, new AtomicLong(delta)); 951d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert if (atomic == null) { 961d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert return delta; 971d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 981d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert // atomic is now non-null; fall through 991d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 1001d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 1011d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert for (;;) { 1021d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert long oldValue = atomic.get(); 1031d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert if (oldValue == 0L) { 1041d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert // don't compareAndSet a zero 1051d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert if (map.replace(key, atomic, new AtomicLong(delta))) { 1061d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert return delta; 1071d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 1081d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert // atomic replaced 1091d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert continue outer; 1101d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 1111d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 1121d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert long newValue = oldValue + delta; 1131d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert if (atomic.compareAndSet(oldValue, newValue)) { 1141d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert return newValue; 1151d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 1161d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert // value changed 1171d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 1181d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 1191d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 1201d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 1211d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert /** 1221d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * Increments by one the value currently associated with {@code key}, and returns the old value. 1231d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert */ 1241d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert public long getAndIncrement(K key) { 1251d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert return getAndAdd(key, 1); 1261d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 1271d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 1281d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert /** 1291d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * Decrements by one the value currently associated with {@code key}, and returns the old value. 1301d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert */ 1311d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert public long getAndDecrement(K key) { 1321d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert return getAndAdd(key, -1); 1331d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 1341d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 1351d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert /** 1361d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * Adds {@code delta} to the value currently associated with {@code key}, and returns the old 1371d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * value. 1381d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert */ 1391d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert public long getAndAdd(K key, long delta) { 1401d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert outer: for (;;) { 1411d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert AtomicLong atomic = map.get(key); 1421d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert if (atomic == null) { 1431d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert atomic = map.putIfAbsent(key, new AtomicLong(delta)); 1441d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert if (atomic == null) { 1451d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert return 0L; 1461d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 1471d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert // atomic is now non-null; fall through 1481d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 1491d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 1501d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert for (;;) { 1511d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert long oldValue = atomic.get(); 1521d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert if (oldValue == 0L) { 1531d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert // don't compareAndSet a zero 1541d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert if (map.replace(key, atomic, new AtomicLong(delta))) { 1551d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert return 0L; 1561d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 1571d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert // atomic replaced 1581d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert continue outer; 1591d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 1601d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 1611d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert long newValue = oldValue + delta; 1621d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert if (atomic.compareAndSet(oldValue, newValue)) { 1631d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert return oldValue; 1641d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 1651d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert // value changed 1661d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 1671d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 1681d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 1691d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 1701d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert /** 1711d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * Associates {@code newValue} with {@code key} in this map, and returns the value previously 1721d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * associated with {@code key}, or zero if there was no such value. 1731d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert */ 1741d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert public long put(K key, long newValue) { 1751d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert outer: for (;;) { 1761d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert AtomicLong atomic = map.get(key); 1771d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert if (atomic == null) { 1781d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert atomic = map.putIfAbsent(key, new AtomicLong(newValue)); 1791d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert if (atomic == null) { 1801d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert return 0L; 1811d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 1821d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert // atomic is now non-null; fall through 1831d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 1841d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 1851d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert for (;;) { 1861d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert long oldValue = atomic.get(); 1871d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert if (oldValue == 0L) { 1881d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert // don't compareAndSet a zero 1891d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert if (map.replace(key, atomic, new AtomicLong(newValue))) { 1901d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert return 0L; 1911d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 1921d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert // atomic replaced 1931d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert continue outer; 1941d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 1951d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 1961d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert if (atomic.compareAndSet(oldValue, newValue)) { 1971d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert return oldValue; 1981d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 1991d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert // value changed 2001d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 2011d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 2021d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 2031d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 2041d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert /** 2051d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * Copies all of the mappings from the specified map to this map. The effect of this call is 2061d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * equivalent to that of calling {@code put(k, v)} on this map once for each mapping from key 2071d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * {@code k} to value {@code v} in the specified map. The behavior of this operation is undefined 2081d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * if the specified map is modified while the operation is in progress. 2091d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert */ 2101d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert public void putAll(Map<? extends K, ? extends Long> m) { 2111d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert for (Map.Entry<? extends K, ? extends Long> entry : m.entrySet()) { 2121d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert put(entry.getKey(), entry.getValue()); 2131d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 2141d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 2151d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 2161d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert /** 2171d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * Removes and returns the value associated with {@code key}. If {@code key} is not 2181d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * in the map, this method has no effect and returns zero. 2191d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert */ 2201d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert public long remove(K key) { 2211d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert AtomicLong atomic = map.get(key); 2221d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert if (atomic == null) { 2231d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert return 0L; 2241d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 2251d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 2261d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert for (;;) { 2271d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert long oldValue = atomic.get(); 2281d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert if (oldValue == 0L || atomic.compareAndSet(oldValue, 0L)) { 2291d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert // only remove after setting to zero, to avoid concurrent updates 2301d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert map.remove(key, atomic); 2311d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert // succeed even if the remove fails, since the value was already adjusted 2321d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert return oldValue; 2331d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 2341d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 2351d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 2361d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 2371d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert /** 2381d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * Removes all mappings from this map whose values are zero. 2391d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * 2401d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * <p>This method is not atomic: the map may be visible in intermediate states, where some 2411d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * of the zero values have been removed and others have not. 2421d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert */ 2431d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert public void removeAllZeros() { 2441d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert for (K key : map.keySet()) { 2451d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert AtomicLong atomic = map.get(key); 2461d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert if (atomic != null && atomic.get() == 0L) { 2471d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert map.remove(key, atomic); 2481d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 2491d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 2501d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 2511d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 2521d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert /** 2531d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * Returns the sum of all values in this map. 2541d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * 2551d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * <p>This method is not atomic: the sum may or may not include other concurrent operations. 2561d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert */ 2571d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert public long sum() { 2581d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert long sum = 0L; 2591d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert for (AtomicLong value : map.values()) { 2601d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert sum = sum + value.get(); 2611d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 2621d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert return sum; 2631d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 2641d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 2651d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert private transient Map<K, Long> asMap; 2661d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 2671d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert /** 2681d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * Returns a live, read-only view of the map backing this {@code AtomicLongMap}. 2691d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert */ 2701d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert public Map<K, Long> asMap() { 2711d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert Map<K, Long> result = asMap; 2721d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert return (result == null) ? asMap = createAsMap() : result; 2731d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 2741d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 2751d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert private Map<K, Long> createAsMap() { 2761d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert return Collections.unmodifiableMap( 2771d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert Maps.transformValues(map, new Function<AtomicLong, Long>() { 2781d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert @Override 2791d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert public Long apply(AtomicLong atomic) { 2801d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert return atomic.get(); 2811d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 2821d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert })); 2831d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 2841d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 2851d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert /** 2861d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * Returns true if this map contains a mapping for the specified key. 2871d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert */ 2881d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert public boolean containsKey(Object key) { 2891d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert return map.containsKey(key); 2901d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 2911d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 2921d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert /** 2931d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * Returns the number of key-value mappings in this map. If the map contains more than 2941d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * {@code Integer.MAX_VALUE} elements, returns {@code Integer.MAX_VALUE}. 2951d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert */ 2961d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert public int size() { 2971d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert return map.size(); 2981d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 2991d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 3001d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert /** 3011d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * Returns {@code true} if this map contains no key-value mappings. 3021d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert */ 3031d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert public boolean isEmpty() { 3041d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert return map.isEmpty(); 3051d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 3061d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 3071d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert /** 3081d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * Removes all of the mappings from this map. The map will be empty after this call returns. 3091d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * 3101d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * <p>This method is not atomic: the map may not be empty after returning if there were concurrent 3111d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * writes. 3121d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert */ 3131d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert public void clear() { 3141d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert map.clear(); 3151d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 3161d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 3171d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert @Override 3181d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert public String toString() { 3191d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert return map.toString(); 3201d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 3211d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 3221d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert /* 3231d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * ConcurrentMap operations which we may eventually add. 3241d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * 3251d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * The problem with these is that remove(K, long) has to be done in two phases by definition --- 3261d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * first decrementing to zero, and then removing. putIfAbsent or replace could observe the 3271d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * intermediate zero-state. Ways we could deal with this are: 3281d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * 3291d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * - Don't define any of the ConcurrentMap operations. This is the current state of affairs. 3301d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * 3311d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * - Define putIfAbsent and replace as treating zero and absent identically (as currently 3321d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * implemented below). This is a bit surprising with putIfAbsent, which really becomes 3331d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * putIfZero. 3341d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * 3351d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * - Allow putIfAbsent and replace to distinguish between zero and absent, but don't implement 3361d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * remove(K, long). Without any two-phase operations it becomes feasible for all remaining 3371d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * operations to distinguish between zero and absent. If we do this, then perhaps we should add 3381d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * replace(key, long). 3391d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * 3401d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * - Introduce a special-value private static final AtomicLong that would have the meaning of 3411d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * removal-in-progress, and rework all operations to properly distinguish between zero and 3421d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * absent. 3431d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert */ 3441d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 3451d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert /** 3461d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * If {@code key} is not already associated with a value or if {@code key} is associated with 3471d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * zero, associate it with {@code newValue}. Returns the previous value associated with 3481d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * {@code key}, or zero if there was no mapping for {@code key}. 3491d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert */ 3501d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert long putIfAbsent(K key, long newValue) { 3511d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert for (;;) { 3521d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert AtomicLong atomic = map.get(key); 3531d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert if (atomic == null) { 3541d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert atomic = map.putIfAbsent(key, new AtomicLong(newValue)); 3551d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert if (atomic == null) { 3561d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert return 0L; 3571d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 3581d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert // atomic is now non-null; fall through 3591d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 3601d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 3611d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert long oldValue = atomic.get(); 3621d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert if (oldValue == 0L) { 3631d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert // don't compareAndSet a zero 3641d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert if (map.replace(key, atomic, new AtomicLong(newValue))) { 3651d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert return 0L; 3661d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 3671d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert // atomic replaced 3681d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert continue; 3691d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 3701d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 3711d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert return oldValue; 3721d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 3731d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 3741d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 3751d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert /** 3761d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * If {@code (key, expectedOldValue)} is currently in the map, this method replaces 3771d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * {@code expectedOldValue} with {@code newValue} and returns true; otherwise, this method 3781d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * returns false. 3791d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * 3801d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * <p>If {@code expectedOldValue} is zero, this method will succeed if {@code (key, zero)} 3811d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * is currently in the map, or if {@code key} is not in the map at all. 3821d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert */ 3831d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert boolean replace(K key, long expectedOldValue, long newValue) { 3841d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert if (expectedOldValue == 0L) { 3851d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert return putIfAbsent(key, newValue) == 0L; 3861d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } else { 3871d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert AtomicLong atomic = map.get(key); 3881d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert return (atomic == null) ? false : atomic.compareAndSet(expectedOldValue, newValue); 3891d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 3901d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 3911d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 3921d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert /** 3931d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * If {@code (key, value)} is currently in the map, this method removes it and returns 3941d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * true; otherwise, this method returns false. 3951d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert */ 3961d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert boolean remove(K key, long value) { 3971d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert AtomicLong atomic = map.get(key); 3981d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert if (atomic == null) { 3991d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert return false; 4001d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 4011d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 4021d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert long oldValue = atomic.get(); 4031d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert if (oldValue != value) { 4041d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert return false; 4051d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 4061d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 4071d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert if (oldValue == 0L || atomic.compareAndSet(oldValue, 0L)) { 4081d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert // only remove after setting to zero, to avoid concurrent updates 4091d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert map.remove(key, atomic); 4101d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert // succeed even if the remove fails, since the value was already adjusted 4111d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert return true; 4121d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 4131d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 4141d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert // value changed 4151d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert return false; 4161d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 4171d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 4181d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert} 419