| /* |
| * Copyright (C) 2016 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 GAPIR_RESOURCE_IN_MEMORY_CACHE_H |
| #define GAPIR_RESOURCE_IN_MEMORY_CACHE_H |
| |
| #include "resource_cache.h" |
| |
| #include <gapic/assert.h> |
| |
| #include <memory> |
| #include <unordered_map> |
| |
| namespace gapir { |
| |
| // Fixed size in-memory resource cache. It uses a ring buffer to store the cache and |
| // starts invalidating cache entries from the oldest to the newest when more space |
| // is required. |
| class ResourceInMemoryCache : public ResourceCache { |
| public: |
| // Creates a new in-memory cache with the given fallback provider and base address. The initial |
| // cache size is 0 byte. |
| static std::unique_ptr<ResourceInMemoryCache> create( |
| std::unique_ptr<ResourceProvider> fallbackProvider, void* buffer); |
| |
| // destructor |
| ~ResourceInMemoryCache(); |
| |
| // Prefetches the specified resources, caching as many that fit in memory as possible. |
| void prefetch(const Resource* resources, size_t count, const ServerConnection& server, |
| void* temp, size_t tempSize) override; |
| |
| // clears the cache. |
| void clear(); |
| |
| // resets the size of the buffer used for caching. |
| void resize(size_t newSize); |
| |
| protected: |
| void putCache(const Resource& resource, const void* data) override; |
| bool getCache(const Resource& resource, void* data) override; |
| |
| private: |
| // constructor |
| ResourceInMemoryCache(std::unique_ptr<ResourceProvider> fallbackProvider, void* buffer); |
| |
| // A doubly-linked list data structure representing a chunk of memory in the cache. |
| struct Block { |
| inline Block(); |
| inline Block(size_t offset, size_t size); |
| inline Block(size_t offset, size_t size, const ResourceId& id); |
| |
| inline ~Block(); |
| |
| inline void linkAfter(Block* other); |
| inline void linkBefore(Block* other); |
| inline void unlink(); |
| |
| size_t offset; // offset in bytes from mBuffer. |
| size_t size; // size in bytes. May wrap-around the cache buffer. |
| ResourceId id; |
| Block* next; |
| Block* prev; |
| }; |
| |
| // put adds the the resource to the cache. |
| // size must be less or equal to mBufferSize. |
| void put(const ResourceId& id, size_t size, const uint8_t* data); |
| |
| // A pointer to the next block to be used for a resource allocation. |
| // While filling the cache, mHead will point to the first free block. Once |
| // the cache is full it will point to an existing cache entry that will be |
| // next to be evicted. |
| Block* mHead; |
| |
| // A map of cached resource identifiers to offsets on mBuffer. |
| std::unordered_map<ResourceId, size_t> mCache; |
| |
| // The base address and the size of the memory used for caching. |
| // This memory region is owned by the memory manager class, not by the cache itself. |
| uint8_t* mBuffer; |
| size_t mBufferSize; |
| }; |
| |
| inline ResourceInMemoryCache::Block::Block() |
| : offset(0), size(0), next(nullptr), prev(nullptr) {} |
| inline ResourceInMemoryCache::Block::Block(size_t offset_, size_t size_) |
| : offset(offset_), size(size_), next(nullptr), prev(nullptr) {} |
| inline ResourceInMemoryCache::Block::Block(size_t offset_, size_t size_, const ResourceId& id) |
| : offset(offset_), size(size_), next(nullptr), prev(nullptr) {} |
| |
| inline ResourceInMemoryCache::Block::~Block() { |
| GAPID_ASSERT((next == nullptr && prev == nullptr) || next == prev); |
| } |
| |
| inline void ResourceInMemoryCache::Block::linkAfter(Block* other) { |
| GAPID_ASSERT(next == nullptr && prev == nullptr); |
| next = other->next; |
| prev = other; |
| next->prev = this; |
| prev->next = this; |
| } |
| |
| inline void ResourceInMemoryCache::Block::linkBefore(Block* other) { |
| GAPID_ASSERT(next == nullptr && prev == nullptr); |
| next = other; |
| prev = other->prev; |
| next->prev = this; |
| prev->next = this; |
| } |
| |
| inline void ResourceInMemoryCache::Block::unlink() { |
| GAPID_ASSERT(next != nullptr && prev != nullptr); |
| next->prev = prev; |
| prev->next = next; |
| next = nullptr; |
| prev = nullptr; |
| } |
| } // namespace gapir |
| |
| #endif // GAPIR_RESOURCE_IN_MEMORY_CACHE_H |