diff --git a/include/lrucache.hpp b/include/lrucache.hpp index 9e5e285..b916c11 100644 --- a/include/lrucache.hpp +++ b/include/lrucache.hpp @@ -1,12 +1,12 @@ /* * 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_ -#define _LRUCACHE_HPP_INCLUDED_ +#ifndef LRU_CACHE_HPP_INCLUDED_ +#define LRU_CACHE_HPP_INCLUDED_ #include #include @@ -16,57 +16,109 @@ 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) + { } + + 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)); + remove(key); + map[key] = list.begin(); + trim(_max_size); + } + + void put(const key_t& key, value_t&& value) + { + list.push_front( key_value_pair_t{key, std::move(value)} ); + remove(key); + map[key] = list.begin(); + trim(_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); - } - _cache_items_map[key] = _cache_items_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(); + // 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 = _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(); + void remove(const key_t& key) + { + auto it = map.find(key); + if( it!= map.end() ) + { + list.erase(it->second); + map.erase(it); + } + } + + void clear() + { + map.clear(); + list.clear(); } - size_t size() const { - return _cache_items_map.size(); + bool exists(const key_t& key) const noexcept + { + return map.find(key) != map.end(); + } + + 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 _cache_items_list; - std::unordered_map _cache_items_map; + 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 -#endif /* _LRUCACHE_HPP_INCLUDED_ */ +#endif /* LRU_CACHE_HPP_INCLUDED_ */