From 263d8ed29c296f201d1f02528945de24f6f952cd Mon Sep 17 00:00:00 2001 From: "Lars H. Rohwedder" Date: Sun, 2 Mar 2025 17:12:57 +0100 Subject: [PATCH 1/7] minor refactorings, add 'noexcept', 'explicit' etc. --- include/lrucache.hpp | 61 +++++++++++++++++++++++--------------------- 1 file changed, 32 insertions(+), 29 deletions(-) diff --git a/include/lrucache.hpp b/include/lrucache.hpp index 9e5e285..b084949 100644 --- a/include/lrucache.hpp +++ b/include/lrucache.hpp @@ -1,8 +1,8 @@ /* * File: lrucache.hpp - * Author: Alexander Ponomarev + * Author: Alexander Ponomarev, Lars H. Rohwedder * - * Created on June 20, 2013, 5:09 PM + * Created on June 20, 2013, 5:09 PM, edited 2024-03-02 by LR */ #ifndef _LRUCACHE_HPP_INCLUDED_ @@ -16,53 +16,56 @@ namespace cache { template -class lru_cache { +class lru_cache +{ public: typedef typename std::pair key_value_pair_t; typedef typename std::list::iterator list_iterator_t; - lru_cache(size_t max_size) : - _max_size(max_size) { - } + explicit lru_cache(size_t max_size = 10) + : _max_size(max_size) + { } - void put(const key_t& key, const value_t& value) { - auto it = _cache_items_map.find(key); - _cache_items_list.push_front(key_value_pair_t(key, value)); - if (it != _cache_items_map.end()) { - _cache_items_list.erase(it->second); - _cache_items_map.erase(it); + void put(const key_t& key, const value_t& value) + { + auto it = map.find(key); + list.push_front(key_value_pair_t(key, value)); + if (it != map.end()) + { + list.erase(it->second); } - _cache_items_map[key] = _cache_items_list.begin(); + map[key] = list.begin(); - if (_cache_items_map.size() > _max_size) { - auto last = _cache_items_list.end(); - last--; - _cache_items_map.erase(last->first); - _cache_items_list.pop_back(); + if (map.size() > _max_size) + { + auto last = list.rbegin(); + map.erase(last->first); + list.pop_back(); } } - const value_t& get(const key_t& key) { - auto it = _cache_items_map.find(key); - if (it == _cache_items_map.end()) { + const value_t& get(const key_t& key) + { + auto it = map.find(key); + if (it == map.end()) + { throw std::range_error("There is no such key in cache"); } else { - _cache_items_list.splice(_cache_items_list.begin(), _cache_items_list, it->second); + list.splice(list.begin(), list, it->second); return it->second->second; } } - bool exists(const key_t& key) const { - return _cache_items_map.find(key) != _cache_items_map.end(); + bool exists(const key_t& key) const noexcept + { + return map.find(key) != map.end(); } - size_t size() const { - return _cache_items_map.size(); - } + size_t size() const noexcept { return map.size(); } private: - std::list _cache_items_list; - std::unordered_map _cache_items_map; + std::list list; + std::unordered_map map; size_t _max_size; }; From aca320942e9e2772417d06caf9b51da873f2bc0b Mon Sep 17 00:00:00 2001 From: "Lars H. Rohwedder" Date: Sun, 2 Mar 2025 17:18:34 +0100 Subject: [PATCH 2/7] get/set max_size --- include/lrucache.hpp | 29 ++++++++++++++++++++++------- 1 file changed, 22 insertions(+), 7 deletions(-) diff --git a/include/lrucache.hpp b/include/lrucache.hpp index b084949..25c5585 100644 --- a/include/lrucache.hpp +++ b/include/lrucache.hpp @@ -35,13 +35,7 @@ class lru_cache list.erase(it->second); } map[key] = list.begin(); - - if (map.size() > _max_size) - { - auto last = list.rbegin(); - map.erase(last->first); - list.pop_back(); - } + trim(_max_size); } const value_t& get(const key_t& key) @@ -63,10 +57,31 @@ class lru_cache size_t size() const noexcept { return map.size(); } + size_t max_size() const noexcept { return max_size(); } + + void max_size(size_t new_max_size) + { + if(new_max_size<_max_size) + { + trim(new_max_size); + } + _max_size = new_max_size; + } + private: std::list list; std::unordered_map map; size_t _max_size; + + void trim(size_t allowed_size) + { + while(map.size() > allowed_size) + { + auto last = list.rbegin(); + map.erase(last->first); + list.pop_back(); + } + } }; } // namespace cache From 97d355903e63274fffd1c3da8f4e88ba51298097 Mon Sep 17 00:00:00 2001 From: "Lars H. Rohwedder" Date: Sun, 2 Mar 2025 17:21:42 +0100 Subject: [PATCH 3/7] add support for move() the value. TODO: move() the key requires set<> instead of map<>. --- include/lrucache.hpp | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/include/lrucache.hpp b/include/lrucache.hpp index 25c5585..d427b09 100644 --- a/include/lrucache.hpp +++ b/include/lrucache.hpp @@ -37,6 +37,18 @@ class lru_cache map[key] = list.begin(); trim(_max_size); } + + void put(const key_t& key, value_t&& value) + { + auto it = map.find(key); + list.push_front( key_value_pair_t{key, std::move(value)} ); + if (it != map.end()) + { + list.erase(it->second); + } + map[key] = list.begin(); + trim(_max_size); + } const value_t& get(const key_t& key) { From 6743103ea60a3d82c65bc8e7428e8e72ec302b1e Mon Sep 17 00:00:00 2001 From: "Lars H. Rohwedder" Date: Sun, 2 Mar 2025 17:51:26 +0100 Subject: [PATCH 4/7] add remove() --- include/lrucache.hpp | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/include/lrucache.hpp b/include/lrucache.hpp index d427b09..b73dade 100644 --- a/include/lrucache.hpp +++ b/include/lrucache.hpp @@ -28,24 +28,16 @@ class lru_cache void put(const key_t& key, const value_t& value) { - auto it = map.find(key); list.push_front(key_value_pair_t(key, value)); - if (it != map.end()) - { - list.erase(it->second); - } + remove(key); map[key] = list.begin(); trim(_max_size); } void put(const key_t& key, value_t&& value) { - auto it = map.find(key); list.push_front( key_value_pair_t{key, std::move(value)} ); - if (it != map.end()) - { - list.erase(it->second); - } + remove(key); map[key] = list.begin(); trim(_max_size); } @@ -62,6 +54,16 @@ class lru_cache } } + void remove(const key_t& key) + { + auto it = map.find(key); + if( it!= map.end() ) + { + list.erase(it->second); + map.erase(it); + } + } + bool exists(const key_t& key) const noexcept { return map.find(key) != map.end(); From ff4515d7fe86a049d0f35f3a9ee5fda9ec18fc3a Mon Sep 17 00:00:00 2001 From: "Lars H. Rohwedder" Date: Sun, 2 Mar 2025 17:51:44 +0100 Subject: [PATCH 5/7] make lru_cache uncopyable, because the iterators in map would not match in the copy. TODO: implement deep copy. --- include/lrucache.hpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/include/lrucache.hpp b/include/lrucache.hpp index b73dade..d31c322 100644 --- a/include/lrucache.hpp +++ b/include/lrucache.hpp @@ -26,6 +26,9 @@ class lru_cache : _max_size(max_size) { } + lru_cache(const lru_cache&) = delete; + void operator=(const lru_cache&) = delete; + void put(const key_t& key, const value_t& value) { list.push_front(key_value_pair_t(key, value)); From e3d3010f36f909aea910f4143882aed73979e82a Mon Sep 17 00:00:00 2001 From: "Lars H. Rohwedder" Date: Sun, 2 Mar 2025 17:52:58 +0100 Subject: [PATCH 6/7] add clear() --- include/lrucache.hpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/include/lrucache.hpp b/include/lrucache.hpp index d31c322..6d1b43f 100644 --- a/include/lrucache.hpp +++ b/include/lrucache.hpp @@ -67,6 +67,12 @@ class lru_cache } } + void clear() + { + map.clear(); + list.clear(); + } + bool exists(const key_t& key) const noexcept { return map.find(key) != map.end(); From 03d1e70861a96844f5d883556781c190955ac1e3 Mon Sep 17 00:00:00 2001 From: "Lars H. Rohwedder" Date: Sun, 2 Mar 2025 18:12:09 +0100 Subject: [PATCH 7/7] add touch(). rename #include guards to ISO C++ compliant names --- include/lrucache.hpp | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/include/lrucache.hpp b/include/lrucache.hpp index 6d1b43f..b916c11 100644 --- a/include/lrucache.hpp +++ b/include/lrucache.hpp @@ -5,8 +5,8 @@ * Created on June 20, 2013, 5:09 PM, edited 2024-03-02 by LR */ -#ifndef _LRUCACHE_HPP_INCLUDED_ -#define _LRUCACHE_HPP_INCLUDED_ +#ifndef LRU_CACHE_HPP_INCLUDED_ +#define LRU_CACHE_HPP_INCLUDED_ #include #include @@ -45,6 +45,17 @@ class lru_cache trim(_max_size); } + // just move the key's element to front of list + void touch(const key_t& key) + { + auto it = map.find(key); + if(it != map.end() && it->second != list.begin()) + { + list.splice(list.begin(), list, it->second); + map.insert(it, key_value_pair_t{key, list.begin()} ); + } + } + const value_t& get(const key_t& key) { auto it = map.find(key); @@ -109,5 +120,5 @@ class lru_cache } // namespace cache -#endif /* _LRUCACHE_HPP_INCLUDED_ */ +#endif /* LRU_CACHE_HPP_INCLUDED_ */