blob: bb9ddd67781f729dd88f049d75f59fb6a980696b [file] [log] [blame]
Romain Guyce0537b2010-06-29 21:05:21 -07001/*
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
Fabrice Di Megliod313c662011-02-24 19:56:18 -080017#ifndef ANDROID_UTILS_GENERATION_CACHE_H
18#define ANDROID_UTILS_GENERATION_CACHE_H
Romain Guyce0537b2010-06-29 21:05:21 -070019
20#include <utils/KeyedVector.h>
21#include <utils/RefBase.h>
22
23namespace android {
Romain Guyce0537b2010-06-29 21:05:21 -070024
Fabrice Di Megliod313c662011-02-24 19:56:18 -080025/**
26 * GenerationCache callback used when an item is removed
27 */
Romain Guyce0537b2010-06-29 21:05:21 -070028template<typename EntryKey, typename EntryValue>
29class OnEntryRemoved {
30public:
31 virtual ~OnEntryRemoved() { };
Romain Guydda57022010-07-06 11:39:32 -070032 virtual void operator()(EntryKey& key, EntryValue& value) = 0;
Romain Guyce0537b2010-06-29 21:05:21 -070033}; // class OnEntryRemoved
34
Romain Guy5f0c6a42010-07-07 13:06:26 -070035template<typename EntryKey, typename EntryValue>
36struct Entry: public LightRefBase<Entry<EntryKey, EntryValue> > {
37 Entry() { }
38 Entry(const Entry<EntryKey, EntryValue>& e):
Romain Guyae5575b2010-07-29 18:48:04 -070039 key(e.key), value(e.value), parent(e.parent), child(e.child) { }
Romain Guy5f0c6a42010-07-07 13:06:26 -070040 Entry(sp<Entry<EntryKey, EntryValue> > e):
Romain Guyae5575b2010-07-29 18:48:04 -070041 key(e->key), value(e->value), parent(e->parent), child(e->child) { }
Romain Guy5f0c6a42010-07-07 13:06:26 -070042
43 EntryKey key;
44 EntryValue value;
Romain Guy5f0c6a42010-07-07 13:06:26 -070045
46 sp<Entry<EntryKey, EntryValue> > parent;
47 sp<Entry<EntryKey, EntryValue> > child;
48}; // struct Entry
49
Fabrice Di Megliod313c662011-02-24 19:56:18 -080050/**
51 * A LRU type cache
52 */
Romain Guyce0537b2010-06-29 21:05:21 -070053template<typename K, typename V>
54class GenerationCache {
55public:
Romain Guy5f0c6a42010-07-07 13:06:26 -070056 GenerationCache(uint32_t maxCapacity);
57 virtual ~GenerationCache();
Romain Guyce0537b2010-06-29 21:05:21 -070058
Romain Guy121e2242010-07-01 18:26:52 -070059 enum Capacity {
60 kUnlimitedCapacity,
61 };
62
Romain Guydda57022010-07-06 11:39:32 -070063 void setOnEntryRemovedListener(OnEntryRemoved<K, V>* listener);
Romain Guyce0537b2010-06-29 21:05:21 -070064
65 void clear();
66
Romain Guydda57022010-07-06 11:39:32 -070067 bool contains(K key) const;
68 V get(K key);
Romain Guya2341a92010-09-08 18:04:33 -070069 K getKeyAt(uint32_t index) const;
Romain Guy8550c4c2010-10-08 15:49:53 -070070 bool put(K key, V value);
Romain Guydda57022010-07-06 11:39:32 -070071 V remove(K key);
72 V removeOldest();
Romain Guyeb993562010-10-05 18:14:38 -070073 V getValueAt(uint32_t index) const;
Romain Guyce0537b2010-06-29 21:05:21 -070074
Romain Guy7d139ba2010-07-02 11:20:34 -070075 uint32_t size() const;
Romain Guyce0537b2010-06-29 21:05:21 -070076
Romain Guydda57022010-07-06 11:39:32 -070077 void addToCache(sp<Entry<K, V> > entry, K key, V value);
78 void attachToCache(sp<Entry<K, V> > entry);
79 void detachFromCache(sp<Entry<K, V> > entry);
Romain Guyce0537b2010-06-29 21:05:21 -070080
Romain Guy5f0c6a42010-07-07 13:06:26 -070081 V removeAt(ssize_t index);
82
Fabrice Di Megliod313c662011-02-24 19:56:18 -080083private:
Romain Guy6c818932010-07-07 15:15:32 -070084 KeyedVector<K, sp<Entry<K, V> > > mCache;
Romain Guy7d139ba2010-07-02 11:20:34 -070085 uint32_t mMaxCapacity;
Romain Guyce0537b2010-06-29 21:05:21 -070086
Romain Guydda57022010-07-06 11:39:32 -070087 OnEntryRemoved<K, V>* mListener;
Romain Guyce0537b2010-06-29 21:05:21 -070088
Romain Guydda57022010-07-06 11:39:32 -070089 sp<Entry<K, V> > mOldest;
Romain Guy5f0c6a42010-07-07 13:06:26 -070090 sp<Entry<K, V> > mYoungest;
Romain Guyce0537b2010-06-29 21:05:21 -070091}; // class GenerationCache
92
93template<typename K, typename V>
Fabrice Di Megliod313c662011-02-24 19:56:18 -080094GenerationCache<K, V>::GenerationCache(uint32_t maxCapacity): mMaxCapacity(maxCapacity),
95 mListener(NULL) {
Romain Guy5f0c6a42010-07-07 13:06:26 -070096};
97
98template<typename K, typename V>
99GenerationCache<K, V>::~GenerationCache() {
100 clear();
Romain Guy5f0c6a42010-07-07 13:06:26 -0700101};
102
103template<typename K, typename V>
Romain Guy7d139ba2010-07-02 11:20:34 -0700104uint32_t GenerationCache<K, V>::size() const {
Romain Guy6c818932010-07-07 15:15:32 -0700105 return mCache.size();
Romain Guyce0537b2010-06-29 21:05:21 -0700106}
107
Fabrice Di Megliod313c662011-02-24 19:56:18 -0800108/**
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 */
Romain Guyce0537b2010-06-29 21:05:21 -0700112template<typename K, typename V>
Romain Guydda57022010-07-06 11:39:32 -0700113void GenerationCache<K, V>::setOnEntryRemovedListener(OnEntryRemoved<K, V>* listener) {
Romain Guyce0537b2010-06-29 21:05:21 -0700114 mListener = listener;
115}
116
117template<typename K, typename V>
118void GenerationCache<K, V>::clear() {
119 if (mListener) {
Romain Guyfb8b7632010-08-23 21:05:08 -0700120 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 }
Romain Guyce0537b2010-06-29 21:05:21 -0700125 }
Romain Guyce0537b2010-06-29 21:05:21 -0700126 }
Romain Guyfb8b7632010-08-23 21:05:08 -0700127 mCache.clear();
Romain Guy5f0c6a42010-07-07 13:06:26 -0700128 mYoungest.clear();
Romain Guyce0537b2010-06-29 21:05:21 -0700129 mOldest.clear();
130}
131
132template<typename K, typename V>
Romain Guydda57022010-07-06 11:39:32 -0700133bool GenerationCache<K, V>::contains(K key) const {
Romain Guy6c818932010-07-07 15:15:32 -0700134 return mCache.indexOfKey(key) >= 0;
Romain Guyce0537b2010-06-29 21:05:21 -0700135}
136
137template<typename K, typename V>
Romain Guya2341a92010-09-08 18:04:33 -0700138K GenerationCache<K, V>::getKeyAt(uint32_t index) const {
139 return mCache.keyAt(index);
140}
141
142template<typename K, typename V>
Romain Guyeb993562010-10-05 18:14:38 -0700143V GenerationCache<K, V>::getValueAt(uint32_t index) const {
Romain Guyfe48f652010-11-11 15:36:56 -0800144 return mCache.valueAt(index)->value;
Romain Guyeb993562010-10-05 18:14:38 -0700145}
146
147template<typename K, typename V>
Romain Guydda57022010-07-06 11:39:32 -0700148V GenerationCache<K, V>::get(K key) {
Romain Guy6c818932010-07-07 15:15:32 -0700149 ssize_t index = mCache.indexOfKey(key);
Romain Guyce0537b2010-06-29 21:05:21 -0700150 if (index >= 0) {
Romain Guy6c818932010-07-07 15:15:32 -0700151 sp<Entry<K, V> > entry = mCache.valueAt(index);
Romain Guyce0537b2010-06-29 21:05:21 -0700152 if (entry.get()) {
153 detachFromCache(entry);
154 attachToCache(entry);
155 return entry->value;
156 }
157 }
158
159 return NULL;
160}
161
162template<typename K, typename V>
Romain Guy8550c4c2010-10-08 15:49:53 -0700163bool GenerationCache<K, V>::put(K key, V value) {
Romain Guy6c818932010-07-07 15:15:32 -0700164 if (mMaxCapacity != kUnlimitedCapacity && mCache.size() >= mMaxCapacity) {
Romain Guyce0537b2010-06-29 21:05:21 -0700165 removeOldest();
166 }
167
Romain Guy6c818932010-07-07 15:15:32 -0700168 ssize_t index = mCache.indexOfKey(key);
Romain Guy9aaa8262010-09-08 15:15:43 -0700169 if (index < 0) {
Romain Guydda57022010-07-06 11:39:32 -0700170 sp<Entry<K, V> > entry = new Entry<K, V>;
Romain Guyce0537b2010-06-29 21:05:21 -0700171 addToCache(entry, key, value);
Romain Guy8550c4c2010-10-08 15:49:53 -0700172 return true;
Romain Guyce0537b2010-06-29 21:05:21 -0700173 }
Romain Guy8550c4c2010-10-08 15:49:53 -0700174
175 return false;
Romain Guyce0537b2010-06-29 21:05:21 -0700176}
177
178template<typename K, typename V>
Romain Guydda57022010-07-06 11:39:32 -0700179void GenerationCache<K, V>::addToCache(sp<Entry<K, V> > entry, K key, V value) {
Romain Guyce0537b2010-06-29 21:05:21 -0700180 entry->key = key;
181 entry->value = value;
Romain Guyae5575b2010-07-29 18:48:04 -0700182 mCache.add(key, entry);
Romain Guyce0537b2010-06-29 21:05:21 -0700183 attachToCache(entry);
184}
185
186template<typename K, typename V>
Romain Guydda57022010-07-06 11:39:32 -0700187V GenerationCache<K, V>::remove(K key) {
Romain Guy6c818932010-07-07 15:15:32 -0700188 ssize_t index = mCache.indexOfKey(key);
Romain Guyce0537b2010-06-29 21:05:21 -0700189 if (index >= 0) {
Romain Guy5f0c6a42010-07-07 13:06:26 -0700190 return removeAt(index);
Romain Guyce0537b2010-06-29 21:05:21 -0700191 }
192
193 return NULL;
194}
195
196template<typename K, typename V>
Romain Guy5f0c6a42010-07-07 13:06:26 -0700197V GenerationCache<K, V>::removeAt(ssize_t index) {
Romain Guy6c818932010-07-07 15:15:32 -0700198 sp<Entry<K, V> > entry = mCache.valueAt(index);
Romain Guy5f0c6a42010-07-07 13:06:26 -0700199 if (mListener) {
200 (*mListener)(entry->key, entry->value);
201 }
Romain Guy6c818932010-07-07 15:15:32 -0700202 mCache.removeItemsAt(index, 1);
Romain Guy5f0c6a42010-07-07 13:06:26 -0700203 detachFromCache(entry);
204
205 return entry->value;
206}
207
208template<typename K, typename V>
Romain Guydda57022010-07-06 11:39:32 -0700209V GenerationCache<K, V>::removeOldest() {
Romain Guyce0537b2010-06-29 21:05:21 -0700210 if (mOldest.get()) {
Romain Guyae5575b2010-07-29 18:48:04 -0700211 ssize_t index = mCache.indexOfKey(mOldest->key);
212 if (index >= 0) {
213 return removeAt(index);
214 }
Romain Guyce0537b2010-06-29 21:05:21 -0700215 }
Romain Guydda57022010-07-06 11:39:32 -0700216
217 return NULL;
Romain Guyce0537b2010-06-29 21:05:21 -0700218}
219
220template<typename K, typename V>
Romain Guydda57022010-07-06 11:39:32 -0700221void GenerationCache<K, V>::attachToCache(sp<Entry<K, V> > entry) {
Romain Guy5f0c6a42010-07-07 13:06:26 -0700222 if (!mYoungest.get()) {
223 mYoungest = mOldest = entry;
Romain Guyce0537b2010-06-29 21:05:21 -0700224 } else {
Romain Guy5f0c6a42010-07-07 13:06:26 -0700225 entry->parent = mYoungest;
226 mYoungest->child = entry;
227 mYoungest = entry;
Romain Guyce0537b2010-06-29 21:05:21 -0700228 }
229}
230
231template<typename K, typename V>
Romain Guydda57022010-07-06 11:39:32 -0700232void GenerationCache<K, V>::detachFromCache(sp<Entry<K, V> > entry) {
Romain Guyce0537b2010-06-29 21:05:21 -0700233 if (entry->parent.get()) {
234 entry->parent->child = entry->child;
235 }
236
237 if (entry->child.get()) {
238 entry->child->parent = entry->parent;
239 }
240
241 if (mOldest == entry) {
242 mOldest = entry->child;
243 }
244
Romain Guy5f0c6a42010-07-07 13:06:26 -0700245 if (mYoungest == entry) {
246 mYoungest = entry->parent;
Romain Guyce0537b2010-06-29 21:05:21 -0700247 }
248
249 entry->parent.clear();
250 entry->child.clear();
251}
252
Romain Guyce0537b2010-06-29 21:05:21 -0700253}; // namespace android
254
Fabrice Di Megliod313c662011-02-24 19:56:18 -0800255#endif // ANDROID_UTILS_GENERATION_CACHE_H