|
1 | | -#include "LRUCache.h" |
2 | | -#include <algorithm> // Required for std::find |
| 1 | +#include "LFUCache.h" |
| 2 | +#include <iostream> |
3 | 3 |
|
4 | | -LRUCache::LRUCache(int capacity) : capacity(capacity) {} |
| 4 | +LFUCache::LFUCache(size_t capacity) : capacity(capacity), hits(0), accesses(0) {} |
5 | 5 |
|
6 | | -// Private helper to move a key to the front of the access_order list |
7 | | -void LRUCache::moveToFront(int key) { |
8 | | - access_order.remove(key); |
9 | | - access_order.push_front(key); |
| 6 | +// --- New Methods --- |
| 7 | +double LFUCache::getHitRate() const { |
| 8 | + if (accesses == 0) return 0.0; |
| 9 | + return static_cast<double>(hits.load()) / accesses.load(); |
10 | 10 | } |
11 | 11 |
|
12 | | -// Private helper to evict the least recently used item |
13 | | -void LRUCache::evict() { |
14 | | - if (access_order.empty()) return; |
15 | | - |
16 | | - // Get the least recently used key from the back of the list |
17 | | - int key_to_evict = access_order.back(); |
18 | | - access_order.pop_back(); |
19 | | - |
20 | | - // Erase it from the cache map |
21 | | - cache.erase(key_to_evict); |
| 12 | +void LFUCache::resetStats() { |
| 13 | + hits = 0; |
| 14 | + accesses = 0; |
22 | 15 | } |
| 16 | +// --- |
23 | 17 |
|
24 | | -int LRUCache::get(int key) { |
| 18 | +int LFUCache::get(int key) { |
25 | 19 | std::lock_guard<std::mutex> lock(cache_mutex); |
| 20 | + accesses++; // Track every access |
26 | 21 |
|
27 | | - // If key is not in the cache, return -1 |
28 | 22 | if (cache.find(key) == cache.end()) { |
29 | | - return -1; |
| 23 | + return -1; // Miss |
30 | 24 | } |
31 | | - |
32 | | - // Key exists, so it's being used. Move it to the front. |
33 | | - moveToFront(key); |
34 | 25 |
|
35 | | - // Note: Assuming the value is stored in the 'first' element of the pair |
| 26 | + hits++; // Track hit |
| 27 | + touch(key); |
36 | 28 | return cache[key].first; |
37 | 29 | } |
38 | 30 |
|
39 | | -void LRUCache::put(int key, int value) { |
| 31 | +void LFUCache::put(int key, int value) { |
40 | 32 | std::lock_guard<std::mutex> lock(cache_mutex); |
41 | | - |
42 | 33 | if (capacity == 0) return; |
43 | 34 |
|
44 | | - // If key already exists, update its value and move it to the front |
45 | 35 | if (cache.find(key) != cache.end()) { |
46 | 36 | cache[key].first = value; |
47 | | - moveToFront(key); |
| 37 | + touch(key); |
48 | 38 | } else { |
49 | | - // If the cache is full, evict the least recently used item first |
50 | 39 | if (cache.size() >= capacity) { |
51 | 40 | evict(); |
52 | 41 | } |
53 | | - // Add the new key-value pair |
54 | | - cache[key] = {value, 0}; // Storing value in .first, .second is unused per your header |
55 | | - access_order.push_front(key); |
| 42 | + cache[key] = {value, 1}; |
| 43 | + freq_map[1].push_front(key); |
| 44 | + } |
| 45 | +} |
| 46 | + |
| 47 | +// Unchanged private helpers... |
| 48 | +void LFUCache::touch(int key) { |
| 49 | + int old_freq = cache[key].second; |
| 50 | + cache[key].second++; |
| 51 | + freq_map[old_freq].remove(key); |
| 52 | + if (freq_map[old_freq].empty()) { |
| 53 | + freq_map.erase(old_freq); |
| 54 | + } |
| 55 | + freq_map[cache[key].second].push_front(key); |
| 56 | +} |
| 57 | + |
| 58 | +void LFUCache::evict() { |
| 59 | + int min_freq = -1; |
| 60 | + for(auto const& [freq, keys] : freq_map) { |
| 61 | + if(min_freq == -1 || freq < min_freq) { |
| 62 | + min_freq = freq; |
| 63 | + } |
| 64 | + } |
| 65 | + if(min_freq != -1) { |
| 66 | + int key_to_evict = freq_map[min_freq].back(); |
| 67 | + freq_map[min_freq].pop_back(); |
| 68 | + if (freq_map[min_freq].empty()) { |
| 69 | + freq_map.erase(min_freq); |
| 70 | + } |
| 71 | + cache.erase(key_to_evict); |
56 | 72 | } |
57 | 73 | } |
0 commit comments