aboutsummaryrefslogtreecommitdiffstats
path: root/guava-gwt/src-super/com/google/common/cache/super/com/google/common/cache/LocalCache.java
diff options
context:
space:
mode:
Diffstat (limited to 'guava-gwt/src-super/com/google/common/cache/super/com/google/common/cache/LocalCache.java')
-rw-r--r--guava-gwt/src-super/com/google/common/cache/super/com/google/common/cache/LocalCache.java829
1 files changed, 0 insertions, 829 deletions
diff --git a/guava-gwt/src-super/com/google/common/cache/super/com/google/common/cache/LocalCache.java b/guava-gwt/src-super/com/google/common/cache/super/com/google/common/cache/LocalCache.java
deleted file mode 100644
index 44528bf..0000000
--- a/guava-gwt/src-super/com/google/common/cache/super/com/google/common/cache/LocalCache.java
+++ /dev/null
@@ -1,829 +0,0 @@
-/*
- * Copyright (C) 2012 The Guava Authors
- *
- * 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
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * 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 com.google.common.cache;
-
-import static com.google.common.base.Objects.firstNonNull;
-import static com.google.common.base.Preconditions.checkNotNull;
-import static com.google.common.base.Preconditions.checkState;
-
-import com.google.common.base.Equivalence;
-import com.google.common.base.Ticker;
-import com.google.common.cache.AbstractCache.StatsCounter;
-import com.google.common.collect.ImmutableMap;
-import com.google.common.util.concurrent.ExecutionError;
-import com.google.common.util.concurrent.UncheckedExecutionException;
-
-import java.util.AbstractSet;
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.LinkedHashMap;
-import java.util.Map;
-import java.util.Map.Entry;
-import java.util.NoSuchElementException;
-import java.util.Set;
-import java.util.concurrent.Callable;
-import java.util.concurrent.ConcurrentMap;
-import java.util.concurrent.ExecutionException;
-
-import javax.annotation.Nullable;
-
-/**
- * LocalCache emulation for GWT.
- *
- * @param <K> the base key type
- * @param <V> the base value type
- * @author Charles Fry
- * @author Jon Donovan
- */
-public class LocalCache<K, V> implements ConcurrentMap<K, V> {
- private static final int UNSET_INT = CacheBuilder.UNSET_INT;
-
- private final LinkedHashMap<K, Timestamped<V>> cachingHashMap;
- private final CacheLoader<? super K, V> loader;
- private final RemovalListener removalListener;
- private final StatsCounter statsCounter;
- private final Ticker ticker;
- private final long expireAfterWrite;
- private final long expireAfterAccess;
-
- LocalCache(CacheBuilder<? super K, ? super V> builder, CacheLoader<? super K, V> loader) {
- this.loader = loader;
- this.removalListener = builder.removalListener;
- this.expireAfterAccess = builder.expireAfterAccessNanos;
- this.expireAfterWrite = builder.expireAfterWriteNanos;
- this.statsCounter = builder.getStatsCounterSupplier().get();
-
- /* Implements size-capped LinkedHashMap */
- final long maximumSize = builder.maximumSize;
- this.cachingHashMap = new CapacityEnforcingLinkedHashMap<K, V>(
- builder.getInitialCapacity(),
- 0.75f,
- (builder.maximumSize != UNSET_INT),
- builder.maximumSize,
- statsCounter,
- removalListener);
-
- this.ticker = firstNonNull(builder.ticker, Ticker.systemTicker());
- }
-
- @Override
- public int size() {
- return cachingHashMap.size();
- }
-
- @Override
- public boolean isEmpty() {
- return cachingHashMap.isEmpty();
- }
-
- @Override
- public V get(Object key) {
- key = checkNotNull(key);
- Timestamped<V> value = cachingHashMap.get(key);
-
- if (value == null) {
- statsCounter.recordMisses(1);
- return null;
- } else if (!isExpired(value)) {
- statsCounter.recordHits(1);
- value.updateTimestamp();
- return value.getValue();
- } else {
- statsCounter.recordEviction();
- statsCounter.recordMisses(1);
- alertListenerIfPresent(key, value.getValue(), RemovalCause.EXPIRED);
- cachingHashMap.remove(key);
- return null;
- }
- }
-
- @Override
- public V put(K key, V value) {
- key = checkNotNull(key);
- value = checkNotNull(value);
- Timestamped<V> oldValue = cachingHashMap.put(key, new Timestamped<V>(value, ticker));
- if (oldValue == null) {
- return null;
- }
- alertListenerIfPresent(key, oldValue.getValue(), RemovalCause.REPLACED);
- return oldValue.getValue();
- }
-
- @Override
- public V remove(Object key) {
- Timestamped<V> stamped = cachingHashMap.remove(key);
- if (stamped != null) {
- V value = stamped.getValue();
-
- if (!isExpired(stamped)) {
- alertListenerIfPresent(key, value, RemovalCause.EXPLICIT);
- return value;
- }
-
- alertListenerIfPresent(key, value, RemovalCause.EXPIRED);
- }
- return null;
- }
-
- @Override
- public void putAll(Map<? extends K, ? extends V> m) {
- for (Map.Entry<? extends K, ? extends V> entry : m.entrySet()) {
- put(entry.getKey(), entry.getValue());
- }
- }
-
- @Override
- public void clear() {
- if (removalListener != null) {
- for (Map.Entry<K, Timestamped<V>> entry : cachingHashMap.entrySet()) {
- alertListenerIfPresent(entry.getKey(), entry.getValue().getValue(), RemovalCause.EXPLICIT);
- }
- }
- cachingHashMap.clear();
- }
-
- @Override
- public V putIfAbsent(K key, V value) {
- V currentValue = get(key);
- if (currentValue != null) {
- return currentValue;
- }
- return put(key, value);
- }
-
- @Override
- public boolean remove(Object key, Object value) {
- if (value.equals(get(key))) {
- alertListenerIfPresent(key, value, RemovalCause.EXPLICIT);
- remove(key);
- return true;
- }
- return false;
- }
-
- @Override
- public boolean replace(K key, V oldValue, V newValue) {
- if (oldValue.equals(get(key))) {
- alertListenerIfPresent(key, oldValue, RemovalCause.REPLACED);
- put(key, newValue);
- return true;
- }
- return false;
- }
-
- @Override
- public V replace(K key, V value) {
- V currentValue = get(key);
- if (currentValue != null) {
- alertListenerIfPresent(key, currentValue, RemovalCause.REPLACED);
- return put(key, value);
- }
- return null;
- }
-
- @Override
- public boolean containsKey(Object key) {
- return cachingHashMap.containsKey(key) && !isExpired(cachingHashMap.get(key));
- }
-
- @Override
- public boolean containsValue(Object value) {
- for (Timestamped<V> val : cachingHashMap.values()) {
- if (val.getValue().equals(value)) {
- if (!isExpired(val)) {
- return true;
- }
- }
- }
- return false;
- }
-
- private boolean isExpired(Timestamped<V> stamped) {
- if ((expireAfterAccess == UNSET_INT) && (expireAfterWrite == UNSET_INT)) {
- return false;
- }
-
- boolean expireWrite = (stamped.getWriteTimestamp() + expireAfterWrite <= currentTimeNanos());
- boolean expireAccess = (stamped.getAccessTimestamp() + expireAfterAccess <= currentTimeNanos());
-
- if (expireAfterAccess == UNSET_INT) {
- return expireWrite;
- }
- if (expireAfterWrite == UNSET_INT) {
- return expireAccess;
- }
-
- return expireWrite || expireAccess;
- }
-
- private long currentTimeNanos() {
- return ticker.read();
- }
-
- private void alertListenerIfPresent(Object key, Object value, RemovalCause cause) {
- if (removalListener != null) {
- removalListener.onRemoval(new RemovalNotification(key, value, cause));
- }
- }
-
- private V load(Object key) throws ExecutionException {
- long startTime = ticker.read();
- V calculatedValue;
- try {
- /*
- * This cast isn't safe, but we can rely on the fact that K is almost always passed to
- * Map.get(), and tools like IDEs and Findbugs can catch situations where this isn't the
- * case.
- *
- * The alternative is to add an overloaded method, but the chances of a user calling get()
- * instead of the new API and the risks inherent in adding a new API outweigh this little
- * hole.
- */
- K castKey = (K) key;
- calculatedValue = loader.load(castKey);
- put(castKey, calculatedValue);
- } catch (RuntimeException e) {
- statsCounter.recordLoadException(ticker.read() - startTime);
- throw new UncheckedExecutionException(e);
- } catch (Exception e) {
- statsCounter.recordLoadException(ticker.read() - startTime);
- throw new ExecutionException(e);
- } catch (Error e) {
- statsCounter.recordLoadException(ticker.read() - startTime);
- throw new ExecutionError(e);
- }
-
- if (calculatedValue == null) {
- String message = loader + " returned null for key " + key + ".";
- throw new CacheLoader.InvalidCacheLoadException(message);
- }
- statsCounter.recordLoadSuccess(ticker.read() - startTime);
- return calculatedValue;
- }
-
- private V getIfPresent(Object key) {
- key = checkNotNull(key);
- Timestamped<V> value = cachingHashMap.get(key);
-
- if (value == null) {
- return null;
- } else if (!isExpired(value)) {
- value.updateTimestamp();
- return value.getValue();
- } else {
- alertListenerIfPresent(key, value.getValue(), RemovalCause.EXPIRED);
- cachingHashMap.remove(key);
- return null;
- }
- }
-
- private V getOrLoad(K key) throws ExecutionException{
- V value = get(key);
- if (value != null) {
- return value;
- }
- return load(key);
- }
-
- private static class Timestamped<V> {
- private final V value;
- private final Ticker ticker;
- private long writeTimestamp;
- private long accessTimestamp;
-
- public Timestamped(V value, Ticker ticker) {
- this.value = checkNotNull(value);
- this.ticker = checkNotNull(ticker);
- this.writeTimestamp = ticker.read();
- this.accessTimestamp = this.writeTimestamp;
- }
-
- public V getValue() {
- return value;
- }
-
- public void updateTimestamp() {
- accessTimestamp = ticker.read();
- }
-
- public long getAccessTimestamp() {
- return accessTimestamp;
- }
-
- public long getWriteTimestamp() {
- return writeTimestamp;
- }
-
- public boolean equals(Object o) {
- return value.equals(o);
- }
-
- public int hashCode() {
- return value.hashCode();
- }
- }
-
- /**
- * LocalManualCache is a wrapper around LocalCache for a cache without loading.
- *
- * @param <K> the base key type
- * @param <V> the base value type
- */
- public static class LocalManualCache<K, V> extends AbstractCache<K, V> {
- final LocalCache<K, V> localCache;
-
- LocalManualCache(CacheBuilder<? super K, ? super V> builder) {
- this(builder, null);
- }
-
- protected LocalManualCache(CacheBuilder<? super K, ? super V> builder,
- CacheLoader<? super K, V> loader) {
- this.localCache = new LocalCache<K, V>(builder, loader);
- }
-
- // Cache methods
-
- @Override
- public V get(K key, Callable<? extends V> valueLoader) throws ExecutionException {
- V value = localCache.get(key);
- if (value != null) {
- return value;
- }
-
- try {
- V newValue = valueLoader.call();
- localCache.put(key, newValue);
- return newValue;
- } catch (Exception e) {
- throw new ExecutionException(e);
- }
- }
-
- @Override
- @Nullable
- public V getIfPresent(Object key) {
- return localCache.getIfPresent(key);
- }
-
- @Override
- public void put(K key, V value) {
- localCache.put(key, value);
- }
-
- @Override
- public void invalidate(Object key) {
- key = checkNotNull(key);
- localCache.remove(key);
- }
-
- @Override
- public void invalidateAll() {
- localCache.clear();
- }
-
- @Override
- public long size() {
- return localCache.size();
- }
-
- @Override
- public ConcurrentMap<K, V> asMap() {
- return localCache;
- }
- }
-
- /**
- * LocalLoadingCache is a wrapper around LocalCache for a cache with loading.
- *
- * @param <K> the base key type
- * @param <V> the base value type
- */
- public static class LocalLoadingCache<K, V>
- extends LocalManualCache<K, V> implements LoadingCache<K, V> {
-
- LocalLoadingCache(CacheBuilder<? super K, ? super V> builder,
- CacheLoader<? super K, V> loader) {
- super(builder, checkNotNull(loader));
- }
-
- // Cache methods
-
- @Override
- public V get(K key) throws ExecutionException {
- return localCache.getOrLoad(key);
- }
-
- @Override
- public V getUnchecked(K key) {
- try {
- return get(key);
- } catch (ExecutionException e) {
- throw new UncheckedExecutionException(e.getCause());
- }
- }
-
- @Override
- public final V apply(K key) {
- return getUnchecked(key);
- }
-
- @Override
- public ImmutableMap<K, V> getAll(Iterable<? extends K> keys) throws ExecutionException {
- Map<K, V> map = new HashMap<K, V>();
- for (K key : keys) {
- map.put(key, localCache.getOrLoad(key));
- }
- return ImmutableMap.copyOf(map);
- }
-
- @Override
- public void refresh(K key) {
- throw new UnsupportedOperationException();
- }
- }
-
- /**
- * LinkedHashMap that enforces it's maximum size and logs events in a StatsCounter object
- * and an optional RemovalListener.
- *
- * @param <K> the base key type
- * @param <V> the base value type
- */
- private class CapacityEnforcingLinkedHashMap<K, V> extends LinkedHashMap<K, Timestamped<V>> {
-
- private final StatsCounter statsCounter;
- private final RemovalListener removalListener;
- private final long maximumSize;
-
- public CapacityEnforcingLinkedHashMap(
- int initialCapacity,
- float loadFactor,
- boolean accessOrder,
- long maximumSize,
- StatsCounter statsCounter,
- @Nullable RemovalListener removalListener) {
- super(initialCapacity, loadFactor, accessOrder);
- this.maximumSize = maximumSize;
- this.statsCounter = statsCounter;
- this.removalListener = removalListener;
- }
-
- @Override
- protected boolean removeEldestEntry(Map.Entry<K, Timestamped<V>> ignored) {
- boolean removal = (maximumSize == UNSET_INT) ? false : (size() > maximumSize);
- if ((removalListener != null) && removal) {
- removalListener.onRemoval(new RemovalNotification(
- ignored.getKey(),
- ignored.getValue().getValue(),
- RemovalCause.SIZE));
- }
- statsCounter.recordEviction();
- return removal;
- }
- }
-
- /**
- * Any updates to LocalCache.Strength used in CacheBuilder need to be matched in this class for
- * compilation purposes.
- */
- enum Strength {
- /*
- * TODO(kevinb): If we strongly reference the value and aren't loading, we needn't wrap the
- * value. This could save ~8 bytes per entry.
- */
-
- STRONG {
- @Override
- Equivalence<Object> defaultEquivalence() {
- return Equivalence.equals();
- }
- },
-
- SOFT {
- @Override
- Equivalence<Object> defaultEquivalence() {
- return Equivalence.identity();
- }
- },
-
- WEAK {
- @Override
- Equivalence<Object> defaultEquivalence() {
- return Equivalence.identity();
- }
- };
-
- abstract Equivalence<Object> defaultEquivalence();
- }
-
- /**
- * <p>Implementation for the EntryIterator, which is used to build Key and Value iterators.
- *
- * <p>Expiration is only checked on hasNext(), so as to ensure that a next() call never returns
- * null when hasNext() has already been called.
- */
- class EntryIterator implements Iterator<Entry<K, V>> {
- Iterator<Entry<K, Timestamped<V>>> iterator;
- Entry<K, Timestamped<V>> lastEntry;
- Entry<K, Timestamped<V>> nextEntry;
-
- EntryIterator() {
- this.iterator = LocalCache.this.cachingHashMap.entrySet().iterator();
- }
-
- @Override
- public Entry<K, V> next(){
- if (nextEntry == null) {
- hasNext();
-
- if (nextEntry == null) {
- throw new NoSuchElementException();
- }
- }
-
- lastEntry = nextEntry;
- nextEntry = null;
- return new WriteThroughEntry(lastEntry.getKey(), lastEntry.getValue().getValue());
- }
-
- @Override
- public boolean hasNext() {
- if (nextEntry == null) {
- while (iterator.hasNext()) {
- Entry<K, Timestamped<V>> next = iterator.next();
- if (!isExpired(next.getValue())) {
- nextEntry = next;
- return true;
- }
- }
- return false;
- }
- return true;
- }
-
- @Override
- public void remove() {
- checkState(lastEntry != null);
- LocalCache.this.remove(lastEntry.getKey(), lastEntry.getValue());
- lastEntry = null;
- }
- }
-
- /**
- * KeyIterator build on top of EntryIterator.
- */
- final class KeyIterator implements Iterator<K> {
- private EntryIterator iterator;
-
- KeyIterator() {
- iterator = new EntryIterator();
- }
-
- @Override
- public boolean hasNext() {
- return iterator.hasNext();
- }
-
- @Override
- public K next() {
- return iterator.next().getKey();
- }
-
- @Override
- public void remove() {
- iterator.remove();
- }
- }
-
- /**
- * ValueIterator build on top of EntryIterator.
- */
- final class ValueIterator implements Iterator<V> {
- private EntryIterator iterator;
-
- ValueIterator() {
- iterator = new EntryIterator();
- }
-
- @Override
- public boolean hasNext() {
- return iterator.hasNext();
- }
-
- @Override
- public V next() {
- return iterator.next().getValue();
- }
-
- @Override
- public void remove() {
- iterator.remove();
- }
- }
-
- Set<K> keySet;
-
- @Override
- public Set<K> keySet() {
- // does not impact recency ordering
- Set<K> ks = keySet;
- return (ks != null) ? ks : (keySet = new KeySet(this));
- }
-
- Collection<V> values;
-
- @Override
- public Collection<V> values() {
- // does not impact recency ordering
- Collection<V> vs = values;
- return (vs != null) ? vs : (values = new Values(this));
- }
-
- Set<Entry<K, V>> entrySet;
-
- @Override
- public Set<Entry<K, V>> entrySet() {
- // does not impact recency ordering
- Set<Entry<K, V>> es = entrySet;
- return (es != null) ? es : (entrySet = new EntrySet(this));
- }
-
- /**
- * Custom Entry class used by EntryIterator.next(), that relays setValue changes to the
- * underlying map.
- */
- private final class WriteThroughEntry implements Entry<K, V> {
- final K key;
- V value;
-
- WriteThroughEntry(K key, V value) {
- this.key = checkNotNull(key);
- this.value = checkNotNull(value);
- }
-
- @Override
- public K getKey() {
- return key;
- }
-
- @Override
- public V getValue() {
- return value;
- }
-
- @Override
- public boolean equals(@Nullable Object object) {
- // Cannot use key and value equivalence
- if (object instanceof Entry) {
- Entry<?, ?> that = (Entry<?, ?>) object;
- return key.equals(that.getKey()) && value.equals(that.getValue());
- }
- return false;
- }
-
- @Override
- public int hashCode() {
- // Cannot use key and value equivalence
- return key.hashCode() ^ value.hashCode();
- }
-
- @Override
- public V setValue(V newValue) {
- throw new UnsupportedOperationException();
- }
-
- /**
- * Returns a string representation of the form <code>{key}={value}</code>.
- */
- @Override
- public String toString() {
- return getKey() + "=" + getValue();
- }
- }
-
- // TODO(fry): Separate logic for consistency between emul and nonemul implementation.
- // TODO(fry): Look into Maps.KeySet and Maps.Values, which can ideally be reused here but are
- // currently only package visible.
- abstract class AbstractCacheSet<T> extends AbstractSet<T> {
- final ConcurrentMap<?, ?> map;
-
- AbstractCacheSet(ConcurrentMap<?, ?> map) {
- this.map = map;
- }
-
- @Override
- public int size() {
- return map.size();
- }
-
- @Override
- public boolean isEmpty() {
- return map.isEmpty();
- }
-
- @Override
- public void clear() {
- map.clear();
- }
- }
-
- /**
- * Abstraction layer for the KeySet, which redirects to cache methods.
- */
- private final class KeySet extends AbstractCacheSet<K> {
-
- KeySet(ConcurrentMap<?, ?> map) {
- super(map);
- }
-
- @Override
- public Iterator<K> iterator() {
- return new KeyIterator();
- }
-
- @Override
- public boolean contains(Object o) {
- return map.containsKey(o);
- }
-
- @Override
- public boolean remove(Object o) {
- return map.remove(o) != null;
- }
- }
-
- /**
- * Abstraction layer for the Values set, which redirects to cache methods.
- */
- private final class Values extends AbstractCacheSet<V> {
-
- Values(ConcurrentMap<?, ?> map) {
- super(map);
- }
-
- @Override
- public Iterator<V> iterator() {
- return new ValueIterator();
- }
-
- @Override
- public boolean contains(Object o) {
- return map.containsValue(o);
- }
- }
-
- /**
- * Abstraction layer for the EntrySet, which redirects to cache methods.
- */
- private final class EntrySet extends AbstractCacheSet<Entry<K, V>> {
-
- EntrySet(ConcurrentMap<?, ?> map) {
- super(map);
- }
-
- @Override
- public Iterator<Entry<K, V>> iterator() {
- return new EntryIterator();
- }
-
- @Override
- public boolean contains(Object o) {
- if (!(o instanceof Entry)) {
- return false;
- }
- Entry<?, ?> e = (Entry<?, ?>) o;
- Object key = e.getKey();
- if (key == null) {
- return false;
- }
- V v = LocalCache.this.get(key);
-
- return (v != null) && e.getValue().equals(v);
- }
-
- @Override
- public boolean remove(Object o) {
- if (!(o instanceof Entry)) {
- return false;
- }
- Entry<?, ?> e = (Entry<?, ?>) o;
- Object key = e.getKey();
- return (key != null) && LocalCache.this.remove(key, e.getValue());
- }
- }
-}