The C based gRPC (C++, Python, Ruby, Objective-C, PHP, C#)
https://grpc.io/
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
122 lines
3.9 KiB
122 lines
3.9 KiB
// |
|
// Copyright 2024 gRPC authors. |
|
// |
|
// 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 GRPC_SRC_CORE_UTIL_LRU_CACHE_H |
|
#define GRPC_SRC_CORE_UTIL_LRU_CACHE_H |
|
|
|
#include <list> |
|
#include <tuple> |
|
#include <utility> |
|
|
|
#include "absl/container/flat_hash_map.h" |
|
#include "absl/functional/any_invocable.h" |
|
#include "absl/log/check.h" |
|
#include "absl/types/optional.h" |
|
|
|
namespace grpc_core { |
|
|
|
// A simple LRU cache. Retains at most max_size entries. |
|
// Caller is responsible for synchronization. |
|
// TODO(roth): Support heterogenous lookups. |
|
template <typename Key, typename Value> |
|
class LruCache { |
|
public: |
|
explicit LruCache(size_t max_size) : max_size_(max_size) { |
|
CHECK_GT(max_size, 0UL); |
|
} |
|
|
|
// Returns the value for key, or nullopt if not present. |
|
absl::optional<Value> Get(Key key); |
|
|
|
// If key is present in the cache, returns the corresponding value. |
|
// Otherwise, inserts a new entry in the map, calling create() to |
|
// construct the new value. If inserting a new entry causes the cache |
|
// to be too large, removes the least recently used entry. |
|
Value GetOrInsert(Key key, absl::AnyInvocable<Value(const Key&)> create); |
|
|
|
// Changes the max size of the cache. If there are currently more than |
|
// max_size entries, deletes least-recently-used entries to enforce |
|
// the new max size. |
|
void SetMaxSize(size_t max_size); |
|
|
|
private: |
|
struct CacheEntry { |
|
Value value; |
|
typename std::list<Key>::iterator lru_iterator; |
|
|
|
explicit CacheEntry(Value v) : value(std::move(v)) {} |
|
}; |
|
|
|
void RemoveOldestEntry(); |
|
|
|
size_t max_size_; |
|
absl::flat_hash_map<Key, CacheEntry> cache_; |
|
std::list<Key> lru_list_; |
|
}; |
|
|
|
// |
|
// implementation -- no user-serviceable parts below |
|
// |
|
|
|
template <typename Key, typename Value> |
|
absl::optional<Value> LruCache<Key, Value>::Get(Key key) { |
|
auto it = cache_.find(key); |
|
if (it == cache_.end()) return absl::nullopt; |
|
// Found the entry. Move the entry to the end of the LRU list. |
|
auto new_lru_it = lru_list_.insert(lru_list_.end(), *it->second.lru_iterator); |
|
lru_list_.erase(it->second.lru_iterator); |
|
it->second.lru_iterator = new_lru_it; |
|
return it->second.value; |
|
} |
|
|
|
template <typename Key, typename Value> |
|
Value LruCache<Key, Value>::GetOrInsert( |
|
Key key, absl::AnyInvocable<Value(const Key&)> create) { |
|
auto value = Get(key); |
|
if (value.has_value()) return std::move(*value); |
|
// Entry not found. We'll need to insert a new entry. |
|
// If the cache is at max size, remove the least recently used entry. |
|
if (cache_.size() == max_size_) RemoveOldestEntry(); |
|
// Create a new entry, insert it, and return it. |
|
auto it = cache_ |
|
.emplace(std::piecewise_construct, std::forward_as_tuple(key), |
|
std::forward_as_tuple(create(key))) |
|
.first; |
|
it->second.lru_iterator = lru_list_.insert(lru_list_.end(), std::move(key)); |
|
return it->second.value; |
|
} |
|
|
|
template <typename Key, typename Value> |
|
void LruCache<Key, Value>::SetMaxSize(size_t max_size) { |
|
max_size_ = max_size; |
|
while (cache_.size() > max_size_) { |
|
RemoveOldestEntry(); |
|
} |
|
} |
|
|
|
template <typename Key, typename Value> |
|
void LruCache<Key, Value>::RemoveOldestEntry() { |
|
auto lru_it = lru_list_.begin(); |
|
CHECK(lru_it != lru_list_.end()); |
|
auto cache_it = cache_.find(*lru_it); |
|
CHECK(cache_it != cache_.end()); |
|
cache_.erase(cache_it); |
|
lru_list_.pop_front(); |
|
} |
|
|
|
} // namespace grpc_core |
|
|
|
#endif // GRPC_SRC_CORE_UTIL_LRU_CACHE_H
|
|
|