blob: d92a0bb918671e2b72e325620d5521b949e44c54 [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
17#ifndef ANDROID_UI_GENERATION_CACHE_H
18#define ANDROID_UI_GENERATION_CACHE_H
19
20#include <utils/KeyedVector.h>
21#include <utils/RefBase.h>
22
23namespace android {
24namespace uirenderer {
25
26template<typename EntryKey, typename EntryValue>
27class OnEntryRemoved {
28public:
29 virtual ~OnEntryRemoved() { };
Romain Guydda570202010-07-06 11:39:32 -070030 virtual void operator()(EntryKey& key, EntryValue& value) = 0;
Romain Guyce0537b2010-06-29 21:05:21 -070031}; // class OnEntryRemoved
32
33template<typename K, typename V>
34class GenerationCache {
35public:
Romain Guy7d139ba2010-07-02 11:20:34 -070036 GenerationCache(uint32_t maxCapacity): mMaxCapacity(maxCapacity), mListener(NULL) { };
Romain Guyce0537b2010-06-29 21:05:21 -070037 ~GenerationCache() { clear(); };
38
Romain Guy121e22422010-07-01 18:26:52 -070039 enum Capacity {
40 kUnlimitedCapacity,
41 };
42
Romain Guydda570202010-07-06 11:39:32 -070043 void setOnEntryRemovedListener(OnEntryRemoved<K, V>* listener);
Romain Guyce0537b2010-06-29 21:05:21 -070044
45 void clear();
46
Romain Guydda570202010-07-06 11:39:32 -070047 bool contains(K key) const;
48 V get(K key);
49 void put(K key, V value);
50 V remove(K key);
51 V removeOldest();
Romain Guyce0537b2010-06-29 21:05:21 -070052
Romain Guy7d139ba2010-07-02 11:20:34 -070053 uint32_t size() const;
Romain Guyce0537b2010-06-29 21:05:21 -070054
55private:
Romain Guyce0537b2010-06-29 21:05:21 -070056 template<typename EntryKey, typename EntryValue>
57 struct Entry: public LightRefBase<Entry<EntryKey, EntryValue> > {
58 Entry() { }
59 Entry(const Entry<EntryKey, EntryValue>& e):
60 key(e.key), value(e.value), parent(e.parent), child(e.child) { }
61 Entry(sp<Entry<EntryKey, EntryValue> > e):
62 key(e->key), value(e->value), parent(e->parent), child(e->child) { }
63
64 EntryKey key;
65 EntryValue value;
66
67 sp<Entry<EntryKey, EntryValue> > parent;
68 sp<Entry<EntryKey, EntryValue> > child;
69 }; // struct Entry
70
Romain Guydda570202010-07-06 11:39:32 -070071 void addToCache(sp<Entry<K, V> > entry, K key, V value);
72 void attachToCache(sp<Entry<K, V> > entry);
73 void detachFromCache(sp<Entry<K, V> > entry);
Romain Guyce0537b2010-06-29 21:05:21 -070074
Romain Guy7d139ba2010-07-02 11:20:34 -070075 uint32_t mMaxCapacity;
Romain Guyce0537b2010-06-29 21:05:21 -070076
Romain Guydda570202010-07-06 11:39:32 -070077 OnEntryRemoved<K, V>* mListener;
Romain Guyce0537b2010-06-29 21:05:21 -070078
Romain Guydda570202010-07-06 11:39:32 -070079 KeyedVector<K, sp<Entry<K, V> > > mCache;
Romain Guyce0537b2010-06-29 21:05:21 -070080
Romain Guydda570202010-07-06 11:39:32 -070081 sp<Entry<K, V> > mOldest;
82 sp<Entry<K, V> > mYougest;
Romain Guyce0537b2010-06-29 21:05:21 -070083}; // class GenerationCache
84
85template<typename K, typename V>
Romain Guy7d139ba2010-07-02 11:20:34 -070086uint32_t GenerationCache<K, V>::size() const {
Romain Guyce0537b2010-06-29 21:05:21 -070087 return mCache.size();
88}
89
90template<typename K, typename V>
Romain Guydda570202010-07-06 11:39:32 -070091void GenerationCache<K, V>::setOnEntryRemovedListener(OnEntryRemoved<K, V>* listener) {
Romain Guyce0537b2010-06-29 21:05:21 -070092 mListener = listener;
93}
94
95template<typename K, typename V>
96void GenerationCache<K, V>::clear() {
97 if (mListener) {
98 while (mCache.size() > 0) {
99 removeOldest();
100 }
101 } else {
102 mCache.clear();
103 }
104 mYougest.clear();
105 mOldest.clear();
106}
107
108template<typename K, typename V>
Romain Guydda570202010-07-06 11:39:32 -0700109bool GenerationCache<K, V>::contains(K key) const {
Romain Guyce0537b2010-06-29 21:05:21 -0700110 return mCache.indexOfKey(key) >= 0;
111}
112
113template<typename K, typename V>
Romain Guydda570202010-07-06 11:39:32 -0700114V GenerationCache<K, V>::get(K key) {
Romain Guyce0537b2010-06-29 21:05:21 -0700115 ssize_t index = mCache.indexOfKey(key);
116 if (index >= 0) {
Romain Guydda570202010-07-06 11:39:32 -0700117 sp<Entry<K, V> > entry = mCache.valueAt(index);
Romain Guyce0537b2010-06-29 21:05:21 -0700118 if (entry.get()) {
119 detachFromCache(entry);
120 attachToCache(entry);
121 return entry->value;
122 }
123 }
124
125 return NULL;
126}
127
128template<typename K, typename V>
Romain Guydda570202010-07-06 11:39:32 -0700129void GenerationCache<K, V>::put(K key, V value) {
Romain Guy121e22422010-07-01 18:26:52 -0700130 if (mMaxCapacity != kUnlimitedCapacity && mCache.size() >= mMaxCapacity) {
Romain Guyce0537b2010-06-29 21:05:21 -0700131 removeOldest();
132 }
133
134 ssize_t index = mCache.indexOfKey(key);
135 if (index >= 0) {
Romain Guydda570202010-07-06 11:39:32 -0700136 sp<Entry<K, V> > entry = mCache.valueAt(index);
Romain Guyce0537b2010-06-29 21:05:21 -0700137 detachFromCache(entry);
138 addToCache(entry, key, value);
139 } else {
Romain Guydda570202010-07-06 11:39:32 -0700140 sp<Entry<K, V> > entry = new Entry<K, V>;
Romain Guyce0537b2010-06-29 21:05:21 -0700141 addToCache(entry, key, value);
142 }
143}
144
145template<typename K, typename V>
Romain Guydda570202010-07-06 11:39:32 -0700146void GenerationCache<K, V>::addToCache(sp<Entry<K, V> > entry, K key, V value) {
Romain Guyce0537b2010-06-29 21:05:21 -0700147 entry->key = key;
148 entry->value = value;
149 mCache.add(key, entry);
150 attachToCache(entry);
151}
152
153template<typename K, typename V>
Romain Guydda570202010-07-06 11:39:32 -0700154V GenerationCache<K, V>::remove(K key) {
Romain Guyce0537b2010-06-29 21:05:21 -0700155 ssize_t index = mCache.indexOfKey(key);
156 if (index >= 0) {
Romain Guydda570202010-07-06 11:39:32 -0700157 sp<Entry<K, V> > entry = mCache.valueAt(index);
Romain Guyce0537b2010-06-29 21:05:21 -0700158 if (mListener) {
159 (*mListener)(entry->key, entry->value);
160 }
161 mCache.removeItemsAt(index, 1);
162 detachFromCache(entry);
Romain Guydda570202010-07-06 11:39:32 -0700163
164 return entry->value;
Romain Guyce0537b2010-06-29 21:05:21 -0700165 }
166
167 return NULL;
168}
169
170template<typename K, typename V>
Romain Guydda570202010-07-06 11:39:32 -0700171V GenerationCache<K, V>::removeOldest() {
Romain Guyce0537b2010-06-29 21:05:21 -0700172 if (mOldest.get()) {
Romain Guydda570202010-07-06 11:39:32 -0700173 return remove(mOldest->key);
Romain Guyce0537b2010-06-29 21:05:21 -0700174 }
Romain Guydda570202010-07-06 11:39:32 -0700175
176 return NULL;
Romain Guyce0537b2010-06-29 21:05:21 -0700177}
178
179template<typename K, typename V>
Romain Guydda570202010-07-06 11:39:32 -0700180void GenerationCache<K, V>::attachToCache(sp<Entry<K, V> > entry) {
Romain Guyce0537b2010-06-29 21:05:21 -0700181 if (!mYougest.get()) {
182 mYougest = mOldest = entry;
183 } else {
184 entry->parent = mYougest;
185 mYougest->child = entry;
186 mYougest = entry;
187 }
188}
189
190template<typename K, typename V>
Romain Guydda570202010-07-06 11:39:32 -0700191void GenerationCache<K, V>::detachFromCache(sp<Entry<K, V> > entry) {
Romain Guyce0537b2010-06-29 21:05:21 -0700192 if (entry->parent.get()) {
193 entry->parent->child = entry->child;
194 }
195
196 if (entry->child.get()) {
197 entry->child->parent = entry->parent;
198 }
199
200 if (mOldest == entry) {
201 mOldest = entry->child;
202 }
203
204 if (mYougest == entry) {
205 mYougest = entry->parent;
206 }
207
208 entry->parent.clear();
209 entry->child.clear();
210}
211
212}; // namespace uirenderer
213}; // namespace android
214
215#endif // ANDROID_UI_GENERATION_CACHE_H