blob: 40722d11e394c5c5529079b97288a7ffabe89f40 [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 Guydda570202010-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> > {
Jeff Brownd9e688c2011-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) { }
Romain Guy5f0c6a42010-07-07 13:06:26 -070042
43 EntryKey key;
44 EntryValue value;
Romain Guy5f0c6a42010-07-07 13:06:26 -070045
Jeff Brownd9e688c2011-11-11 15:40:13 -080046 sp<Entry<EntryKey, EntryValue> > parent; // next older entry
47 sp<Entry<EntryKey, EntryValue> > child; // next younger entry
Romain Guy5f0c6a42010-07-07 13:06:26 -070048}; // 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 Guy121e22422010-07-01 18:26:52 -070059 enum Capacity {
60 kUnlimitedCapacity,
61 };
62
Romain Guydda570202010-07-06 11:39:32 -070063 void setOnEntryRemovedListener(OnEntryRemoved<K, V>* listener);
Romain Guyce0537b2010-06-29 21:05:21 -070064
Jeff Brownd9e688c2011-11-11 15:40:13 -080065 size_t size() const;
66
Romain Guyce0537b2010-06-29 21:05:21 -070067 void clear();
68
Jeff Brownd9e688c2011-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;
Romain Guyce0537b2010-06-29 21:05:21 -070072
Jeff Brownd9e688c2011-11-11 15:40:13 -080073 const V& get(const K& key);
74 bool put(const K& key, const V& value);
Romain Guyce0537b2010-06-29 21:05:21 -070075
Jeff Brownd9e688c2011-11-11 15:40:13 -080076 void removeAt(ssize_t index);
77 bool remove(const K& key);
78 bool removeOldest();
Romain Guy5f0c6a42010-07-07 13:06:26 -070079
Fabrice Di Megliod313c662011-02-24 19:56:18 -080080private:
Romain Guy6c818932010-07-07 15:15:32 -070081 KeyedVector<K, sp<Entry<K, V> > > mCache;
Romain Guy7d139ba2010-07-02 11:20:34 -070082 uint32_t mMaxCapacity;
Romain Guyce0537b2010-06-29 21:05:21 -070083
Romain Guydda570202010-07-06 11:39:32 -070084 OnEntryRemoved<K, V>* mListener;
Romain Guyce0537b2010-06-29 21:05:21 -070085
Romain Guydda570202010-07-06 11:39:32 -070086 sp<Entry<K, V> > mOldest;
Romain Guy5f0c6a42010-07-07 13:06:26 -070087 sp<Entry<K, V> > mYoungest;
Jeff Brownd9e688c2011-11-11 15:40:13 -080088
89 void attachToCache(const sp<Entry<K, V> >& entry);
90 void detachFromCache(const sp<Entry<K, V> >& entry);
Romain Guy46b9f7c2011-12-08 18:19:39 -080091
92 const V mNullValue;
Romain Guyce0537b2010-06-29 21:05:21 -070093}; // class GenerationCache
94
95template<typename K, typename V>
Fabrice Di Megliod313c662011-02-24 19:56:18 -080096GenerationCache<K, V>::GenerationCache(uint32_t maxCapacity): mMaxCapacity(maxCapacity),
Romain Guy46b9f7c2011-12-08 18:19:39 -080097 mListener(NULL), mNullValue(NULL) {
Romain Guy5f0c6a42010-07-07 13:06:26 -070098};
99
100template<typename K, typename V>
101GenerationCache<K, V>::~GenerationCache() {
102 clear();
Romain Guy5f0c6a42010-07-07 13:06:26 -0700103};
104
105template<typename K, typename V>
Romain Guy7d139ba2010-07-02 11:20:34 -0700106uint32_t GenerationCache<K, V>::size() const {
Romain Guy6c818932010-07-07 15:15:32 -0700107 return mCache.size();
Romain Guyce0537b2010-06-29 21:05:21 -0700108}
109
Fabrice Di Megliod313c662011-02-24 19:56:18 -0800110/**
111 * Should be set by the user of the Cache so that the callback is called whenever an item is
112 * removed from the cache
113 */
Romain Guyce0537b2010-06-29 21:05:21 -0700114template<typename K, typename V>
Romain Guydda570202010-07-06 11:39:32 -0700115void GenerationCache<K, V>::setOnEntryRemovedListener(OnEntryRemoved<K, V>* listener) {
Romain Guyce0537b2010-06-29 21:05:21 -0700116 mListener = listener;
117}
118
119template<typename K, typename V>
120void GenerationCache<K, V>::clear() {
121 if (mListener) {
Romain Guyfb8b7632010-08-23 21:05:08 -0700122 for (uint32_t i = 0; i < mCache.size(); i++) {
123 sp<Entry<K, V> > entry = mCache.valueAt(i);
124 if (mListener) {
125 (*mListener)(entry->key, entry->value);
126 }
Romain Guyce0537b2010-06-29 21:05:21 -0700127 }
Romain Guyce0537b2010-06-29 21:05:21 -0700128 }
Romain Guyfb8b7632010-08-23 21:05:08 -0700129 mCache.clear();
Romain Guy5f0c6a42010-07-07 13:06:26 -0700130 mYoungest.clear();
Romain Guyce0537b2010-06-29 21:05:21 -0700131 mOldest.clear();
132}
133
134template<typename K, typename V>
Jeff Brownd9e688c2011-11-11 15:40:13 -0800135bool GenerationCache<K, V>::contains(const K& key) const {
Romain Guy6c818932010-07-07 15:15:32 -0700136 return mCache.indexOfKey(key) >= 0;
Romain Guyce0537b2010-06-29 21:05:21 -0700137}
138
139template<typename K, typename V>
Jeff Brownd9e688c2011-11-11 15:40:13 -0800140const K& GenerationCache<K, V>::getKeyAt(size_t index) const {
Romain Guya2341a92010-09-08 18:04:33 -0700141 return mCache.keyAt(index);
142}
143
144template<typename K, typename V>
Jeff Brownd9e688c2011-11-11 15:40:13 -0800145const V& GenerationCache<K, V>::getValueAt(size_t index) const {
Romain Guyfe48f652010-11-11 15:36:56 -0800146 return mCache.valueAt(index)->value;
Romain Guyeb993562010-10-05 18:14:38 -0700147}
148
149template<typename K, typename V>
Jeff Brownd9e688c2011-11-11 15:40:13 -0800150const V& GenerationCache<K, V>::get(const K& key) {
Romain Guy6c818932010-07-07 15:15:32 -0700151 ssize_t index = mCache.indexOfKey(key);
Romain Guyce0537b2010-06-29 21:05:21 -0700152 if (index >= 0) {
Jeff Brownd9e688c2011-11-11 15:40:13 -0800153 const sp<Entry<K, V> >& entry = mCache.valueAt(index);
154 detachFromCache(entry);
155 attachToCache(entry);
156 return entry->value;
Romain Guyce0537b2010-06-29 21:05:21 -0700157 }
158
Romain Guy46b9f7c2011-12-08 18:19:39 -0800159 return mNullValue;
Romain Guyce0537b2010-06-29 21:05:21 -0700160}
161
162template<typename K, typename V>
Jeff Brownd9e688c2011-11-11 15:40:13 -0800163bool GenerationCache<K, V>::put(const K& key, const 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) {
Jeff Brownd9e688c2011-11-11 15:40:13 -0800170 sp<Entry<K, V> > entry = new Entry<K, V>(key, value);
171 mCache.add(key, entry);
172 attachToCache(entry);
Romain Guy8550c4c2010-10-08 15:49:53 -0700173 return true;
Romain Guyce0537b2010-06-29 21:05:21 -0700174 }
Romain Guy8550c4c2010-10-08 15:49:53 -0700175
176 return false;
Romain Guyce0537b2010-06-29 21:05:21 -0700177}
178
179template<typename K, typename V>
Jeff Brownd9e688c2011-11-11 15:40:13 -0800180bool GenerationCache<K, V>::remove(const K& key) {
Romain Guy6c818932010-07-07 15:15:32 -0700181 ssize_t index = mCache.indexOfKey(key);
Romain Guyce0537b2010-06-29 21:05:21 -0700182 if (index >= 0) {
Jeff Brownd9e688c2011-11-11 15:40:13 -0800183 removeAt(index);
184 return true;
Romain Guyce0537b2010-06-29 21:05:21 -0700185 }
186
Jeff Brownd9e688c2011-11-11 15:40:13 -0800187 return false;
Romain Guyce0537b2010-06-29 21:05:21 -0700188}
189
190template<typename K, typename V>
Jeff Brownd9e688c2011-11-11 15:40:13 -0800191void GenerationCache<K, V>::removeAt(ssize_t index) {
Romain Guy6c818932010-07-07 15:15:32 -0700192 sp<Entry<K, V> > entry = mCache.valueAt(index);
Romain Guy5f0c6a42010-07-07 13:06:26 -0700193 if (mListener) {
194 (*mListener)(entry->key, entry->value);
195 }
Romain Guy6c818932010-07-07 15:15:32 -0700196 mCache.removeItemsAt(index, 1);
Romain Guy5f0c6a42010-07-07 13:06:26 -0700197 detachFromCache(entry);
Romain Guy5f0c6a42010-07-07 13:06:26 -0700198}
199
200template<typename K, typename V>
Jeff Brownd9e688c2011-11-11 15:40:13 -0800201bool GenerationCache<K, V>::removeOldest() {
Romain Guyce0537b2010-06-29 21:05:21 -0700202 if (mOldest.get()) {
Romain Guyae5575b2010-07-29 18:48:04 -0700203 ssize_t index = mCache.indexOfKey(mOldest->key);
204 if (index >= 0) {
Jeff Brownd9e688c2011-11-11 15:40:13 -0800205 removeAt(index);
206 return true;
Romain Guyae5575b2010-07-29 18:48:04 -0700207 }
Steve Block3762c312012-01-06 19:20:56 +0000208 ALOGE("GenerationCache: removeOldest failed to find the item in the cache "
Jeff Brownd9e688c2011-11-11 15:40:13 -0800209 "with the given key, but we know it must be in there. "
210 "Is the key comparator kaput?");
Romain Guyce0537b2010-06-29 21:05:21 -0700211 }
Romain Guydda570202010-07-06 11:39:32 -0700212
Jeff Brownd9e688c2011-11-11 15:40:13 -0800213 return false;
Romain Guyce0537b2010-06-29 21:05:21 -0700214}
215
216template<typename K, typename V>
Jeff Brownd9e688c2011-11-11 15:40:13 -0800217void GenerationCache<K, V>::attachToCache(const sp<Entry<K, V> >& entry) {
Romain Guy5f0c6a42010-07-07 13:06:26 -0700218 if (!mYoungest.get()) {
219 mYoungest = mOldest = entry;
Romain Guyce0537b2010-06-29 21:05:21 -0700220 } else {
Romain Guy5f0c6a42010-07-07 13:06:26 -0700221 entry->parent = mYoungest;
222 mYoungest->child = entry;
223 mYoungest = entry;
Romain Guyce0537b2010-06-29 21:05:21 -0700224 }
225}
226
227template<typename K, typename V>
Jeff Brownd9e688c2011-11-11 15:40:13 -0800228void GenerationCache<K, V>::detachFromCache(const sp<Entry<K, V> >& entry) {
Romain Guyce0537b2010-06-29 21:05:21 -0700229 if (entry->parent.get()) {
230 entry->parent->child = entry->child;
Jeff Brownd9e688c2011-11-11 15:40:13 -0800231 } else {
232 mOldest = entry->child;
Romain Guyce0537b2010-06-29 21:05:21 -0700233 }
234
235 if (entry->child.get()) {
236 entry->child->parent = entry->parent;
Jeff Brownd9e688c2011-11-11 15:40:13 -0800237 } else {
Romain Guy5f0c6a42010-07-07 13:06:26 -0700238 mYoungest = entry->parent;
Romain Guyce0537b2010-06-29 21:05:21 -0700239 }
240
241 entry->parent.clear();
242 entry->child.clear();
243}
244
Romain Guyce0537b2010-06-29 21:05:21 -0700245}; // namespace android
246
Fabrice Di Megliod313c662011-02-24 19:56:18 -0800247#endif // ANDROID_UTILS_GENERATION_CACHE_H