blob: 4a3ca77571a5f21b07c6d6f915c4a311feb289e9 [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() { };
30 virtual void operator()(EntryKey key, EntryValue value) = 0;
31}; // class OnEntryRemoved
32
33template<typename K, typename V>
34class GenerationCache {
35public:
36 GenerationCache(unsigned int maxCapacity): mMaxCapacity(maxCapacity), mListener(NULL) { };
37 ~GenerationCache() { clear(); };
38
39 void setOnEntryRemovedListener(OnEntryRemoved<K*, V*>* listener);
40
41 void clear();
42
43 bool contains(K* key) const;
Romain Guy364703c2010-06-30 15:51:03 -070044 V* get(K* key);
Romain Guyce0537b2010-06-29 21:05:21 -070045 void put(K* key, V* value);
Romain Guy364703c2010-06-30 15:51:03 -070046 V* remove(K* key);
Romain Guyce0537b2010-06-29 21:05:21 -070047
48 unsigned int size() const;
49
50private:
51 void removeOldest();
52
53 template<typename EntryKey, typename EntryValue>
54 struct Entry: public LightRefBase<Entry<EntryKey, EntryValue> > {
55 Entry() { }
56 Entry(const Entry<EntryKey, EntryValue>& e):
57 key(e.key), value(e.value), parent(e.parent), child(e.child) { }
58 Entry(sp<Entry<EntryKey, EntryValue> > e):
59 key(e->key), value(e->value), parent(e->parent), child(e->child) { }
60
61 EntryKey key;
62 EntryValue value;
63
64 sp<Entry<EntryKey, EntryValue> > parent;
65 sp<Entry<EntryKey, EntryValue> > child;
66 }; // struct Entry
67
68 void addToCache(sp<Entry<K*, V*> > entry, K* key, V* value);
69 void attachToCache(sp<Entry<K*, V*> > entry);
70 void detachFromCache(sp<Entry<K*, V*> > entry);
71
72 unsigned int mMaxCapacity;
73
74 OnEntryRemoved<K*, V*>* mListener;
75
76 KeyedVector<K*, sp<Entry<K*, V*> > > mCache;
77
78 sp<Entry<K*, V*> > mOldest;
79 sp<Entry<K*, V*> > mYougest;
80}; // class GenerationCache
81
82template<typename K, typename V>
83unsigned int GenerationCache<K, V>::size() const {
84 return mCache.size();
85}
86
87template<typename K, typename V>
88void GenerationCache<K, V>::setOnEntryRemovedListener(OnEntryRemoved<K*, V*>* listener) {
89 mListener = listener;
90}
91
92template<typename K, typename V>
93void GenerationCache<K, V>::clear() {
94 if (mListener) {
95 while (mCache.size() > 0) {
96 removeOldest();
97 }
98 } else {
99 mCache.clear();
100 }
101 mYougest.clear();
102 mOldest.clear();
103}
104
105template<typename K, typename V>
106bool GenerationCache<K, V>::contains(K* key) const {
107 return mCache.indexOfKey(key) >= 0;
108}
109
110template<typename K, typename V>
Romain Guy364703c2010-06-30 15:51:03 -0700111V* GenerationCache<K, V>::get(K* key) {
Romain Guyce0537b2010-06-29 21:05:21 -0700112 ssize_t index = mCache.indexOfKey(key);
113 if (index >= 0) {
114 sp<Entry<K*, V*> > entry = mCache.valueAt(index);
115 if (entry.get()) {
116 detachFromCache(entry);
117 attachToCache(entry);
118 return entry->value;
119 }
120 }
121
122 return NULL;
123}
124
125template<typename K, typename V>
126void GenerationCache<K, V>::put(K* key, V* value) {
127 if (mCache.size() >= mMaxCapacity) {
128 removeOldest();
129 }
130
131 ssize_t index = mCache.indexOfKey(key);
132 if (index >= 0) {
133 sp<Entry<K*, V*> > entry = mCache.valueAt(index);
134 detachFromCache(entry);
135 addToCache(entry, key, value);
136 } else {
137 sp<Entry<K*, V*> > entry = new Entry<K*, V*>;
138 addToCache(entry, key, value);
139 }
140}
141
142template<typename K, typename V>
143void GenerationCache<K, V>::addToCache(sp<Entry<K*, V*> > entry, K* key, V* value) {
144 entry->key = key;
145 entry->value = value;
146 mCache.add(key, entry);
147 attachToCache(entry);
148}
149
150template<typename K, typename V>
Romain Guy364703c2010-06-30 15:51:03 -0700151V* GenerationCache<K, V>::remove(K* key) {
Romain Guyce0537b2010-06-29 21:05:21 -0700152 ssize_t index = mCache.indexOfKey(key);
153 if (index >= 0) {
154 sp<Entry<K*, V*> > entry = mCache.valueAt(index);
155 if (mListener) {
156 (*mListener)(entry->key, entry->value);
157 }
158 mCache.removeItemsAt(index, 1);
159 detachFromCache(entry);
160 }
161
162 return NULL;
163}
164
165template<typename K, typename V>
166void GenerationCache<K, V>::removeOldest() {
167 if (mOldest.get()) {
168 remove(mOldest->key);
169 }
170}
171
172template<typename K, typename V>
173void GenerationCache<K, V>::attachToCache(sp<Entry<K*, V*> > entry) {
174 if (!mYougest.get()) {
175 mYougest = mOldest = entry;
176 } else {
177 entry->parent = mYougest;
178 mYougest->child = entry;
179 mYougest = entry;
180 }
181}
182
183template<typename K, typename V>
184void GenerationCache<K, V>::detachFromCache(sp<Entry<K*, V*> > entry) {
185 if (entry->parent.get()) {
186 entry->parent->child = entry->child;
187 }
188
189 if (entry->child.get()) {
190 entry->child->parent = entry->parent;
191 }
192
193 if (mOldest == entry) {
194 mOldest = entry->child;
195 }
196
197 if (mYougest == entry) {
198 mYougest = entry->parent;
199 }
200
201 entry->parent.clear();
202 entry->child.clear();
203}
204
205}; // namespace uirenderer
206}; // namespace android
207
208#endif // ANDROID_UI_GENERATION_CACHE_H