RESULT
TEST DEMO
int main(void){
constexpr auto ADDRESS_MAX { 1024U };
srand((unsigned)time(nullptr));
using Address_t = int32_t;
using Data_t = char;
LRUCache<Address_t, Data_t> cache;
std::mt19937 gen(std::random_device{}());
std::uniform_int_distribution<> distrib(0, 100);
int rounds { 1024 };
std::size_t hits { 0U };
std::size_t misses { 0U };
std::size_t loads { 0U };
std::size_t fetches { 0U };
while( rounds-- ){
if(distrib(gen) <= 90){
++loads;
int address { rand() % ADDRESS_MAX };
char data { (char)(rand() % 26 + 'a') };
std::printf("load [%x, %c]...\n",address, data);
cache.put({address, data});
}else{
++fetches;
int address { rand() % ADDRESS_MAX };
std::puts("--------------------------------------------");
std::printf("try to fetch data at address [%x] from cache...\n", address);
auto result { cache.get(address) };
if( result.has_value() ){
++hits;
std::printf("hit the data [%c] from cache...\n", *result);
}else{
++misses;
puts("miss the data from cache...\n");
}
std::puts("--------------------------------------------");
}
}
puts("---------LRUCache result-------------");
std::cout << "load times:\t" << loads << '\n'
<< "fetch times:\t" << fetches << '\n'
<< "hit times:\t" << hits << '\n'
<< "miss times:\t" << misses << '\n'
<< "hit rate:\t"
<< std::setprecision(4)
<< (double)hits/fetches;
std::endl(std::cout);
return 0;
}
DETAIL IMPLEMENTATION
#include <list>
#include <unordered_map>
#include <concepts>
#include <type_traits>
#include <utility>
#include <optional>
#include <random>
#include <exception>
#include <iostream>
#include <iomanip>
template <class Key,
class Value,
class Hash = std::hash<Key>,
class = std::common_type<
typename std::result_of<typename
std::decay<Hash>::type(Key&&)>::type,
std::size_t>>
class LRUCache{
public:
typedef std::pair<Key, Value> store_type;
typedef std::optional<Value> get_return_type;
static constexpr std::size_t default_capacity { 64U };
protected:
std::unordered_map<Key, Value, Hash> hash;
std::list<Key> cache;
std::unordered_map<Key,
typename decltype(cache)::iterator>
assotiator;
private:
std::size_t capacity { default_capacity };
template <class K, class V, class H, class>
friend class LRUCache;
public:
constexpr LRUCache(void) noexcept = default;
LRUCache(std::size_t __capacity) noexcept
: capacity(__capacity) {}
LRUCache(const LRUCache&) = default;
explicit LRUCache(LRUCache&&) noexcept = default;
[[discard]] get_return_type
get(const Key& key) try{
if(!hash.count(key))
return static_cast
<get_return_type>(std::nullopt);
const auto& it = assotiator[key];
cache.splice(cache.begin(), cache, it);
return std::make_optional<Value>(*it);
}catch(const std::exception& e){
std::cerr << "located LRU::get():\t"
<< e.what() << '\n';
}
void put(const store_type& p)
requires std::assignable_from<Key&, Key>
&& std::assignable_from<Value&, Value>
try{
const auto& [__key, __value] = p;
if(hash.count(__key)) cache.erase(assotiator[__key]);
cache.push_front(__key);
hash.insert(p);
assotiator[__key] = cache.begin();
if(cache.size() > capacity){
auto& __fkey = cache.back();
hash.erase(__fkey);
assotiator.erase(__fkey);
cache.pop_back();
}
}catch(const std::exception& e){
std::cout << "locate LRUCache::put():\t"
<< e.what() << '\n';
}
};