LruCache.java revision 9b5a93550f3853b229ae9cfb5f6cf33091478023
1e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson/*
2e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson * Copyright (C) 2011 The Android Open Source Project
3e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson *
4e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson * Licensed under the Apache License, Version 2.0 (the "License");
5e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson * you may not use this file except in compliance with the License.
6e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson * You may obtain a copy of the License at
7e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson *
8e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson *      http://www.apache.org/licenses/LICENSE-2.0
9e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson *
10e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson * Unless required by applicable law or agreed to in writing, software
11e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson * distributed under the License is distributed on an "AS IS" BASIS,
12e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson * See the License for the specific language governing permissions and
14e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson * limitations under the License.
15e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson */
16e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson
17e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilsonpackage android.util;
18e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson
19e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilsonimport java.util.LinkedHashMap;
20e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilsonimport java.util.Map;
21e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson
22e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson/**
23e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson * A cache that holds strong references to a limited number of values. Each time
24e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson * a value is accessed, it is moved to the head of a queue. When a value is
25e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson * added to a full cache, the value at the end of that queue is evicted and may
26e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson * become eligible for garbage collection.
27e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson *
28e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson * <p>If your cached values hold resources that need to be explicitly released,
29e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson * override {@link #entryEvicted}. This method is only invoked when values are
30e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson * evicted. Values replaced by calls to {@link #put} must be released manually.
31e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson *
32e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson * <p>If a cache miss should be computed on demand for the corresponding keys,
33e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson * override {@link #create}. This simplifies the calling code, allowing it to
34e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson * assume a value will always be returned, even when there's a cache miss.
35e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson *
36e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson * <p>By default, the cache size is measured in the number of entries. Override
3734895b09db3679c7d4e80d21198847d316e6b0c3Jesse Wilson * {@link #sizeOf} to size the cache in different units. For example, this cache
3834895b09db3679c7d4e80d21198847d316e6b0c3Jesse Wilson * is limited to 4MiB of bitmaps:
39e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson * <pre>   {@code
4034895b09db3679c7d4e80d21198847d316e6b0c3Jesse Wilson *   int cacheSize = 4 * 1024 * 1024; // 4MiB
4134895b09db3679c7d4e80d21198847d316e6b0c3Jesse Wilson *   LruCache<String, Bitmap> bitmapCache = new LruCache<String, Bitmap>(cacheSize) {
4234895b09db3679c7d4e80d21198847d316e6b0c3Jesse Wilson *       protected int sizeOf(String key, Bitmap value) {
4334895b09db3679c7d4e80d21198847d316e6b0c3Jesse Wilson *           return value.getByteCount();
4434895b09db3679c7d4e80d21198847d316e6b0c3Jesse Wilson *       }
4534895b09db3679c7d4e80d21198847d316e6b0c3Jesse Wilson *   }}</pre>
4634895b09db3679c7d4e80d21198847d316e6b0c3Jesse Wilson *
4734895b09db3679c7d4e80d21198847d316e6b0c3Jesse Wilson * <p>This class is thread-safe. Perform multiple cache operations atomically by
4834895b09db3679c7d4e80d21198847d316e6b0c3Jesse Wilson * synchronizing on the cache: <pre>   {@code
4934895b09db3679c7d4e80d21198847d316e6b0c3Jesse Wilson *   synchronized (cache) {
5034895b09db3679c7d4e80d21198847d316e6b0c3Jesse Wilson *     if (cache.get(key) == null) {
5134895b09db3679c7d4e80d21198847d316e6b0c3Jesse Wilson *         cache.put(key, value);
52e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson *     }
5334895b09db3679c7d4e80d21198847d316e6b0c3Jesse Wilson *   }}</pre>
54e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson */
55e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilsonpublic class LruCache<K, V> {
56e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson    private final LinkedHashMap<K, V> map;
57e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson
58e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson    /** Size of this cache in units. Not necessarily the number of elements. */
59e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson    private int size;
609b5a93550f3853b229ae9cfb5f6cf33091478023Jesse Wilson    private int maxSize;
61e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson
62e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson    private int putCount;
63e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson    private int createCount;
64e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson    private int evictionCount;
65e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson    private int hitCount;
66e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson    private int missCount;
67e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson
68e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson    /**
69e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson     * @param maxSize for caches that do not override {@link #sizeOf}, this is
70e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson     *     the maximum number of entries in the cache. For all other caches,
71e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson     *     this is the maximum sum of the sizes of the entries in this cache.
72e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson     */
73e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson    public LruCache(int maxSize) {
74e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson        if (maxSize <= 0) {
75e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson            throw new IllegalArgumentException("maxSize <= 0");
76e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson        }
77e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson        this.maxSize = maxSize;
78e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson        this.map = new LinkedHashMap<K, V>(0, 0.75f, true);
79e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson    }
80e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson
81e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson    /**
82e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson     * Returns the value for {@code key} if it exists in the cache or can be
83e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson     * created by {@code #create}. If a value was returned, it is moved to the
84e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson     * head of the queue. This returns null if a value is not cached and cannot
85e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson     * be created.
86e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson     */
87e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson    public synchronized final V get(K key) {
88e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson        if (key == null) {
89e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson            throw new NullPointerException();
90e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson        }
91e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson
92e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson        V result = map.get(key);
93e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson        if (result != null) {
94e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson            hitCount++;
95e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson            return result;
96e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson        }
97e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson
98e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson        missCount++;
99e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson
100e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson        // TODO: release the lock while calling this potentially slow user code
101e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson        result = create(key);
102e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson
103e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson        if (result != null) {
104e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson            createCount++;
105e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson            size += safeSizeOf(key, result);
106e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson            map.put(key, result);
107e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson            trimToSize(maxSize);
108e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson        }
109e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson        return result;
110e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson    }
111e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson
112e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson    /**
113e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson     * Caches {@code value} for {@code key}. The value is moved to the head of
114e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson     * the queue.
115e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson     *
116e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson     * @return the previous value mapped by {@code key}. Although that entry is
117e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson     *     no longer cached, it has not been passed to {@link #entryEvicted}.
118e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson     */
119e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson    public synchronized final V put(K key, V value) {
120e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson        if (key == null || value == null) {
121e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson            throw new NullPointerException();
122e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson        }
123e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson
124e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson        putCount++;
125e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson        size += safeSizeOf(key, value);
126e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson        V previous = map.put(key, value);
127e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson        if (previous != null) {
128e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson            size -= safeSizeOf(key, previous);
129e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson        }
130e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson        trimToSize(maxSize);
131e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson        return previous;
132e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson    }
133e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson
134e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson    private void trimToSize(int maxSize) {
135e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson        while (size > maxSize) {
136e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson            Map.Entry<K, V> toEvict = map.eldest();
137e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson            if (toEvict == null) {
138e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson                break; // map is empty; if size is not 0 then throw an error below
139e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson            }
140e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson
141e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson            K key = toEvict.getKey();
142e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson            V value = toEvict.getValue();
143e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson            map.remove(key);
144e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson            size -= safeSizeOf(key, value);
145e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson            evictionCount++;
146e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson
147e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson            // TODO: release the lock while calling this potentially slow user code
148e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson            entryEvicted(key, value);
149e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson        }
150e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson
151e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson        if (size < 0 || (map.isEmpty() && size != 0)) {
152e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson            throw new IllegalStateException(getClass().getName()
153e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson                    + ".sizeOf() is reporting inconsistent results!");
154e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson        }
155e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson    }
156e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson
157e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson    /**
1589b5a93550f3853b229ae9cfb5f6cf33091478023Jesse Wilson     * Sets the maximum size of this cache. Decreasing the maximum size may
1599b5a93550f3853b229ae9cfb5f6cf33091478023Jesse Wilson     * evict entries from this cache.
1609b5a93550f3853b229ae9cfb5f6cf33091478023Jesse Wilson     *
1619b5a93550f3853b229ae9cfb5f6cf33091478023Jesse Wilson     * @param maxSize for caches that do not override {@link #sizeOf}, this is
1629b5a93550f3853b229ae9cfb5f6cf33091478023Jesse Wilson     *     the maximum number of entries in the cache. For all other caches,
1639b5a93550f3853b229ae9cfb5f6cf33091478023Jesse Wilson     *     this is the maximum sum of the sizes of the entries in this cache.
1649b5a93550f3853b229ae9cfb5f6cf33091478023Jesse Wilson     */
1659b5a93550f3853b229ae9cfb5f6cf33091478023Jesse Wilson    public synchronized final void setMaxSize(int maxSize) {
1669b5a93550f3853b229ae9cfb5f6cf33091478023Jesse Wilson        if (maxSize <= 0) {
1679b5a93550f3853b229ae9cfb5f6cf33091478023Jesse Wilson            throw new IllegalArgumentException("maxSize <= 0");
1689b5a93550f3853b229ae9cfb5f6cf33091478023Jesse Wilson        }
1699b5a93550f3853b229ae9cfb5f6cf33091478023Jesse Wilson
1709b5a93550f3853b229ae9cfb5f6cf33091478023Jesse Wilson        trimToSize(maxSize);
1719b5a93550f3853b229ae9cfb5f6cf33091478023Jesse Wilson        this.maxSize = maxSize;
1729b5a93550f3853b229ae9cfb5f6cf33091478023Jesse Wilson    }
1739b5a93550f3853b229ae9cfb5f6cf33091478023Jesse Wilson
1749b5a93550f3853b229ae9cfb5f6cf33091478023Jesse Wilson    /**
175e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson     * Called for entries that have reached the tail of the least recently used
176e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson     * queue and are be removed. The default implementation does nothing.
177e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson     */
178e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson    protected void entryEvicted(K key, V value) {}
179e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson
180e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson    /**
181e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson     * Called after a cache miss to compute a value for the corresponding key.
182e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson     * Returns the computed value or null if no value can be computed. The
183e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson     * default implementation returns null.
184e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson     */
185e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson    protected V create(K key) {
186e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson        return null;
187e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson    }
188e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson
189e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson    private int safeSizeOf(K key, V value) {
190e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson        int result = sizeOf(key, value);
191e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson        if (result < 0) {
192e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson            throw new IllegalStateException("Negative size: " + key + "=" + value);
193e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson        }
194e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson        return result;
195e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson    }
196e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson
197e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson    /**
198e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson     * Returns the size of the entry for {@code key} and {@code value} in
199e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson     * user-defined units.  The default implementation returns 1 so that size
200e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson     * is the number of entries and max size is the maximum number of entries.
201e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson     *
202e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson     * <p>An entry's size must not change while it is in the cache.
203e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson     */
204e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson    protected int sizeOf(K key, V value) {
205e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson        return 1;
206e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson    }
207e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson
208e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson    /**
209e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson     * Clear the cache, calling {@link #entryEvicted} on each removed entry.
210e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson     */
211e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson    public synchronized final void evictAll() {
212e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson        trimToSize(-1); // -1 will evict 0-sized elements
213e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson    }
214e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson
215e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson    /**
2169b5a93550f3853b229ae9cfb5f6cf33091478023Jesse Wilson     * For caches that do not override {@link #sizeOf}, this returns the number
2179b5a93550f3853b229ae9cfb5f6cf33091478023Jesse Wilson     * of entries in the cache. For all other caches, this returns the sum of
2189b5a93550f3853b229ae9cfb5f6cf33091478023Jesse Wilson     * the sizes of the entries in this cache.
219e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson     */
220e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson    public synchronized final int size() {
221e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson        return size;
222e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson    }
223e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson
224e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson    /**
2259b5a93550f3853b229ae9cfb5f6cf33091478023Jesse Wilson     * For caches that do not override {@link #sizeOf}, this returns the maximum
2269b5a93550f3853b229ae9cfb5f6cf33091478023Jesse Wilson     * number of entries in the cache. For all other caches, this returns the
2279b5a93550f3853b229ae9cfb5f6cf33091478023Jesse Wilson     * maximum sum of the sizes of the entries in this cache.
2289b5a93550f3853b229ae9cfb5f6cf33091478023Jesse Wilson     */
2299b5a93550f3853b229ae9cfb5f6cf33091478023Jesse Wilson    public synchronized final int maxSize() {
2309b5a93550f3853b229ae9cfb5f6cf33091478023Jesse Wilson        return maxSize;
2319b5a93550f3853b229ae9cfb5f6cf33091478023Jesse Wilson    }
2329b5a93550f3853b229ae9cfb5f6cf33091478023Jesse Wilson
2339b5a93550f3853b229ae9cfb5f6cf33091478023Jesse Wilson    /**
234e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson     * Returns the number of times {@link #get} returned a value.
235e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson     */
236e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson    public synchronized final int hitCount() {
237e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson        return hitCount;
238e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson    }
239e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson
240e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson    /**
241e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson     * Returns the number of times {@link #get} returned null or required a new
242e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson     * value to be created.
243e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson     */
244e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson    public synchronized final int missCount() {
245e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson        return missCount;
246e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson    }
247e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson
248e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson    /**
249e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson     * Returns the number of times {@link #create(Object)} returned a value.
250e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson     */
251e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson    public synchronized final int createCount() {
252e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson        return createCount;
253e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson    }
254e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson
255e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson    /**
256e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson     * Returns the number of times {@link #put} was called.
257e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson     */
258e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson    public synchronized final int putCount() {
259e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson        return putCount;
260e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson    }
261e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson
262e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson    /**
263e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson     * Returns the number of values that have been evicted.
264e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson     */
265e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson    public synchronized final int evictionCount() {
266e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson        return evictionCount;
267e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson    }
268e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson
269e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson    /**
270e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson     * Returns a copy of the current contents of the cache, ordered from least
271e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson     * recently accessed to most recently accessed.
272e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson     */
273e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson    public synchronized final Map<K, V> snapshot() {
274e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson        return new LinkedHashMap<K, V>(map);
275e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson    }
276e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson
277e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson    @Override public synchronized final String toString() {
278e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson        int accesses = hitCount + missCount;
279e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson        int hitPercent = accesses != 0 ? (100 * hitCount / accesses) : 0;
280e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson        return String.format("LruCache[maxSize=%d,hits=%d,misses=%d,hitRate=%d%%]",
281e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson                maxSize, hitCount, missCount, hitPercent);
282e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson    }
283e2c1f4a0ee026e7a2a15d198dc3be4529896e9f6Jesse Wilson}
284