/* * Copyright (C) 2010 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef ANDROID_HWUI_GENERATION_CACHE_H #define ANDROID_HWUI_GENERATION_CACHE_H #include #include namespace android { namespace uirenderer { template class OnEntryRemoved { public: virtual ~OnEntryRemoved() { }; virtual void operator()(EntryKey& key, EntryValue& value) = 0; }; // class OnEntryRemoved template struct Entry: public LightRefBase > { Entry() { } Entry(const Entry& e): key(e.key), value(e.value), parent(e.parent), child(e.child) { } Entry(sp > e): key(e->key), value(e->value), parent(e->parent), child(e->child) { } EntryKey key; EntryValue value; sp > parent; sp > child; }; // struct Entry template class GenerationCache { public: GenerationCache(uint32_t maxCapacity); virtual ~GenerationCache(); enum Capacity { kUnlimitedCapacity, }; void setOnEntryRemovedListener(OnEntryRemoved* listener); void clear(); bool contains(K key) const; V get(K key); K getKeyAt(uint32_t index) const; bool put(K key, V value); V remove(K key); V removeOldest(); V getValueAt(uint32_t index) const; uint32_t size() const; void addToCache(sp > entry, K key, V value); void attachToCache(sp > entry); void detachFromCache(sp > entry); V removeAt(ssize_t index); KeyedVector > > mCache; uint32_t mMaxCapacity; OnEntryRemoved* mListener; sp > mOldest; sp > mYoungest; }; // class GenerationCache template GenerationCache::GenerationCache(uint32_t maxCapacity): mMaxCapacity(maxCapacity), mListener(NULL) { }; template GenerationCache::~GenerationCache() { clear(); }; template uint32_t GenerationCache::size() const { return mCache.size(); } template void GenerationCache::setOnEntryRemovedListener(OnEntryRemoved* listener) { mListener = listener; } template void GenerationCache::clear() { if (mListener) { for (uint32_t i = 0; i < mCache.size(); i++) { sp > entry = mCache.valueAt(i); if (mListener) { (*mListener)(entry->key, entry->value); } } } mCache.clear(); mYoungest.clear(); mOldest.clear(); } template bool GenerationCache::contains(K key) const { return mCache.indexOfKey(key) >= 0; } template K GenerationCache::getKeyAt(uint32_t index) const { return mCache.keyAt(index); } template V GenerationCache::getValueAt(uint32_t index) const { return mCache.valueAt(index)->value; } template V GenerationCache::get(K key) { ssize_t index = mCache.indexOfKey(key); if (index >= 0) { sp > entry = mCache.valueAt(index); if (entry.get()) { detachFromCache(entry); attachToCache(entry); return entry->value; } } return NULL; } template bool GenerationCache::put(K key, V value) { if (mMaxCapacity != kUnlimitedCapacity && mCache.size() >= mMaxCapacity) { removeOldest(); } ssize_t index = mCache.indexOfKey(key); if (index < 0) { sp > entry = new Entry; addToCache(entry, key, value); return true; } return false; } template void GenerationCache::addToCache(sp > entry, K key, V value) { entry->key = key; entry->value = value; mCache.add(key, entry); attachToCache(entry); } template V GenerationCache::remove(K key) { ssize_t index = mCache.indexOfKey(key); if (index >= 0) { return removeAt(index); } return NULL; } template V GenerationCache::removeAt(ssize_t index) { sp > entry = mCache.valueAt(index); if (mListener) { (*mListener)(entry->key, entry->value); } mCache.removeItemsAt(index, 1); detachFromCache(entry); return entry->value; } template V GenerationCache::removeOldest() { if (mOldest.get()) { ssize_t index = mCache.indexOfKey(mOldest->key); if (index >= 0) { return removeAt(index); } } return NULL; } template void GenerationCache::attachToCache(sp > entry) { if (!mYoungest.get()) { mYoungest = mOldest = entry; } else { entry->parent = mYoungest; mYoungest->child = entry; mYoungest = entry; } } template void GenerationCache::detachFromCache(sp > entry) { if (entry->parent.get()) { entry->parent->child = entry->child; } if (entry->child.get()) { entry->child->parent = entry->parent; } if (mOldest == entry) { mOldest = entry->child; } if (mYoungest == entry) { mYoungest = entry->parent; } entry->parent.clear(); entry->child.clear(); } }; // namespace uirenderer }; // namespace android #endif // ANDROID_HWUI_GENERATION_CACHE_H