1795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson/*
2795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson * Copyright (C) 2011 The Android Open Source Project
3795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson *
4795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson * Licensed under the Apache License, Version 2.0 (the "License");
5795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson * you may not use this file except in compliance with the License.
6795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson * You may obtain a copy of the License at
7795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson *
8795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson *      http://www.apache.org/licenses/LICENSE-2.0
9795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson *
10795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson * Unless required by applicable law or agreed to in writing, software
11795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson * distributed under the License is distributed on an "AS IS" BASIS,
12795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson * See the License for the specific language governing permissions and
14795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson * limitations under the License.
15795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson */
16795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson
17795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilsonpackage android.support.v4.util;
18795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson
19795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilsonimport java.util.LinkedHashMap;
20795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilsonimport java.util.Map;
21795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson
22795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson/**
237dc96cc2410f551eefaa973ddc144146ad72d1ecDianne Hackborn * Static library version of {@link android.util.LruCache}. Used to write apps
242f57cb1149f4ff23de0c8b926b893412704d3d35Jesse Wilson * that run on API levels prior to 12. When running on API level 12 or above,
252f57cb1149f4ff23de0c8b926b893412704d3d35Jesse Wilson * this implementation is still used; it does not try to switch to the
262f57cb1149f4ff23de0c8b926b893412704d3d35Jesse Wilson * framework's implementation. See the framework SDK documentation for a class
272f57cb1149f4ff23de0c8b926b893412704d3d35Jesse Wilson * overview.
28795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson */
29795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilsonpublic class LruCache<K, V> {
30795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson    private final LinkedHashMap<K, V> map;
31795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson
32795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson    /** Size of this cache in units. Not necessarily the number of elements. */
33795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson    private int size;
34795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson    private int maxSize;
35795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson
36795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson    private int putCount;
37795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson    private int createCount;
38795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson    private int evictionCount;
39795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson    private int hitCount;
40795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson    private int missCount;
41795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson
42795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson    /**
43795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson     * @param maxSize for caches that do not override {@link #sizeOf}, this is
44795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson     *     the maximum number of entries in the cache. For all other caches,
45795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson     *     this is the maximum sum of the sizes of the entries in this cache.
46795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson     */
47795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson    public LruCache(int maxSize) {
48795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson        if (maxSize <= 0) {
49795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson            throw new IllegalArgumentException("maxSize <= 0");
50795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson        }
51795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson        this.maxSize = maxSize;
52795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson        this.map = new LinkedHashMap<K, V>(0, 0.75f, true);
53795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson    }
54795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson
55795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson    /**
56795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson     * Returns the value for {@code key} if it exists in the cache or can be
57795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson     * created by {@code #create}. If a value was returned, it is moved to the
58795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson     * head of the queue. This returns null if a value is not cached and cannot
59795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson     * be created.
60795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson     */
61a87be984a409450f8e697bd5009d2aa9ccebbea6Jesse Wilson    public final V get(K key) {
62795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson        if (key == null) {
63795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson            throw new NullPointerException("key == null");
64795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson        }
65795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson
66a87be984a409450f8e697bd5009d2aa9ccebbea6Jesse Wilson        V mapValue;
67a87be984a409450f8e697bd5009d2aa9ccebbea6Jesse Wilson        synchronized (this) {
68a87be984a409450f8e697bd5009d2aa9ccebbea6Jesse Wilson            mapValue = map.get(key);
69a87be984a409450f8e697bd5009d2aa9ccebbea6Jesse Wilson            if (mapValue != null) {
70a87be984a409450f8e697bd5009d2aa9ccebbea6Jesse Wilson                hitCount++;
71a87be984a409450f8e697bd5009d2aa9ccebbea6Jesse Wilson                return mapValue;
72a87be984a409450f8e697bd5009d2aa9ccebbea6Jesse Wilson            }
73a87be984a409450f8e697bd5009d2aa9ccebbea6Jesse Wilson            missCount++;
74795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson        }
75795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson
76a87be984a409450f8e697bd5009d2aa9ccebbea6Jesse Wilson        /*
77a87be984a409450f8e697bd5009d2aa9ccebbea6Jesse Wilson         * Attempt to create a value. This may take a long time, and the map
78a87be984a409450f8e697bd5009d2aa9ccebbea6Jesse Wilson         * may be different when create() returns. If a conflicting value was
79a87be984a409450f8e697bd5009d2aa9ccebbea6Jesse Wilson         * added to the map while create() was working, we leave that value in
80a87be984a409450f8e697bd5009d2aa9ccebbea6Jesse Wilson         * the map and release the created value.
81a87be984a409450f8e697bd5009d2aa9ccebbea6Jesse Wilson         */
82795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson
83a87be984a409450f8e697bd5009d2aa9ccebbea6Jesse Wilson        V createdValue = create(key);
84a87be984a409450f8e697bd5009d2aa9ccebbea6Jesse Wilson        if (createdValue == null) {
85a87be984a409450f8e697bd5009d2aa9ccebbea6Jesse Wilson            return null;
86a87be984a409450f8e697bd5009d2aa9ccebbea6Jesse Wilson        }
87795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson
88a87be984a409450f8e697bd5009d2aa9ccebbea6Jesse Wilson        synchronized (this) {
89795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson            createCount++;
90a87be984a409450f8e697bd5009d2aa9ccebbea6Jesse Wilson            mapValue = map.put(key, createdValue);
91a87be984a409450f8e697bd5009d2aa9ccebbea6Jesse Wilson
92a87be984a409450f8e697bd5009d2aa9ccebbea6Jesse Wilson            if (mapValue != null) {
93a87be984a409450f8e697bd5009d2aa9ccebbea6Jesse Wilson                // There was a conflict so undo that last put
94a87be984a409450f8e697bd5009d2aa9ccebbea6Jesse Wilson                map.put(key, mapValue);
95a87be984a409450f8e697bd5009d2aa9ccebbea6Jesse Wilson            } else {
96a87be984a409450f8e697bd5009d2aa9ccebbea6Jesse Wilson                size += safeSizeOf(key, createdValue);
97a87be984a409450f8e697bd5009d2aa9ccebbea6Jesse Wilson            }
98a87be984a409450f8e697bd5009d2aa9ccebbea6Jesse Wilson        }
99a87be984a409450f8e697bd5009d2aa9ccebbea6Jesse Wilson
100a87be984a409450f8e697bd5009d2aa9ccebbea6Jesse Wilson        if (mapValue != null) {
101a87be984a409450f8e697bd5009d2aa9ccebbea6Jesse Wilson            entryRemoved(false, key, createdValue, mapValue);
102a87be984a409450f8e697bd5009d2aa9ccebbea6Jesse Wilson            return mapValue;
103a87be984a409450f8e697bd5009d2aa9ccebbea6Jesse Wilson        } else {
104795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson            trimToSize(maxSize);
105a87be984a409450f8e697bd5009d2aa9ccebbea6Jesse Wilson            return createdValue;
106795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson        }
107795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson    }
108795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson
109795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson    /**
110795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson     * Caches {@code value} for {@code key}. The value is moved to the head of
111795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson     * the queue.
112795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson     *
113a87be984a409450f8e697bd5009d2aa9ccebbea6Jesse Wilson     * @return the previous value mapped by {@code key}.
114795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson     */
115a87be984a409450f8e697bd5009d2aa9ccebbea6Jesse Wilson    public final V put(K key, V value) {
116795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson        if (key == null || value == null) {
117795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson            throw new NullPointerException("key == null || value == null");
118795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson        }
119795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson
120a87be984a409450f8e697bd5009d2aa9ccebbea6Jesse Wilson        V previous;
121a87be984a409450f8e697bd5009d2aa9ccebbea6Jesse Wilson        synchronized (this) {
122a87be984a409450f8e697bd5009d2aa9ccebbea6Jesse Wilson            putCount++;
123a87be984a409450f8e697bd5009d2aa9ccebbea6Jesse Wilson            size += safeSizeOf(key, value);
124a87be984a409450f8e697bd5009d2aa9ccebbea6Jesse Wilson            previous = map.put(key, value);
125a87be984a409450f8e697bd5009d2aa9ccebbea6Jesse Wilson            if (previous != null) {
126a87be984a409450f8e697bd5009d2aa9ccebbea6Jesse Wilson                size -= safeSizeOf(key, previous);
127a87be984a409450f8e697bd5009d2aa9ccebbea6Jesse Wilson            }
128a87be984a409450f8e697bd5009d2aa9ccebbea6Jesse Wilson        }
129a87be984a409450f8e697bd5009d2aa9ccebbea6Jesse Wilson
130795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson        if (previous != null) {
131a87be984a409450f8e697bd5009d2aa9ccebbea6Jesse Wilson            entryRemoved(false, key, previous, value);
132795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson        }
133a87be984a409450f8e697bd5009d2aa9ccebbea6Jesse Wilson
134795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson        trimToSize(maxSize);
135795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson        return previous;
136795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson    }
137795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson
138a87be984a409450f8e697bd5009d2aa9ccebbea6Jesse Wilson    /**
139e00e7889dd8eb9389f7dff0f054e3e811b264a77Jeff Sharkey     * Remove the eldest entries until the total of remaining entries is at or
140e00e7889dd8eb9389f7dff0f054e3e811b264a77Jeff Sharkey     * below the requested size.
141e00e7889dd8eb9389f7dff0f054e3e811b264a77Jeff Sharkey     *
142a87be984a409450f8e697bd5009d2aa9ccebbea6Jesse Wilson     * @param maxSize the maximum size of the cache before returning. May be -1
143e00e7889dd8eb9389f7dff0f054e3e811b264a77Jeff Sharkey     *            to evict even 0-sized elements.
144a87be984a409450f8e697bd5009d2aa9ccebbea6Jesse Wilson     */
145e00e7889dd8eb9389f7dff0f054e3e811b264a77Jeff Sharkey    public void trimToSize(int maxSize) {
146a87be984a409450f8e697bd5009d2aa9ccebbea6Jesse Wilson        while (true) {
147a87be984a409450f8e697bd5009d2aa9ccebbea6Jesse Wilson            K key;
148a87be984a409450f8e697bd5009d2aa9ccebbea6Jesse Wilson            V value;
149a87be984a409450f8e697bd5009d2aa9ccebbea6Jesse Wilson            synchronized (this) {
150a87be984a409450f8e697bd5009d2aa9ccebbea6Jesse Wilson                if (size < 0 || (map.isEmpty() && size != 0)) {
151a87be984a409450f8e697bd5009d2aa9ccebbea6Jesse Wilson                    throw new IllegalStateException(getClass().getName()
152a87be984a409450f8e697bd5009d2aa9ccebbea6Jesse Wilson                            + ".sizeOf() is reporting inconsistent results!");
153a87be984a409450f8e697bd5009d2aa9ccebbea6Jesse Wilson                }
154795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson
1558e63c6994ea91c4a9ab3e68a60fcf6de7aab5565Jesse Wilson                if (size <= maxSize || map.isEmpty()) {
156a87be984a409450f8e697bd5009d2aa9ccebbea6Jesse Wilson                    break;
157a87be984a409450f8e697bd5009d2aa9ccebbea6Jesse Wilson                }
158a87be984a409450f8e697bd5009d2aa9ccebbea6Jesse Wilson
1598e63c6994ea91c4a9ab3e68a60fcf6de7aab5565Jesse Wilson                Map.Entry<K, V> toEvict = map.entrySet().iterator().next();
160a87be984a409450f8e697bd5009d2aa9ccebbea6Jesse Wilson                key = toEvict.getKey();
161a87be984a409450f8e697bd5009d2aa9ccebbea6Jesse Wilson                value = toEvict.getValue();
162a87be984a409450f8e697bd5009d2aa9ccebbea6Jesse Wilson                map.remove(key);
163a87be984a409450f8e697bd5009d2aa9ccebbea6Jesse Wilson                size -= safeSizeOf(key, value);
164a87be984a409450f8e697bd5009d2aa9ccebbea6Jesse Wilson                evictionCount++;
165a87be984a409450f8e697bd5009d2aa9ccebbea6Jesse Wilson            }
166795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson
167a87be984a409450f8e697bd5009d2aa9ccebbea6Jesse Wilson            entryRemoved(true, key, value, null);
168795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson        }
169795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson    }
170795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson
171795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson    /**
172795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson     * Removes the entry for {@code key} if it exists.
173795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson     *
174a87be984a409450f8e697bd5009d2aa9ccebbea6Jesse Wilson     * @return the previous value mapped by {@code key}.
175795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson     */
176a87be984a409450f8e697bd5009d2aa9ccebbea6Jesse Wilson    public final V remove(K key) {
177795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson        if (key == null) {
178795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson            throw new NullPointerException("key == null");
179795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson        }
180795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson
181a87be984a409450f8e697bd5009d2aa9ccebbea6Jesse Wilson        V previous;
182a87be984a409450f8e697bd5009d2aa9ccebbea6Jesse Wilson        synchronized (this) {
183a87be984a409450f8e697bd5009d2aa9ccebbea6Jesse Wilson            previous = map.remove(key);
184a87be984a409450f8e697bd5009d2aa9ccebbea6Jesse Wilson            if (previous != null) {
185a87be984a409450f8e697bd5009d2aa9ccebbea6Jesse Wilson                size -= safeSizeOf(key, previous);
186a87be984a409450f8e697bd5009d2aa9ccebbea6Jesse Wilson            }
187a87be984a409450f8e697bd5009d2aa9ccebbea6Jesse Wilson        }
188a87be984a409450f8e697bd5009d2aa9ccebbea6Jesse Wilson
189795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson        if (previous != null) {
190a87be984a409450f8e697bd5009d2aa9ccebbea6Jesse Wilson            entryRemoved(false, key, previous, null);
191795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson        }
192a87be984a409450f8e697bd5009d2aa9ccebbea6Jesse Wilson
193795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson        return previous;
194795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson    }
195795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson
196795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson    /**
197a87be984a409450f8e697bd5009d2aa9ccebbea6Jesse Wilson     * Called for entries that have been evicted or removed. This method is
198a87be984a409450f8e697bd5009d2aa9ccebbea6Jesse Wilson     * invoked when a value is evicted to make space, removed by a call to
199a87be984a409450f8e697bd5009d2aa9ccebbea6Jesse Wilson     * {@link #remove}, or replaced by a call to {@link #put}. The default
200a87be984a409450f8e697bd5009d2aa9ccebbea6Jesse Wilson     * implementation does nothing.
201a87be984a409450f8e697bd5009d2aa9ccebbea6Jesse Wilson     *
202a87be984a409450f8e697bd5009d2aa9ccebbea6Jesse Wilson     * <p>The method is called without synchronization: other threads may
203a87be984a409450f8e697bd5009d2aa9ccebbea6Jesse Wilson     * access the cache while this method is executing.
204a87be984a409450f8e697bd5009d2aa9ccebbea6Jesse Wilson     *
205a87be984a409450f8e697bd5009d2aa9ccebbea6Jesse Wilson     * @param evicted true if the entry is being removed to make space, false
206a87be984a409450f8e697bd5009d2aa9ccebbea6Jesse Wilson     *     if the removal was caused by a {@link #put} or {@link #remove}.
207a87be984a409450f8e697bd5009d2aa9ccebbea6Jesse Wilson     * @param newValue the new value for {@code key}, if it exists. If non-null,
208a87be984a409450f8e697bd5009d2aa9ccebbea6Jesse Wilson     *     this removal was caused by a {@link #put}. Otherwise it was caused by
209a87be984a409450f8e697bd5009d2aa9ccebbea6Jesse Wilson     *     an eviction or a {@link #remove}.
210795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson     */
211a87be984a409450f8e697bd5009d2aa9ccebbea6Jesse Wilson    protected void entryRemoved(boolean evicted, K key, V oldValue, V newValue) {}
212795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson
213795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson    /**
214795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson     * Called after a cache miss to compute a value for the corresponding key.
215795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson     * Returns the computed value or null if no value can be computed. The
216795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson     * default implementation returns null.
217a87be984a409450f8e697bd5009d2aa9ccebbea6Jesse Wilson     *
218a87be984a409450f8e697bd5009d2aa9ccebbea6Jesse Wilson     * <p>The method is called without synchronization: other threads may
219a87be984a409450f8e697bd5009d2aa9ccebbea6Jesse Wilson     * access the cache while this method is executing.
220a87be984a409450f8e697bd5009d2aa9ccebbea6Jesse Wilson     *
221a87be984a409450f8e697bd5009d2aa9ccebbea6Jesse Wilson     * <p>If a value for {@code key} exists in the cache when this method
222a87be984a409450f8e697bd5009d2aa9ccebbea6Jesse Wilson     * returns, the created value will be released with {@link #entryRemoved}
223a87be984a409450f8e697bd5009d2aa9ccebbea6Jesse Wilson     * and discarded. This can occur when multiple threads request the same key
224a87be984a409450f8e697bd5009d2aa9ccebbea6Jesse Wilson     * at the same time (causing multiple values to be created), or when one
225a87be984a409450f8e697bd5009d2aa9ccebbea6Jesse Wilson     * thread calls {@link #put} while another is creating a value for the same
226a87be984a409450f8e697bd5009d2aa9ccebbea6Jesse Wilson     * key.
227795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson     */
228795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson    protected V create(K key) {
229795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson        return null;
230795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson    }
231795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson
232795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson    private int safeSizeOf(K key, V value) {
233795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson        int result = sizeOf(key, value);
234795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson        if (result < 0) {
235795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson            throw new IllegalStateException("Negative size: " + key + "=" + value);
236795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson        }
237795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson        return result;
238795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson    }
239795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson
240795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson    /**
241795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson     * Returns the size of the entry for {@code key} and {@code value} in
242795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson     * user-defined units.  The default implementation returns 1 so that size
243795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson     * is the number of entries and max size is the maximum number of entries.
244795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson     *
245795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson     * <p>An entry's size must not change while it is in the cache.
246795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson     */
247795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson    protected int sizeOf(K key, V value) {
248795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson        return 1;
249795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson    }
250795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson
251795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson    /**
252a87be984a409450f8e697bd5009d2aa9ccebbea6Jesse Wilson     * Clear the cache, calling {@link #entryRemoved} on each removed entry.
253795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson     */
254a87be984a409450f8e697bd5009d2aa9ccebbea6Jesse Wilson    public final void evictAll() {
255795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson        trimToSize(-1); // -1 will evict 0-sized elements
256795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson    }
257795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson
258795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson    /**
259795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson     * For caches that do not override {@link #sizeOf}, this returns the number
260795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson     * of entries in the cache. For all other caches, this returns the sum of
261795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson     * the sizes of the entries in this cache.
262795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson     */
263795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson    public synchronized final int size() {
264795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson        return size;
265795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson    }
266795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson
267795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson    /**
268795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson     * For caches that do not override {@link #sizeOf}, this returns the maximum
269795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson     * number of entries in the cache. For all other caches, this returns the
270795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson     * maximum sum of the sizes of the entries in this cache.
271795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson     */
272795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson    public synchronized final int maxSize() {
273795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson        return maxSize;
274795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson    }
275795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson
276795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson    /**
277795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson     * Returns the number of times {@link #get} returned a value.
278795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson     */
279795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson    public synchronized final int hitCount() {
280795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson        return hitCount;
281795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson    }
282795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson
283795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson    /**
284795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson     * Returns the number of times {@link #get} returned null or required a new
285795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson     * value to be created.
286795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson     */
287795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson    public synchronized final int missCount() {
288795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson        return missCount;
289795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson    }
290795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson
291795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson    /**
292795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson     * Returns the number of times {@link #create(Object)} returned a value.
293795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson     */
294795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson    public synchronized final int createCount() {
295795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson        return createCount;
296795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson    }
297795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson
298795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson    /**
299795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson     * Returns the number of times {@link #put} was called.
300795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson     */
301795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson    public synchronized final int putCount() {
302795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson        return putCount;
303795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson    }
304795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson
305795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson    /**
306795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson     * Returns the number of values that have been evicted.
307795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson     */
308795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson    public synchronized final int evictionCount() {
309795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson        return evictionCount;
310795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson    }
311795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson
312795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson    /**
313795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson     * Returns a copy of the current contents of the cache, ordered from least
314795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson     * recently accessed to most recently accessed.
315795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson     */
316795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson    public synchronized final Map<K, V> snapshot() {
317795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson        return new LinkedHashMap<K, V>(map);
318795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson    }
319795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson
320795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson    @Override public synchronized final String toString() {
321795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson        int accesses = hitCount + missCount;
322795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson        int hitPercent = accesses != 0 ? (100 * hitCount / accesses) : 0;
323795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson        return String.format("LruCache[maxSize=%d,hits=%d,misses=%d,hitRate=%d%%]",
324795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson                maxSize, hitCount, missCount, hitPercent);
325795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson    }
326795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson}
327