1f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin/*
2f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * Copyright (C) 2009 The Android Open Source Project
3f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin *
4f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * Licensed under the Apache License, Version 2.0 (the "License");
5f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * you may not use this file except in compliance with the License.
6f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * You may obtain a copy of the License at
7f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin *
8f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin *      http://www.apache.org/licenses/LICENSE-2.0
9f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin *
10f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * Unless required by applicable law or agreed to in writing, software
11f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * distributed under the License is distributed on an "AS IS" BASIS,
12f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * See the License for the specific language governing permissions and
14f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * limitations under the License.
15f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin */
16f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
17f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linpackage com.android.gallery3d.common;
18f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
19f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport java.lang.ref.ReferenceQueue;
20f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport java.lang.ref.WeakReference;
21f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport java.util.HashMap;
22f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport java.util.LinkedHashMap;
23f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport java.util.Map;
24f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
25f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin/**
26f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * An LRU cache which stores recently inserted entries and all entries ever
27f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * inserted which still has a strong reference elsewhere.
28f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin */
29f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linpublic class LruCache<K, V> {
30f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
31f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    private final HashMap<K, V> mLruMap;
32f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    private final HashMap<K, Entry<K, V>> mWeakMap =
33f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            new HashMap<K, Entry<K, V>>();
34f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    private ReferenceQueue<V> mQueue = new ReferenceQueue<V>();
35f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
36f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    @SuppressWarnings("serial")
37f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    public LruCache(final int capacity) {
38f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        mLruMap = new LinkedHashMap<K, V>(16, 0.75f, true) {
39f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            @Override
40f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            protected boolean removeEldestEntry(Map.Entry<K, V> eldest) {
41f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                return size() > capacity;
42f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            }
43f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        };
44f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
45f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
46f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    private static class Entry<K, V> extends WeakReference<V> {
47f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        K mKey;
48f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
49f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        public Entry(K key, V value, ReferenceQueue<V> queue) {
50f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            super(value, queue);
51f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            mKey = key;
52f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        }
53f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
54f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
55f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    @SuppressWarnings("unchecked")
56f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    private void cleanUpWeakMap() {
57f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        Entry<K, V> entry = (Entry<K, V>) mQueue.poll();
58f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        while (entry != null) {
59f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            mWeakMap.remove(entry.mKey);
60f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            entry = (Entry<K, V>) mQueue.poll();
61f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        }
62f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
63f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
64f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    public synchronized boolean containsKey(K key) {
65f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        cleanUpWeakMap();
66f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        return mWeakMap.containsKey(key);
67f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
68f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
69f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    public synchronized V put(K key, V value) {
70f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        cleanUpWeakMap();
71f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        mLruMap.put(key, value);
72f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        Entry<K, V> entry = mWeakMap.put(
73f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                key, new Entry<K, V>(key, value, mQueue));
74f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        return entry == null ? null : entry.get();
75f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
76f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
77f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    public synchronized V get(K key) {
78f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        cleanUpWeakMap();
79f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        V value = mLruMap.get(key);
80f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        if (value != null) return value;
81f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        Entry<K, V> entry = mWeakMap.get(key);
82f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        return entry == null ? null : entry.get();
83f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
84f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
85f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    public synchronized void clear() {
86f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        mLruMap.clear();
87f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        mWeakMap.clear();
88f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        mQueue = new ReferenceQueue<V>();
89f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
90f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin}
91