blob: 83cda8689fd1cd56037cf27abef1be56d6551e65 [file] [log] [blame]
Fabrice Di Meglioe88a9a42011-02-24 19:56:18 -08001/*
2 * Copyright (C) 2010 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#ifndef ANDROID_UTILS_GENERATION_CACHE_H
18#define ANDROID_UTILS_GENERATION_CACHE_H
19
20#include <utils/KeyedVector.h>
21#include <utils/RefBase.h>
22
23namespace android {
24
25/**
26 * GenerationCache callback used when an item is removed
27 */
28template<typename EntryKey, typename EntryValue>
29class OnEntryRemoved {
30public:
31 virtual ~OnEntryRemoved() { };
32 virtual void operator()(EntryKey& key, EntryValue& value) = 0;
33}; // class OnEntryRemoved
34
35template<typename EntryKey, typename EntryValue>
36struct Entry: public LightRefBase<Entry<EntryKey, EntryValue> > {
Jeff Brownb4293fe2011-11-11 15:40:13 -080037 Entry(const Entry<EntryKey, EntryValue>& e) :
38 key(e.key), value(e.value),
39 parent(e.parent), child(e.child) { }
40 Entry(const EntryKey& key, const EntryValue& value) :
41 key(key), value(value) { }
Fabrice Di Meglioe88a9a42011-02-24 19:56:18 -080042
43 EntryKey key;
44 EntryValue value;
45
Jeff Brownb4293fe2011-11-11 15:40:13 -080046 sp<Entry<EntryKey, EntryValue> > parent; // next older entry
47 sp<Entry<EntryKey, EntryValue> > child; // next younger entry
Fabrice Di Meglioe88a9a42011-02-24 19:56:18 -080048}; // struct Entry
49
50/**
51 * A LRU type cache
52 */
53template<typename K, typename V>
54class GenerationCache {
55public:
56 GenerationCache(uint32_t maxCapacity);
57 virtual ~GenerationCache();
58
59 enum Capacity {
60 kUnlimitedCapacity,
61 };
62
63 void setOnEntryRemovedListener(OnEntryRemoved<K, V>* listener);
64
Jeff Brownb4293fe2011-11-11 15:40:13 -080065 size_t size() const;
66
Fabrice Di Meglioe88a9a42011-02-24 19:56:18 -080067 void clear();
68
Jeff Brownb4293fe2011-11-11 15:40:13 -080069 bool contains(const K& key) const;
70 const K& getKeyAt(size_t index) const;
71 const V& getValueAt(size_t index) const;
Fabrice Di Meglioe88a9a42011-02-24 19:56:18 -080072
Jeff Brownb4293fe2011-11-11 15:40:13 -080073 const V& get(const K& key);
74 bool put(const K& key, const V& value);
Fabrice Di Meglioe88a9a42011-02-24 19:56:18 -080075
Jeff Brownb4293fe2011-11-11 15:40:13 -080076 void removeAt(ssize_t index);
77 bool remove(const K& key);
78 bool removeOldest();
Fabrice Di Meglioe88a9a42011-02-24 19:56:18 -080079
80private:
81 KeyedVector<K, sp<Entry<K, V> > > mCache;
82 uint32_t mMaxCapacity;
83
84 OnEntryRemoved<K, V>* mListener;
85
86 sp<Entry<K, V> > mOldest;
87 sp<Entry<K, V> > mYoungest;
Jeff Brownb4293fe2011-11-11 15:40:13 -080088
89 void attachToCache(const sp<Entry<K, V> >& entry);
90 void detachFromCache(const sp<Entry<K, V> >& entry);
Fabrice Di Meglioe88a9a42011-02-24 19:56:18 -080091}; // class GenerationCache
92
93template<typename K, typename V>
94GenerationCache<K, V>::GenerationCache(uint32_t maxCapacity): mMaxCapacity(maxCapacity),
95 mListener(NULL) {
96};
97
98template<typename K, typename V>
99GenerationCache<K, V>::~GenerationCache() {
100 clear();
101};
102
103template<typename K, typename V>
104uint32_t GenerationCache<K, V>::size() const {
105 return mCache.size();
106}
107
108/**
109 * Should be set by the user of the Cache so that the callback is called whenever an item is
110 * removed from the cache
111 */
112template<typename K, typename V>
113void GenerationCache<K, V>::setOnEntryRemovedListener(OnEntryRemoved<K, V>* listener) {
114 mListener = listener;
115}
116
117template<typename K, typename V>
118void GenerationCache<K, V>::clear() {
119 if (mListener) {
120 for (uint32_t i = 0; i < mCache.size(); i++) {
121 sp<Entry<K, V> > entry = mCache.valueAt(i);
122 if (mListener) {
123 (*mListener)(entry->key, entry->value);
124 }
125 }
126 }
127 mCache.clear();
128 mYoungest.clear();
129 mOldest.clear();
130}
131
132template<typename K, typename V>
Jeff Brownb4293fe2011-11-11 15:40:13 -0800133bool GenerationCache<K, V>::contains(const K& key) const {
Fabrice Di Meglioe88a9a42011-02-24 19:56:18 -0800134 return mCache.indexOfKey(key) >= 0;
135}
136
137template<typename K, typename V>
Jeff Brownb4293fe2011-11-11 15:40:13 -0800138const K& GenerationCache<K, V>::getKeyAt(size_t index) const {
Fabrice Di Meglioe88a9a42011-02-24 19:56:18 -0800139 return mCache.keyAt(index);
140}
141
142template<typename K, typename V>
Jeff Brownb4293fe2011-11-11 15:40:13 -0800143const V& GenerationCache<K, V>::getValueAt(size_t index) const {
Fabrice Di Meglioe88a9a42011-02-24 19:56:18 -0800144 return mCache.valueAt(index)->value;
145}
146
147template<typename K, typename V>
Jeff Brownb4293fe2011-11-11 15:40:13 -0800148const V& GenerationCache<K, V>::get(const K& key) {
Fabrice Di Meglioe88a9a42011-02-24 19:56:18 -0800149 ssize_t index = mCache.indexOfKey(key);
150 if (index >= 0) {
Jeff Brownb4293fe2011-11-11 15:40:13 -0800151 const sp<Entry<K, V> >& entry = mCache.valueAt(index);
152 detachFromCache(entry);
153 attachToCache(entry);
154 return entry->value;
Fabrice Di Meglioe88a9a42011-02-24 19:56:18 -0800155 }
156
157 return NULL;
158}
159
160template<typename K, typename V>
Jeff Brownb4293fe2011-11-11 15:40:13 -0800161bool GenerationCache<K, V>::put(const K& key, const V& value) {
Fabrice Di Meglioe88a9a42011-02-24 19:56:18 -0800162 if (mMaxCapacity != kUnlimitedCapacity && mCache.size() >= mMaxCapacity) {
163 removeOldest();
164 }
165
166 ssize_t index = mCache.indexOfKey(key);
167 if (index < 0) {
Jeff Brownb4293fe2011-11-11 15:40:13 -0800168 sp<Entry<K, V> > entry = new Entry<K, V>(key, value);
169 mCache.add(key, entry);
170 attachToCache(entry);
Fabrice Di Meglioe88a9a42011-02-24 19:56:18 -0800171 return true;
172 }
173
174 return false;
175}
176
177template<typename K, typename V>
Jeff Brownb4293fe2011-11-11 15:40:13 -0800178bool GenerationCache<K, V>::remove(const K& key) {
Fabrice Di Meglioe88a9a42011-02-24 19:56:18 -0800179 ssize_t index = mCache.indexOfKey(key);
180 if (index >= 0) {
Jeff Brownb4293fe2011-11-11 15:40:13 -0800181 removeAt(index);
182 return true;
Fabrice Di Meglioe88a9a42011-02-24 19:56:18 -0800183 }
184
Jeff Brownb4293fe2011-11-11 15:40:13 -0800185 return false;
Fabrice Di Meglioe88a9a42011-02-24 19:56:18 -0800186}
187
188template<typename K, typename V>
Jeff Brownb4293fe2011-11-11 15:40:13 -0800189void GenerationCache<K, V>::removeAt(ssize_t index) {
Fabrice Di Meglioe88a9a42011-02-24 19:56:18 -0800190 sp<Entry<K, V> > entry = mCache.valueAt(index);
191 if (mListener) {
192 (*mListener)(entry->key, entry->value);
193 }
194 mCache.removeItemsAt(index, 1);
195 detachFromCache(entry);
Fabrice Di Meglioe88a9a42011-02-24 19:56:18 -0800196}
197
198template<typename K, typename V>
Jeff Brownb4293fe2011-11-11 15:40:13 -0800199bool GenerationCache<K, V>::removeOldest() {
Fabrice Di Meglioe88a9a42011-02-24 19:56:18 -0800200 if (mOldest.get()) {
201 ssize_t index = mCache.indexOfKey(mOldest->key);
202 if (index >= 0) {
Jeff Brownb4293fe2011-11-11 15:40:13 -0800203 removeAt(index);
204 return true;
Fabrice Di Meglioe88a9a42011-02-24 19:56:18 -0800205 }
Jeff Brownb4293fe2011-11-11 15:40:13 -0800206 LOGE("GenerationCache: removeOldest failed to find the item in the cache "
207 "with the given key, but we know it must be in there. "
208 "Is the key comparator kaput?");
Fabrice Di Meglioe88a9a42011-02-24 19:56:18 -0800209 }
210
Jeff Brownb4293fe2011-11-11 15:40:13 -0800211 return false;
Fabrice Di Meglioe88a9a42011-02-24 19:56:18 -0800212}
213
214template<typename K, typename V>
Jeff Brownb4293fe2011-11-11 15:40:13 -0800215void GenerationCache<K, V>::attachToCache(const sp<Entry<K, V> >& entry) {
Fabrice Di Meglioe88a9a42011-02-24 19:56:18 -0800216 if (!mYoungest.get()) {
217 mYoungest = mOldest = entry;
218 } else {
219 entry->parent = mYoungest;
220 mYoungest->child = entry;
221 mYoungest = entry;
222 }
223}
224
225template<typename K, typename V>
Jeff Brownb4293fe2011-11-11 15:40:13 -0800226void GenerationCache<K, V>::detachFromCache(const sp<Entry<K, V> >& entry) {
Fabrice Di Meglioe88a9a42011-02-24 19:56:18 -0800227 if (entry->parent.get()) {
228 entry->parent->child = entry->child;
Jeff Brownb4293fe2011-11-11 15:40:13 -0800229 } else {
230 mOldest = entry->child;
Fabrice Di Meglioe88a9a42011-02-24 19:56:18 -0800231 }
232
233 if (entry->child.get()) {
234 entry->child->parent = entry->parent;
Jeff Brownb4293fe2011-11-11 15:40:13 -0800235 } else {
Fabrice Di Meglioe88a9a42011-02-24 19:56:18 -0800236 mYoungest = entry->parent;
237 }
238
239 entry->parent.clear();
240 entry->child.clear();
241}
242
243}; // namespace android
244
245#endif // ANDROID_UTILS_GENERATION_CACHE_H