// Copyright (c) 2014-2023 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 BITCOIN_CACHEMAP_H #define BITCOIN_CACHEMAP_H #include #include #include #include /** * 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; SERIALIZE_METHODS(CacheItem, obj) { READWRITE(obj.key, obj.value); } }; /** * Map like container that keeps the N most recently added items */ template class CacheMap { public: using size_type = Size; using item_t = CacheItem; using list_t = std::list; using list_it = typename list_t::iterator; using list_cit = typename list_t::const_iterator; using map_t = std::map; using map_it = typename map_t::iterator; using map_cit = typename map_t::const_iterator; private: size_type nMaxSize; list_t listItems; map_t mapIndex; public: explicit CacheMap(size_type nMaxSizeIn = 0) : nMaxSize(nMaxSizeIn), listItems(), mapIndex() {} explicit 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; } const 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; } SERIALIZE_METHODS(CacheMap, obj) { READWRITE(obj.nMaxSize, obj.listItems); SER_READ(obj, obj.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 // BITCOIN_CACHEMAP_H