32#include <shared_mutex>
34#include <unordered_map>
42template <
typename Key,
typename Value,
typename Hash,
typename KeyEqual>
43class simple_lru_cache;
58 std::chrono::seconds
ttl{300};
79 std::atomic<std::uint64_t>
hits{0};
80 std::atomic<std::uint64_t>
misses{0};
90 [[nodiscard]]
double hit_rate() const noexcept {
91 const auto total_hits =
hits.load(std::memory_order_relaxed);
92 const auto total_misses =
misses.load(std::memory_order_relaxed);
93 const auto total = total_hits + total_misses;
97 return (
static_cast<double>(total_hits) /
static_cast<double>(total)) * 100.0;
105 return hits.load(std::memory_order_relaxed) +
106 misses.load(std::memory_order_relaxed);
113 hits.store(0, std::memory_order_relaxed);
114 misses.store(0, std::memory_order_relaxed);
115 insertions.store(0, std::memory_order_relaxed);
116 evictions.store(0, std::memory_order_relaxed);
173template <
typename Key,
175 typename Hash = std::hash<Key>,
176 typename KeyEqual = std::equal_to<Key>>
215 std::unique_lock lock(
other.mutex_);
224 if (
this != &
other) {
225 std::unique_lock lock1(
mutex_, std::defer_lock);
226 std::unique_lock lock2(
other.mutex_, std::defer_lock);
227 std::lock(lock1, lock2);
253 [[nodiscard]] std::optional<Value>
get(
const Key& key) {
254 std::unique_lock lock(
mutex_);
263 auto& entry = it->second;
275 stats_.
hits.fetch_add(1, std::memory_order_relaxed);
290 void put(
const Key& key,
const Value& value) {
291 std::unique_lock lock(
mutex_);
296 auto& entry = it->second;
297 entry->value = value;
322 void put(
const Key& key, Value&& value) {
323 std::unique_lock lock(
mutex_);
328 auto& entry = it->second;
329 entry->value = std::move(value);
357 [[nodiscard]]
bool contains(
const Key& key)
const {
358 std::shared_lock lock(
mutex_);
369 std::unique_lock lock(
mutex_);
405 template <
typename Predicate>
407 std::unique_lock lock(
mutex_);
413 if (pred(it->key, it->value)) {
430 std::unique_lock lock(
mutex_);
446 std::unique_lock lock(
mutex_);
449 const auto now = clock_type::now();
476 std::shared_lock lock(
mutex_);
485 std::shared_lock lock(
mutex_);
501 [[nodiscard]] std::chrono::seconds
ttl() const noexcept {
509 [[nodiscard]]
const std::string&
name() const noexcept {
563 using map_type = std::unordered_map<Key, list_iterator, Hash, KeyEqual>;
574 return clock_type::now() > expiry;
625template <
typename Value>
Thread-safe LRU cache with TTL support.
std::chrono::seconds ttl() const noexcept
Get the TTL duration.
size_type max_size() const noexcept
Get the maximum cache size.
void put(const Key &key, const Value &value)
Store a value in the cache.
const cache_config & config() const noexcept
Get the cache configuration.
const cache_stats & stats() const noexcept
Get cache statistics.
std::chrono::steady_clock clock_type
const std::string & name() const noexcept
Get the cache name (for metrics identification)
clock_type::time_point time_point
void clear()
Remove all entries from the cache.
typename list_type::iterator list_iterator
bool is_expired(time_point expiry, time_point now) const
simple_lru_cache(const cache_config &config=cache_config{})
Construct a cache with the given configuration.
bool invalidate(const Key &key)
Remove a specific entry from the cache.
std::unordered_map< Key, list_iterator, Hash, KeyEqual > map_type
time_point calculate_expiry() const
std::list< cache_entry > list_type
bool empty() const
Check if the cache is empty.
void remove_entry(typename map_type::iterator map_it)
bool contains(const Key &key) const
Check if a key exists in the cache (without affecting LRU order)
double hit_rate() const noexcept
Get the cache hit rate.
bool is_expired(time_point expiry) const
size_type purge_expired()
Remove all expired entries from the cache.
size_type size() const
Get the current number of entries in the cache.
~simple_lru_cache()=default
void put(const Key &key, Value &&value)
Store a value in the cache (move semantics)
simple_lru_cache(simple_lru_cache &&other) noexcept
Movable.
simple_lru_cache(const simple_lru_cache &)=delete
Non-copyable.
std::optional< Value > get(const Key &key)
Retrieve a value from the cache.
void reset_stats() noexcept
Reset cache statistics.
simple_lru_cache(size_type max_size, std::chrono::seconds ttl)
Construct a cache with size and TTL.
simple_lru_cache & operator=(const simple_lru_cache &)=delete
simple_lru_cache & operator=(simple_lru_cache &&other) noexcept
size_type invalidate_if(Predicate pred)
@ other
Other service classes.
Configuration options for the LRU cache.
bool enable_metrics
Enable metrics collection for hit/miss tracking.
std::size_t max_size
Maximum number of entries in the cache.
std::string cache_name
Name for metrics identification (e.g., "query_cache", "study_cache")
std::chrono::seconds ttl
Time-To-Live for cache entries in seconds (default: 300 = 5 minutes)
Statistics for cache performance monitoring.
void reset() noexcept
Reset all statistics to zero.
std::atomic< std::uint64_t > hits
Number of cache hits.
std::atomic< std::uint64_t > evictions
Number of LRU evictions.
double hit_rate() const noexcept
Calculate the cache hit rate.
std::atomic< std::size_t > current_size
Current number of entries.
std::uint64_t total_accesses() const noexcept
Get total number of cache accesses (hits + misses)
std::atomic< std::uint64_t > expirations
Number of TTL expirations.
std::atomic< std::uint64_t > misses
Number of cache misses.
std::atomic< std::uint64_t > insertions
Number of insertions.