blob: 42e6d9bb8cda35c3afd10564cd24fc0a6293207d [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_HWUI_GENERATION_CACHE_H
18#define ANDROID_HWUI_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() { };
30 virtual void operator()(EntryKey& key, EntryValue& value) = 0;
31}; // class OnEntryRemoved
32
33template<typename EntryKey, typename EntryValue>
34struct Entry: public LightRefBase<Entry<EntryKey, EntryValue> > {
35 Entry() { }
36 Entry(const Entry<EntryKey, EntryValue>& e):
37 key(e.key), value(e.value), parent(e.parent), child(e.child) { }
38 Entry(sp<Entry<EntryKey, EntryValue> > e):
39 key(e->key), value(e->value), parent(e->parent), child(e->child) { }
40
41 EntryKey key;
42 EntryValue value;
43
44 sp<Entry<EntryKey, EntryValue> > parent;
45 sp<Entry<EntryKey, EntryValue> > child;
46}; // struct Entry
47
48template<typename K, typename V>
49class GenerationCache {
50public:
51 GenerationCache(uint32_t maxCapacity);
52 virtual ~GenerationCache();
53
54 enum Capacity {
55 kUnlimitedCapacity,
56 };
57
58 void setOnEntryRemovedListener(OnEntryRemoved<K, V>* listener);
59
60 void clear();
61
62 bool contains(K key) const;
63 V get(K key);
64 K getKeyAt(uint32_t index) const;
65 bool put(K key, V value);
66 V remove(K key);
67 V removeOldest();
68 V getValueAt(uint32_t index) const;
69
70 uint32_t size() const;
71
72 void addToCache(sp<Entry<K, V> > entry, K key, V value);
73 void attachToCache(sp<Entry<K, V> > entry);
74 void detachFromCache(sp<Entry<K, V> > entry);
75
76 V removeAt(ssize_t index);
77
78 KeyedVector<K, sp<Entry<K, V> > > mCache;
79 uint32_t mMaxCapacity;
80
81 OnEntryRemoved<K, V>* mListener;
82
83 sp<Entry<K, V> > mOldest;
84 sp<Entry<K, V> > mYoungest;
85}; // class GenerationCache
86
87template<typename K, typename V>
88GenerationCache<K, V>::GenerationCache(uint32_t maxCapacity): mMaxCapacity(maxCapacity), mListener(NULL) {
89};
90
91template<typename K, typename V>
92GenerationCache<K, V>::~GenerationCache() {
93 clear();
94};
95
96template<typename K, typename V>
97uint32_t GenerationCache<K, V>::size() const {
98 return mCache.size();
99}
100
101template<typename K, typename V>
102void GenerationCache<K, V>::setOnEntryRemovedListener(OnEntryRemoved<K, V>* listener) {
103 mListener = listener;
104}
105
106template<typename K, typename V>
107void GenerationCache<K, V>::clear() {
108 if (mListener) {
109 for (uint32_t i = 0; i < mCache.size(); i++) {
110 sp<Entry<K, V> > entry = mCache.valueAt(i);
111 if (mListener) {
112 (*mListener)(entry->key, entry->value);
113 }
114 }
115 }
116 mCache.clear();
117 mYoungest.clear();
118 mOldest.clear();
119}
120
121template<typename K, typename V>
122bool GenerationCache<K, V>::contains(K key) const {
123 return mCache.indexOfKey(key) >= 0;
124}
125
126template<typename K, typename V>
127K GenerationCache<K, V>::getKeyAt(uint32_t index) const {
128 return mCache.keyAt(index);
129}
130
131template<typename K, typename V>
132V GenerationCache<K, V>::getValueAt(uint32_t index) const {
133 return mCache.valueAt(index)->value;
134}
135
136template<typename K, typename V>
137V GenerationCache<K, V>::get(K key) {
138 ssize_t index = mCache.indexOfKey(key);
139 if (index >= 0) {
140 sp<Entry<K, V> > entry = mCache.valueAt(index);
141 if (entry.get()) {
142 detachFromCache(entry);
143 attachToCache(entry);
144 return entry->value;
145 }
146 }
147
148 return NULL;
149}
150
151template<typename K, typename V>
152bool GenerationCache<K, V>::put(K key, V value) {
153 if (mMaxCapacity != kUnlimitedCapacity && mCache.size() >= mMaxCapacity) {
154 removeOldest();
155 }
156
157 ssize_t index = mCache.indexOfKey(key);
158 if (index < 0) {
159 sp<Entry<K, V> > entry = new Entry<K, V>;
160 addToCache(entry, key, value);
161 return true;
162 }
163
164 return false;
165}
166
167template<typename K, typename V>
168void GenerationCache<K, V>::addToCache(sp<Entry<K, V> > entry, K key, V value) {
169 entry->key = key;
170 entry->value = value;
171 mCache.add(key, entry);
172 attachToCache(entry);
173}
174
175template<typename K, typename V>
176V GenerationCache<K, V>::remove(K key) {
177 ssize_t index = mCache.indexOfKey(key);
178 if (index >= 0) {
179 return removeAt(index);
180 }
181
182 return NULL;
183}
184
185template<typename K, typename V>
186V GenerationCache<K, V>::removeAt(ssize_t index) {
187 sp<Entry<K, V> > entry = mCache.valueAt(index);
188 if (mListener) {
189 (*mListener)(entry->key, entry->value);
190 }
191 mCache.removeItemsAt(index, 1);
192 detachFromCache(entry);
193
194 return entry->value;
195}
196
197template<typename K, typename V>
198V GenerationCache<K, V>::removeOldest() {
199 if (mOldest.get()) {
200 ssize_t index = mCache.indexOfKey(mOldest->key);
201 if (index >= 0) {
202 return removeAt(index);
203 }
204 }
205
206 return NULL;
207}
208
209template<typename K, typename V>
210void GenerationCache<K, V>::attachToCache(sp<Entry<K, V> > entry) {
211 if (!mYoungest.get()) {
212 mYoungest = mOldest = entry;
213 } else {
214 entry->parent = mYoungest;
215 mYoungest->child = entry;
216 mYoungest = entry;
217 }
218}
219
220template<typename K, typename V>
221void GenerationCache<K, V>::detachFromCache(sp<Entry<K, V> > entry) {
222 if (entry->parent.get()) {
223 entry->parent->child = entry->child;
224 }
225
226 if (entry->child.get()) {
227 entry->child->parent = entry->parent;
228 }
229
230 if (mOldest == entry) {
231 mOldest = entry->child;
232 }
233
234 if (mYoungest == entry) {
235 mYoungest = entry->parent;
236 }
237
238 entry->parent.clear();
239 entry->child.clear();
240}
241
242}; // namespace uirenderer
243}; // namespace android
244
245#endif // ANDROID_HWUI_GENERATION_CACHE_H