blob: 56693dac736e69a2cf0ffb2e47e12b033af1cb4e [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:
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 Guyce0537b2010-06-29 21:05:21 -070043 void setOnEntryRemovedListener(OnEntryRemoved<K*, V*>* listener);
44
45 void clear();
46
47 bool contains(K* key) const;
Romain Guy364703c2010-06-30 15:51:03 -070048 V* get(K* key);
Romain Guyce0537b2010-06-29 21:05:21 -070049 void put(K* key, V* value);
Romain Guy364703c2010-06-30 15:51:03 -070050 V* remove(K* key);
Romain Guy121e22422010-07-01 18:26:52 -070051 void 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
71 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);
74
Romain Guy7d139ba2010-07-02 11:20:34 -070075 uint32_t mMaxCapacity;
Romain Guyce0537b2010-06-29 21:05:21 -070076
77 OnEntryRemoved<K*, V*>* mListener;
78
79 KeyedVector<K*, sp<Entry<K*, V*> > > mCache;
80
81 sp<Entry<K*, V*> > mOldest;
82 sp<Entry<K*, V*> > mYougest;
83}; // 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>
91void GenerationCache<K, V>::setOnEntryRemovedListener(OnEntryRemoved<K*, V*>* listener) {
92 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>
109bool GenerationCache<K, V>::contains(K* key) const {
110 return mCache.indexOfKey(key) >= 0;
111}
112
113template<typename K, typename V>
Romain Guy364703c2010-06-30 15:51:03 -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) {
117 sp<Entry<K*, V*> > entry = mCache.valueAt(index);
118 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>
129void 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) {
136 sp<Entry<K*, V*> > entry = mCache.valueAt(index);
137 detachFromCache(entry);
138 addToCache(entry, key, value);
139 } else {
140 sp<Entry<K*, V*> > entry = new Entry<K*, V*>;
141 addToCache(entry, key, value);
142 }
143}
144
145template<typename K, typename V>
146void GenerationCache<K, V>::addToCache(sp<Entry<K*, V*> > entry, K* key, V* value) {
147 entry->key = key;
148 entry->value = value;
149 mCache.add(key, entry);
150 attachToCache(entry);
151}
152
153template<typename K, typename V>
Romain Guy364703c2010-06-30 15:51:03 -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) {
157 sp<Entry<K*, V*> > entry = mCache.valueAt(index);
158 if (mListener) {
159 (*mListener)(entry->key, entry->value);
160 }
161 mCache.removeItemsAt(index, 1);
162 detachFromCache(entry);
163 }
164
165 return NULL;
166}
167
168template<typename K, typename V>
169void GenerationCache<K, V>::removeOldest() {
170 if (mOldest.get()) {
171 remove(mOldest->key);
172 }
173}
174
175template<typename K, typename V>
176void GenerationCache<K, V>::attachToCache(sp<Entry<K*, V*> > entry) {
177 if (!mYougest.get()) {
178 mYougest = mOldest = entry;
179 } else {
180 entry->parent = mYougest;
181 mYougest->child = entry;
182 mYougest = entry;
183 }
184}
185
186template<typename K, typename V>
187void GenerationCache<K, V>::detachFromCache(sp<Entry<K*, V*> > entry) {
188 if (entry->parent.get()) {
189 entry->parent->child = entry->child;
190 }
191
192 if (entry->child.get()) {
193 entry->child->parent = entry->parent;
194 }
195
196 if (mOldest == entry) {
197 mOldest = entry->child;
198 }
199
200 if (mYougest == entry) {
201 mYougest = entry->parent;
202 }
203
204 entry->parent.clear();
205 entry->child.clear();
206}
207
208}; // namespace uirenderer
209}; // namespace android
210
211#endif // ANDROID_UI_GENERATION_CACHE_H