1 /* 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 23 namespace android { 24 25 /** 26 * GenerationCache callback used when an item is removed 27 */ 28 template<typename EntryKey, typename EntryValue> 29 class OnEntryRemoved { 30 public: 31 virtual ~OnEntryRemoved() { }; 32 virtual void operator()(EntryKey& key, EntryValue& value) = 0; 33 }; // class OnEntryRemoved 34 35 template<typename EntryKey, typename EntryValue> 36 struct Entry: public LightRefBase<Entry<EntryKey, EntryValue> > { 37 Entry() { } 38 Entry(const Entry<EntryKey, EntryValue>& e): 39 key(e.key), value(e.value), parent(e.parent), child(e.child) { } 40 Entry(sp<Entry<EntryKey, EntryValue> > e): 41 key(e->key), value(e->value), parent(e->parent), child(e->child) { } 42 43 EntryKey key; 44 EntryValue value; 45 46 sp<Entry<EntryKey, EntryValue> > parent; 47 sp<Entry<EntryKey, EntryValue> > child; 48 }; // struct Entry 49 50 /** 51 * A LRU type cache 52 */ 53 template<typename K, typename V> 54 class GenerationCache { 55 public: 56 GenerationCache(uint32_t maxCapacity); 57 virtual ~GenerationCache(); 58 59 enum Capacity { 60 kUnlimitedCapacity, 61 }; 62 63 void setOnEntryRemovedListener(OnEntryRemoved<K, V>* listener); 64 65 void clear(); 66 67 bool contains(K key) const; 68 V get(K key); 69 K getKeyAt(uint32_t index) const; 70 bool put(K key, V value); 71 V remove(K key); 72 V removeOldest(); 73 V getValueAt(uint32_t index) const; 74 75 uint32_t size() const; 76 77 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); 80 81 V removeAt(ssize_t index); 82 83 private: 84 KeyedVector<K, sp<Entry<K, V> > > mCache; 85 uint32_t mMaxCapacity; 86 87 OnEntryRemoved<K, V>* mListener; 88 89 sp<Entry<K, V> > mOldest; 90 sp<Entry<K, V> > mYoungest; 91 }; // class GenerationCache 92 93 template<typename K, typename V> 94 GenerationCache<K, V>::GenerationCache(uint32_t maxCapacity): mMaxCapacity(maxCapacity), 95 mListener(NULL) { 96 }; 97 98 template<typename K, typename V> 99 GenerationCache<K, V>::~GenerationCache() { 100 clear(); 101 }; 102 103 template<typename K, typename V> 104 uint32_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 */ 112 template<typename K, typename V> 113 void GenerationCache<K, V>::setOnEntryRemovedListener(OnEntryRemoved<K, V>* listener) { 114 mListener = listener; 115 } 116 117 template<typename K, typename V> 118 void 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 132 template<typename K, typename V> 133 bool GenerationCache<K, V>::contains(K key) const { 134 return mCache.indexOfKey(key) >= 0; 135 } 136 137 template<typename K, typename V> 138 K GenerationCache<K, V>::getKeyAt(uint32_t index) const { 139 return mCache.keyAt(index); 140 } 141 142 template<typename K, typename V> 143 V GenerationCache<K, V>::getValueAt(uint32_t index) const { 144 return mCache.valueAt(index)->value; 145 } 146 147 template<typename K, typename V> 148 V GenerationCache<K, V>::get(K key) { 149 ssize_t index = mCache.indexOfKey(key); 150 if (index >= 0) { 151 sp<Entry<K, V> > entry = mCache.valueAt(index); 152 if (entry.get()) { 153 detachFromCache(entry); 154 attachToCache(entry); 155 return entry->value; 156 } 157 } 158 159 return NULL; 160 } 161 162 template<typename K, typename V> 163 bool GenerationCache<K, V>::put(K key, V value) { 164 if (mMaxCapacity != kUnlimitedCapacity && mCache.size() >= mMaxCapacity) { 165 removeOldest(); 166 } 167 168 ssize_t index = mCache.indexOfKey(key); 169 if (index < 0) { 170 sp<Entry<K, V> > entry = new Entry<K, V>; 171 addToCache(entry, key, value); 172 return true; 173 } 174 175 return false; 176 } 177 178 template<typename K, typename V> 179 void GenerationCache<K, V>::addToCache(sp<Entry<K, V> > entry, K key, V value) { 180 entry->key = key; 181 entry->value = value; 182 mCache.add(key, entry); 183 attachToCache(entry); 184 } 185 186 template<typename K, typename V> 187 V GenerationCache<K, V>::remove(K key) { 188 ssize_t index = mCache.indexOfKey(key); 189 if (index >= 0) { 190 return removeAt(index); 191 } 192 193 return NULL; 194 } 195 196 template<typename K, typename V> 197 V GenerationCache<K, V>::removeAt(ssize_t index) { 198 sp<Entry<K, V> > entry = mCache.valueAt(index); 199 if (mListener) { 200 (*mListener)(entry->key, entry->value); 201 } 202 mCache.removeItemsAt(index, 1); 203 detachFromCache(entry); 204 205 return entry->value; 206 } 207 208 template<typename K, typename V> 209 V GenerationCache<K, V>::removeOldest() { 210 if (mOldest.get()) { 211 ssize_t index = mCache.indexOfKey(mOldest->key); 212 if (index >= 0) { 213 return removeAt(index); 214 } 215 } 216 217 return NULL; 218 } 219 220 template<typename K, typename V> 221 void GenerationCache<K, V>::attachToCache(sp<Entry<K, V> > entry) { 222 if (!mYoungest.get()) { 223 mYoungest = mOldest = entry; 224 } else { 225 entry->parent = mYoungest; 226 mYoungest->child = entry; 227 mYoungest = entry; 228 } 229 } 230 231 template<typename K, typename V> 232 void GenerationCache<K, V>::detachFromCache(sp<Entry<K, V> > entry) { 233 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 245 if (mYoungest == entry) { 246 mYoungest = entry->parent; 247 } 248 249 entry->parent.clear(); 250 entry->child.clear(); 251 } 252 253 }; // namespace android 254 255 #endif // ANDROID_UTILS_GENERATION_CACHE_H 256