diff options
Diffstat (limited to 'gfx/angle/checkout/src/libANGLE/SizedMRUCache.h')
-rw-r--r-- | gfx/angle/checkout/src/libANGLE/SizedMRUCache.h | 156 |
1 files changed, 156 insertions, 0 deletions
diff --git a/gfx/angle/checkout/src/libANGLE/SizedMRUCache.h b/gfx/angle/checkout/src/libANGLE/SizedMRUCache.h new file mode 100644 index 0000000000..b557e657ec --- /dev/null +++ b/gfx/angle/checkout/src/libANGLE/SizedMRUCache.h @@ -0,0 +1,156 @@ +// +// Copyright 2017 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// SizedMRUCache.h: A hashing map that stores blobs of sized, untyped data. + +#ifndef LIBANGLE_SIZED_MRU_CACHE_H_ +#define LIBANGLE_SIZED_MRU_CACHE_H_ + +#include <anglebase/containers/mru_cache.h> + +namespace angle +{ + +template <typename Key, typename Value> +class SizedMRUCache final : angle::NonCopyable +{ + public: + SizedMRUCache(size_t maximumTotalSize) + : mMaximumTotalSize(maximumTotalSize), + mCurrentSize(0), + mStore(SizedMRUCacheStore::NO_AUTO_EVICT) + {} + + // Returns nullptr on failure. + const Value *put(const Key &key, Value &&value, size_t size) + { + if (size > mMaximumTotalSize) + { + return nullptr; + } + + // Check for existing key. + eraseByKey(key); + + auto retVal = mStore.Put(key, ValueAndSize(std::move(value), size)); + mCurrentSize += size; + + shrinkToSize(mMaximumTotalSize); + + return &retVal->second.value; + } + + bool get(const Key &key, const Value **valueOut) + { + const auto &iter = mStore.Get(key); + if (iter == mStore.end()) + { + return false; + } + *valueOut = &iter->second.value; + return true; + } + + bool getAt(size_t index, const Key **keyOut, const Value **valueOut) + { + if (index < mStore.size()) + { + auto it = mStore.begin(); + std::advance(it, index); + *keyOut = &it->first; + *valueOut = &it->second.value; + return true; + } + *valueOut = nullptr; + return false; + } + + bool empty() const { return mStore.empty(); } + + void clear() + { + mStore.Clear(); + mCurrentSize = 0; + } + + void eraseByKey(const Key &key) + { + // Check for existing key. + auto existing = mStore.Peek(key); + if (existing != mStore.end()) + { + mCurrentSize -= existing->second.size; + mStore.Erase(existing); + } + } + + size_t entryCount() const { return mStore.size(); } + + size_t size() const { return mCurrentSize; } + + // Also discards the cache contents. + void resize(size_t maximumTotalSize) + { + clear(); + mMaximumTotalSize = maximumTotalSize; + } + + // Reduce current memory usage. + size_t shrinkToSize(size_t limit) + { + size_t initialSize = mCurrentSize; + + while (mCurrentSize > limit) + { + ASSERT(!mStore.empty()); + auto iter = mStore.rbegin(); + mCurrentSize -= iter->second.size; + mStore.Erase(iter); + } + + return (initialSize - mCurrentSize); + } + + size_t maxSize() const { return mMaximumTotalSize; } + + private: + struct ValueAndSize + { + ValueAndSize() : value(), size(0) {} + ValueAndSize(Value &&value, size_t size) : value(std::move(value)), size(size) {} + ValueAndSize(ValueAndSize &&other) : ValueAndSize() { *this = std::move(other); } + ValueAndSize &operator=(ValueAndSize &&other) + { + std::swap(value, other.value); + std::swap(size, other.size); + return *this; + } + + Value value; + size_t size; + }; + + using SizedMRUCacheStore = base::HashingMRUCache<Key, ValueAndSize>; + + size_t mMaximumTotalSize; + size_t mCurrentSize; + SizedMRUCacheStore mStore; +}; + +// Helper function used in a few places. +template <typename T> +void TrimCache(size_t maxStates, size_t gcLimit, const char *name, T *cache) +{ + const size_t kGarbageCollectionLimit = maxStates / 2 + gcLimit; + + if (cache->size() >= kGarbageCollectionLimit) + { + WARN() << "Overflowed the " << name << " cache limit of " << (maxStates / 2) + << " elements, removing the least recently used to make room."; + cache->ShrinkToSize(maxStates / 2); + } +} +} // namespace angle +#endif // LIBANGLE_SIZED_MRU_CACHE_H_ |