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    /**
56ec04140e47f9253d6d25c5e0e5bb66b52c547ac7Narayan Kamath     * Sets the size of the cache.
57ec04140e47f9253d6d25c5e0e5bb66b52c547ac7Narayan Kamath     *
58ec04140e47f9253d6d25c5e0e5bb66b52c547ac7Narayan Kamath     * @param maxSize The new maximum size.
59ec04140e47f9253d6d25c5e0e5bb66b52c547ac7Narayan Kamath     */
60ec04140e47f9253d6d25c5e0e5bb66b52c547ac7Narayan Kamath    public void resize(int maxSize) {
61ec04140e47f9253d6d25c5e0e5bb66b52c547ac7Narayan Kamath        if (maxSize <= 0) {
62ec04140e47f9253d6d25c5e0e5bb66b52c547ac7Narayan Kamath            throw new IllegalArgumentException("maxSize <= 0");
63ec04140e47f9253d6d25c5e0e5bb66b52c547ac7Narayan Kamath        }
64ec04140e47f9253d6d25c5e0e5bb66b52c547ac7Narayan Kamath
65ec04140e47f9253d6d25c5e0e5bb66b52c547ac7Narayan Kamath        synchronized (this) {
66ec04140e47f9253d6d25c5e0e5bb66b52c547ac7Narayan Kamath            this.maxSize = maxSize;
67ec04140e47f9253d6d25c5e0e5bb66b52c547ac7Narayan Kamath        }
68ec04140e47f9253d6d25c5e0e5bb66b52c547ac7Narayan Kamath        trimToSize(maxSize);
69ec04140e47f9253d6d25c5e0e5bb66b52c547ac7Narayan Kamath    }
70ec04140e47f9253d6d25c5e0e5bb66b52c547ac7Narayan Kamath
71ec04140e47f9253d6d25c5e0e5bb66b52c547ac7Narayan Kamath    /**
72795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson     * Returns the value for {@code key} if it exists in the cache or can be
73795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson     * created by {@code #create}. If a value was returned, it is moved to the
74795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson     * head of the queue. This returns null if a value is not cached and cannot
75795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson     * be created.
76795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson     */
77a87be984a409450f8e697bd5009d2aa9ccebbea6Jesse Wilson    public final V get(K key) {
78795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson        if (key == null) {
79795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson            throw new NullPointerException("key == null");
80795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson        }
81795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson
82a87be984a409450f8e697bd5009d2aa9ccebbea6Jesse Wilson        V mapValue;
83a87be984a409450f8e697bd5009d2aa9ccebbea6Jesse Wilson        synchronized (this) {
84a87be984a409450f8e697bd5009d2aa9ccebbea6Jesse Wilson            mapValue = map.get(key);
85a87be984a409450f8e697bd5009d2aa9ccebbea6Jesse Wilson            if (mapValue != null) {
86a87be984a409450f8e697bd5009d2aa9ccebbea6Jesse Wilson                hitCount++;
87a87be984a409450f8e697bd5009d2aa9ccebbea6Jesse Wilson                return mapValue;
88a87be984a409450f8e697bd5009d2aa9ccebbea6Jesse Wilson            }
89a87be984a409450f8e697bd5009d2aa9ccebbea6Jesse Wilson            missCount++;
90795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson        }
91795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson
92a87be984a409450f8e697bd5009d2aa9ccebbea6Jesse Wilson        /*
93a87be984a409450f8e697bd5009d2aa9ccebbea6Jesse Wilson         * Attempt to create a value. This may take a long time, and the map
94a87be984a409450f8e697bd5009d2aa9ccebbea6Jesse Wilson         * may be different when create() returns. If a conflicting value was
95a87be984a409450f8e697bd5009d2aa9ccebbea6Jesse Wilson         * added to the map while create() was working, we leave that value in
96a87be984a409450f8e697bd5009d2aa9ccebbea6Jesse Wilson         * the map and release the created value.
97a87be984a409450f8e697bd5009d2aa9ccebbea6Jesse Wilson         */
98795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson
99a87be984a409450f8e697bd5009d2aa9ccebbea6Jesse Wilson        V createdValue = create(key);
100a87be984a409450f8e697bd5009d2aa9ccebbea6Jesse Wilson        if (createdValue == null) {
101a87be984a409450f8e697bd5009d2aa9ccebbea6Jesse Wilson            return null;
102a87be984a409450f8e697bd5009d2aa9ccebbea6Jesse Wilson        }
103795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson
104a87be984a409450f8e697bd5009d2aa9ccebbea6Jesse Wilson        synchronized (this) {
105795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson            createCount++;
106a87be984a409450f8e697bd5009d2aa9ccebbea6Jesse Wilson            mapValue = map.put(key, createdValue);
107a87be984a409450f8e697bd5009d2aa9ccebbea6Jesse Wilson
108a87be984a409450f8e697bd5009d2aa9ccebbea6Jesse Wilson            if (mapValue != null) {
109a87be984a409450f8e697bd5009d2aa9ccebbea6Jesse Wilson                // There was a conflict so undo that last put
110a87be984a409450f8e697bd5009d2aa9ccebbea6Jesse Wilson                map.put(key, mapValue);
111a87be984a409450f8e697bd5009d2aa9ccebbea6Jesse Wilson            } else {
112a87be984a409450f8e697bd5009d2aa9ccebbea6Jesse Wilson                size += safeSizeOf(key, createdValue);
113a87be984a409450f8e697bd5009d2aa9ccebbea6Jesse Wilson            }
114a87be984a409450f8e697bd5009d2aa9ccebbea6Jesse Wilson        }
115a87be984a409450f8e697bd5009d2aa9ccebbea6Jesse Wilson
116a87be984a409450f8e697bd5009d2aa9ccebbea6Jesse Wilson        if (mapValue != null) {
117a87be984a409450f8e697bd5009d2aa9ccebbea6Jesse Wilson            entryRemoved(false, key, createdValue, mapValue);
118a87be984a409450f8e697bd5009d2aa9ccebbea6Jesse Wilson            return mapValue;
119a87be984a409450f8e697bd5009d2aa9ccebbea6Jesse Wilson        } else {
120795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson            trimToSize(maxSize);
121a87be984a409450f8e697bd5009d2aa9ccebbea6Jesse Wilson            return createdValue;
122795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson        }
123795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson    }
124795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson
125795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson    /**
126795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson     * Caches {@code value} for {@code key}. The value is moved to the head of
127795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson     * the queue.
128795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson     *
129a87be984a409450f8e697bd5009d2aa9ccebbea6Jesse Wilson     * @return the previous value mapped by {@code key}.
130795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson     */
131a87be984a409450f8e697bd5009d2aa9ccebbea6Jesse Wilson    public final V put(K key, V value) {
132795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson        if (key == null || value == null) {
133795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson            throw new NullPointerException("key == null || value == null");
134795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson        }
135795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson
136a87be984a409450f8e697bd5009d2aa9ccebbea6Jesse Wilson        V previous;
137a87be984a409450f8e697bd5009d2aa9ccebbea6Jesse Wilson        synchronized (this) {
138a87be984a409450f8e697bd5009d2aa9ccebbea6Jesse Wilson            putCount++;
139a87be984a409450f8e697bd5009d2aa9ccebbea6Jesse Wilson            size += safeSizeOf(key, value);
140a87be984a409450f8e697bd5009d2aa9ccebbea6Jesse Wilson            previous = map.put(key, value);
141a87be984a409450f8e697bd5009d2aa9ccebbea6Jesse Wilson            if (previous != null) {
142a87be984a409450f8e697bd5009d2aa9ccebbea6Jesse Wilson                size -= safeSizeOf(key, previous);
143a87be984a409450f8e697bd5009d2aa9ccebbea6Jesse Wilson            }
144a87be984a409450f8e697bd5009d2aa9ccebbea6Jesse Wilson        }
145a87be984a409450f8e697bd5009d2aa9ccebbea6Jesse Wilson
146795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson        if (previous != null) {
147a87be984a409450f8e697bd5009d2aa9ccebbea6Jesse Wilson            entryRemoved(false, key, previous, value);
148795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson        }
149a87be984a409450f8e697bd5009d2aa9ccebbea6Jesse Wilson
150795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson        trimToSize(maxSize);
151795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson        return previous;
152795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson    }
153795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson
154a87be984a409450f8e697bd5009d2aa9ccebbea6Jesse Wilson    /**
155e00e7889dd8eb9389f7dff0f054e3e811b264a77Jeff Sharkey     * Remove the eldest entries until the total of remaining entries is at or
156e00e7889dd8eb9389f7dff0f054e3e811b264a77Jeff Sharkey     * below the requested size.
157e00e7889dd8eb9389f7dff0f054e3e811b264a77Jeff Sharkey     *
158a87be984a409450f8e697bd5009d2aa9ccebbea6Jesse Wilson     * @param maxSize the maximum size of the cache before returning. May be -1
159e00e7889dd8eb9389f7dff0f054e3e811b264a77Jeff Sharkey     *            to evict even 0-sized elements.
160a87be984a409450f8e697bd5009d2aa9ccebbea6Jesse Wilson     */
161e00e7889dd8eb9389f7dff0f054e3e811b264a77Jeff Sharkey    public void trimToSize(int maxSize) {
162a87be984a409450f8e697bd5009d2aa9ccebbea6Jesse Wilson        while (true) {
163a87be984a409450f8e697bd5009d2aa9ccebbea6Jesse Wilson            K key;
164a87be984a409450f8e697bd5009d2aa9ccebbea6Jesse Wilson            V value;
165a87be984a409450f8e697bd5009d2aa9ccebbea6Jesse Wilson            synchronized (this) {
166a87be984a409450f8e697bd5009d2aa9ccebbea6Jesse Wilson                if (size < 0 || (map.isEmpty() && size != 0)) {
167a87be984a409450f8e697bd5009d2aa9ccebbea6Jesse Wilson                    throw new IllegalStateException(getClass().getName()
168a87be984a409450f8e697bd5009d2aa9ccebbea6Jesse Wilson                            + ".sizeOf() is reporting inconsistent results!");
169a87be984a409450f8e697bd5009d2aa9ccebbea6Jesse Wilson                }
170795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson
1718e63c6994ea91c4a9ab3e68a60fcf6de7aab5565Jesse Wilson                if (size <= maxSize || map.isEmpty()) {
172a87be984a409450f8e697bd5009d2aa9ccebbea6Jesse Wilson                    break;
173a87be984a409450f8e697bd5009d2aa9ccebbea6Jesse Wilson                }
174a87be984a409450f8e697bd5009d2aa9ccebbea6Jesse Wilson
1758e63c6994ea91c4a9ab3e68a60fcf6de7aab5565Jesse Wilson                Map.Entry<K, V> toEvict = map.entrySet().iterator().next();
176a87be984a409450f8e697bd5009d2aa9ccebbea6Jesse Wilson                key = toEvict.getKey();
177a87be984a409450f8e697bd5009d2aa9ccebbea6Jesse Wilson                value = toEvict.getValue();
178a87be984a409450f8e697bd5009d2aa9ccebbea6Jesse Wilson                map.remove(key);
179a87be984a409450f8e697bd5009d2aa9ccebbea6Jesse Wilson                size -= safeSizeOf(key, value);
180a87be984a409450f8e697bd5009d2aa9ccebbea6Jesse Wilson                evictionCount++;
181a87be984a409450f8e697bd5009d2aa9ccebbea6Jesse Wilson            }
182795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson
183a87be984a409450f8e697bd5009d2aa9ccebbea6Jesse Wilson            entryRemoved(true, key, value, null);
184795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson        }
185795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson    }
186795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson
187795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson    /**
188795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson     * Removes the entry for {@code key} if it exists.
189795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson     *
190a87be984a409450f8e697bd5009d2aa9ccebbea6Jesse Wilson     * @return the previous value mapped by {@code key}.
191795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson     */
192a87be984a409450f8e697bd5009d2aa9ccebbea6Jesse Wilson    public final V remove(K key) {
193795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson        if (key == null) {
194795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson            throw new NullPointerException("key == null");
195795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson        }
196795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson
197a87be984a409450f8e697bd5009d2aa9ccebbea6Jesse Wilson        V previous;
198a87be984a409450f8e697bd5009d2aa9ccebbea6Jesse Wilson        synchronized (this) {
199a87be984a409450f8e697bd5009d2aa9ccebbea6Jesse Wilson            previous = map.remove(key);
200a87be984a409450f8e697bd5009d2aa9ccebbea6Jesse Wilson            if (previous != null) {
201a87be984a409450f8e697bd5009d2aa9ccebbea6Jesse Wilson                size -= safeSizeOf(key, previous);
202a87be984a409450f8e697bd5009d2aa9ccebbea6Jesse Wilson            }
203a87be984a409450f8e697bd5009d2aa9ccebbea6Jesse Wilson        }
204a87be984a409450f8e697bd5009d2aa9ccebbea6Jesse Wilson
205795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson        if (previous != null) {
206a87be984a409450f8e697bd5009d2aa9ccebbea6Jesse Wilson            entryRemoved(false, key, previous, null);
207795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson        }
208a87be984a409450f8e697bd5009d2aa9ccebbea6Jesse Wilson
209795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson        return previous;
210795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson    }
211795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson
212795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson    /**
213a87be984a409450f8e697bd5009d2aa9ccebbea6Jesse Wilson     * Called for entries that have been evicted or removed. This method is
214a87be984a409450f8e697bd5009d2aa9ccebbea6Jesse Wilson     * invoked when a value is evicted to make space, removed by a call to
215a87be984a409450f8e697bd5009d2aa9ccebbea6Jesse Wilson     * {@link #remove}, or replaced by a call to {@link #put}. The default
216a87be984a409450f8e697bd5009d2aa9ccebbea6Jesse Wilson     * implementation does nothing.
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     * @param evicted true if the entry is being removed to make space, false
222a87be984a409450f8e697bd5009d2aa9ccebbea6Jesse Wilson     *     if the removal was caused by a {@link #put} or {@link #remove}.
223a87be984a409450f8e697bd5009d2aa9ccebbea6Jesse Wilson     * @param newValue the new value for {@code key}, if it exists. If non-null,
224a87be984a409450f8e697bd5009d2aa9ccebbea6Jesse Wilson     *     this removal was caused by a {@link #put}. Otherwise it was caused by
225a87be984a409450f8e697bd5009d2aa9ccebbea6Jesse Wilson     *     an eviction or a {@link #remove}.
226795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson     */
227a87be984a409450f8e697bd5009d2aa9ccebbea6Jesse Wilson    protected void entryRemoved(boolean evicted, K key, V oldValue, V newValue) {}
228795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson
229795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson    /**
230795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson     * Called after a cache miss to compute a value for the corresponding key.
231795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson     * Returns the computed value or null if no value can be computed. The
232795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson     * default implementation returns null.
233a87be984a409450f8e697bd5009d2aa9ccebbea6Jesse Wilson     *
234a87be984a409450f8e697bd5009d2aa9ccebbea6Jesse Wilson     * <p>The method is called without synchronization: other threads may
235a87be984a409450f8e697bd5009d2aa9ccebbea6Jesse Wilson     * access the cache while this method is executing.
236a87be984a409450f8e697bd5009d2aa9ccebbea6Jesse Wilson     *
237a87be984a409450f8e697bd5009d2aa9ccebbea6Jesse Wilson     * <p>If a value for {@code key} exists in the cache when this method
238a87be984a409450f8e697bd5009d2aa9ccebbea6Jesse Wilson     * returns, the created value will be released with {@link #entryRemoved}
239a87be984a409450f8e697bd5009d2aa9ccebbea6Jesse Wilson     * and discarded. This can occur when multiple threads request the same key
240a87be984a409450f8e697bd5009d2aa9ccebbea6Jesse Wilson     * at the same time (causing multiple values to be created), or when one
241a87be984a409450f8e697bd5009d2aa9ccebbea6Jesse Wilson     * thread calls {@link #put} while another is creating a value for the same
242a87be984a409450f8e697bd5009d2aa9ccebbea6Jesse Wilson     * key.
243795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson     */
244795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson    protected V create(K key) {
245795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson        return null;
246795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson    }
247795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson
248795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson    private int safeSizeOf(K key, V value) {
249795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson        int result = sizeOf(key, value);
250795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson        if (result < 0) {
251795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson            throw new IllegalStateException("Negative size: " + key + "=" + value);
252795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson        }
253795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson        return result;
254795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson    }
255795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson
256795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson    /**
257795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson     * Returns the size of the entry for {@code key} and {@code value} in
258795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson     * user-defined units.  The default implementation returns 1 so that size
259795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson     * is the number of entries and max size is the maximum number of entries.
260795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson     *
261795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson     * <p>An entry's size must not change while it is in the cache.
262795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson     */
263795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson    protected int sizeOf(K key, V value) {
264795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson        return 1;
265795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson    }
266795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson
267795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson    /**
268a87be984a409450f8e697bd5009d2aa9ccebbea6Jesse Wilson     * Clear the cache, calling {@link #entryRemoved} on each removed entry.
269795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson     */
270a87be984a409450f8e697bd5009d2aa9ccebbea6Jesse Wilson    public final void evictAll() {
271795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson        trimToSize(-1); // -1 will evict 0-sized elements
272795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson    }
273795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson
274795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson    /**
275795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson     * For caches that do not override {@link #sizeOf}, this returns the number
276795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson     * of entries in the cache. For all other caches, this returns the sum of
277795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson     * the sizes of the entries in this cache.
278795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson     */
279795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson    public synchronized final int size() {
280795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson        return size;
281795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson    }
282795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson
283795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson    /**
284795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson     * For caches that do not override {@link #sizeOf}, this returns the maximum
285795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson     * number of entries in the cache. For all other caches, this returns the
286795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson     * maximum sum of the sizes of the entries in this cache.
287795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson     */
288795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson    public synchronized final int maxSize() {
289795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson        return maxSize;
290795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson    }
291795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson
292795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson    /**
293ec04140e47f9253d6d25c5e0e5bb66b52c547ac7Narayan Kamath     * Returns the number of times {@link #get} returned a value that was
294ec04140e47f9253d6d25c5e0e5bb66b52c547ac7Narayan Kamath     * already present in the cache.
295795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson     */
296795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson    public synchronized final int hitCount() {
297795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson        return hitCount;
298795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson    }
299795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson
300795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson    /**
301795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson     * Returns the number of times {@link #get} returned null or required a new
302795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson     * value to be created.
303795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson     */
304795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson    public synchronized final int missCount() {
305795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson        return missCount;
306795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson    }
307795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson
308795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson    /**
309795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson     * Returns the number of times {@link #create(Object)} returned a value.
310795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson     */
311795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson    public synchronized final int createCount() {
312795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson        return createCount;
313795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson    }
314795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson
315795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson    /**
316795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson     * Returns the number of times {@link #put} was called.
317795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson     */
318795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson    public synchronized final int putCount() {
319795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson        return putCount;
320795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson    }
321795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson
322795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson    /**
323795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson     * Returns the number of values that have been evicted.
324795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson     */
325795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson    public synchronized final int evictionCount() {
326795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson        return evictionCount;
327795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson    }
328795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson
329795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson    /**
330795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson     * Returns a copy of the current contents of the cache, ordered from least
331795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson     * recently accessed to most recently accessed.
332795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson     */
333795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson    public synchronized final Map<K, V> snapshot() {
334795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson        return new LinkedHashMap<K, V>(map);
335795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson    }
336795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson
337795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson    @Override public synchronized final String toString() {
338795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson        int accesses = hitCount + missCount;
339795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson        int hitPercent = accesses != 0 ? (100 * hitCount / accesses) : 0;
340795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson        return String.format("LruCache[maxSize=%d,hits=%d,misses=%d,hitRate=%d%%]",
341795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson                maxSize, hitCount, missCount, hitPercent);
342795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson    }
343795b97d901e1793dac5c3e67d43c96a758fec388Jesse Wilson}
344