#pragma once
#include <whiteout/common_types.h>
#include <array>
#include <cstring>
#include <list>
#include <mutex>
#include <optional>
#include <span>
#include <unordered_map>
#include <vector>
namespace whiteout::storages::casc {
class MemoryCache {
public:
class CacheView {
public:
CacheView() = default;
CacheView(CacheView&&) = default;
CacheView& operator=(CacheView&&) = default;
std::span<const u8> data() const noexcept {
return m_data;
}
size_t size() const noexcept {
return m_data.size();
}
private:
friend class MemoryCache;
std::unique_lock<std::mutex> m_lock;
std::span<const u8> m_data;
};
explicit MemoryCache(size_t maxBytes = 256 * 1024 * 1024);
std::optional<std::vector<u8>> get(const std::array<u8, 16>& eKey) const;
std::optional<CacheView> view(const std::array<u8, 16>& eKey) const;
void put(const std::array<u8, 16>& eKey, const std::vector<u8>& data);
void clear();
size_t maxBytes() const noexcept {
return m_maxBytes;
}
private:
struct CacheEntry {
std::array<u8, 16> eKey;
std::vector<u8> data;
};
struct KeyHash {
size_t operator()(const std::array<u8, 16>& k) const noexcept {
u64 h = 0;
std::memcpy(&h, k.data(), 8);
return static_cast<size_t>(h);
}
};
size_t m_maxBytes;
mutable size_t m_currentBytes = 0;
using LruList = std::list<CacheEntry>;
mutable LruList m_lru;
using LruIt = LruList::iterator;
mutable std::unordered_map<std::array<u8, 16>, LruIt, KeyHash> m_map;
mutable std::mutex m_mutex;
void evict();
};
}