// Copyright (c) 2014-2020 The Dash Core developers // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #ifndef CACHEMAP_H_ #define CACHEMAP_H_ #include #include #include #include "serialize.h" /** * Serializable structure for key/value items */ template struct CacheItem { CacheItem() {} CacheItem(const K& keyIn, const V& valueIn) : key(keyIn), value(valueIn) {} K key; V value; ADD_SERIALIZE_METHODS; template inline void SerializationOp(Stream& s, Operation ser_action) { READWRITE(key); READWRITE(value); } }; /** * Map like container that keeps the N most recently added items */ template class CacheMap { public: typedef Size size_type; typedef CacheItem item_t; typedef std::list list_t; typedef typename list_t::iterator list_it; typedef typename list_t::const_iterator list_cit; typedef std::map map_t; typedef typename map_t::iterator map_it; typedef typename map_t::const_iterator map_cit; private: size_type nMaxSize; list_t listItems; map_t mapIndex; public: explicit CacheMap(size_type nMaxSizeIn = 0) : nMaxSize(nMaxSizeIn), listItems(), mapIndex() {} CacheMap(const CacheMap& other) : nMaxSize(other.nMaxSize), listItems(other.listItems), mapIndex() { RebuildIndex(); } void Clear() { mapIndex.clear(); listItems.clear(); } void SetMaxSize(size_type nMaxSizeIn) { nMaxSize = nMaxSizeIn; } size_type GetMaxSize() const { return nMaxSize; } size_type GetSize() const { return listItems.size(); } bool Insert(const K& key, const V& value) { if(mapIndex.find(key) != mapIndex.end()) { return false; } if(listItems.size() == nMaxSize) { PruneLast(); } listItems.push_front(item_t(key, value)); mapIndex.emplace(key, listItems.begin()); return true; } bool HasKey(const K& key) const { return (mapIndex.find(key) != mapIndex.end()); } bool Get(const K& key, V& value) const { map_cit it = mapIndex.find(key); if(it == mapIndex.end()) { return false; } item_t& item = *(it->second); value = item.value; return true; } void Erase(const K& key) { map_it it = mapIndex.find(key); if(it == mapIndex.end()) { return; } listItems.erase(it->second); mapIndex.erase(it); } const list_t& GetItemList() const { return listItems; } CacheMap& operator=(const CacheMap& other) { nMaxSize = other.nMaxSize; listItems = other.listItems; RebuildIndex(); return *this; } ADD_SERIALIZE_METHODS; template inline void SerializationOp(Stream& s, Operation ser_action) { READWRITE(nMaxSize); READWRITE(listItems); if(ser_action.ForRead()) { RebuildIndex(); } } private: void PruneLast() { if(listItems.empty()) { return; } item_t& item = listItems.back(); mapIndex.erase(item.key); listItems.pop_back(); } void RebuildIndex() { mapIndex.clear(); for(list_it it = listItems.begin(); it != listItems.end(); ++it) { mapIndex.emplace(it->key, it); } } }; #endif /* CACHEMAP_H_ */