| 90 | |
| 91 | template<class Value> |
| 92 | typename LFUCache<Value>::InsertRes |
| 93 | LFUCache<Value>::insert(std::string_view key, Value value) { |
| 94 | if (!can_write_cache(key)) { |
| 95 | return InsertRes{false}; |
| 96 | } |
| 97 | |
| 98 | std::unique_lock<std::shared_mutex> l(m); |
| 99 | // Re-check enabled after acquiring lock: state may have flipped while waiting. |
| 100 | if (!enabled.load(std::memory_order_relaxed)) { |
| 101 | return InsertRes{false}; |
| 102 | } |
| 103 | |
| 104 | auto it = cache_data.find(key); |
| 105 | if (it != cache_data.end()) { |
| 106 | InsertRes res{true}; |
| 107 | res.replaced = std::move(it->second.val); |
| 108 | it->second.val = std::move(value); |
| 109 | return res; |
| 110 | } |
| 111 | |
| 112 | // New insert counts as a miss (cache didn't have it) |
| 113 | mark_miss(); |
| 114 | |
| 115 | InsertRes res{true}; |
| 116 | if (cache_data.size() >= capacity && !cache_data.empty()) { |
| 117 | auto min_it = std::min_element(cache_data.begin(), |
| 118 | cache_data.end(), |
| 119 | [](const auto& a, const auto& b) { |
| 120 | return a.second.hits.load(std::memory_order_relaxed) < |
| 121 | b.second.hits.load(std::memory_order_relaxed); |
| 122 | }); |
| 123 | res.evicted = std::move(min_it->second.val); |
| 124 | cache_data.erase(min_it); |
| 125 | } |
| 126 | |
| 127 | // Allocate std::string only here, when we actually need to store a new key. |
| 128 | cache_data.emplace(std::string(key), Entry(std::move(value))); |
| 129 | return res; |
| 130 | } |
| 131 | |
| 132 | template <class Value> |
| 133 | MgrMapCache<Value>::MgrMapCache(uint16_t size) |
nothing calls this directly
no test coverage detected