140 lines
		
	
	
		
			3.5 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
		
		
			
		
	
	
			140 lines
		
	
	
		
			3.5 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
|   | //---------------------------------------------------------------------------// | ||
|  | // Copyright (c) 2013 Kyle Lutz <kyle.r.lutz@gmail.com> | ||
|  | // | ||
|  | // Distributed under the Boost Software License, Version 1.0 | ||
|  | // See accompanying file LICENSE_1_0.txt or copy at | ||
|  | // http://www.boost.org/LICENSE_1_0.txt | ||
|  | // | ||
|  | // See http://boostorg.github.com/compute for more information. | ||
|  | //---------------------------------------------------------------------------// | ||
|  | 
 | ||
|  | #ifndef BOOST_COMPUTE_DETAIL_LRU_CACHE_HPP | ||
|  | #define BOOST_COMPUTE_DETAIL_LRU_CACHE_HPP | ||
|  | 
 | ||
|  | #include <map> | ||
|  | #include <list> | ||
|  | #include <utility> | ||
|  | 
 | ||
|  | #include <boost/optional.hpp> | ||
|  | 
 | ||
|  | namespace boost { | ||
|  | namespace compute { | ||
|  | namespace detail { | ||
|  | 
 | ||
|  | // a cache which evicts the least recently used item when it is full | ||
|  | template<class Key, class Value> | ||
|  | class lru_cache | ||
|  | { | ||
|  | public: | ||
|  |     typedef Key key_type; | ||
|  |     typedef Value value_type; | ||
|  |     typedef std::list<key_type> list_type; | ||
|  |     typedef std::map< | ||
|  |                 key_type, | ||
|  |                 std::pair<value_type, typename list_type::iterator> | ||
|  |             > map_type; | ||
|  | 
 | ||
|  |     lru_cache(size_t capacity) | ||
|  |         : m_capacity(capacity) | ||
|  |     { | ||
|  |     } | ||
|  | 
 | ||
|  |     ~lru_cache() | ||
|  |     { | ||
|  |     } | ||
|  | 
 | ||
|  |     size_t size() const | ||
|  |     { | ||
|  |         return m_map.size(); | ||
|  |     } | ||
|  | 
 | ||
|  |     size_t capacity() const | ||
|  |     { | ||
|  |         return m_capacity; | ||
|  |     } | ||
|  | 
 | ||
|  |     bool empty() const | ||
|  |     { | ||
|  |         return m_map.empty(); | ||
|  |     } | ||
|  | 
 | ||
|  |     bool contains(const key_type &key) | ||
|  |     { | ||
|  |         return m_map.find(key) != m_map.end(); | ||
|  |     } | ||
|  | 
 | ||
|  |     void insert(const key_type &key, const value_type &value) | ||
|  |     { | ||
|  |         typename map_type::iterator i = m_map.find(key); | ||
|  |         if(i == m_map.end()){ | ||
|  |             // insert item into the cache, but first check if it is full | ||
|  |             if(size() >= m_capacity){ | ||
|  |                 // cache is full, evict the least recently used item | ||
|  |                 evict(); | ||
|  |             } | ||
|  | 
 | ||
|  |             // insert the new item | ||
|  |             m_list.push_front(key); | ||
|  |             m_map[key] = std::make_pair(value, m_list.begin()); | ||
|  |         } | ||
|  |     } | ||
|  | 
 | ||
|  |     boost::optional<value_type> get(const key_type &key) | ||
|  |     { | ||
|  |         // lookup value in the cache | ||
|  |         typename map_type::iterator i = m_map.find(key); | ||
|  |         if(i == m_map.end()){ | ||
|  |             // value not in cache | ||
|  |             return boost::none; | ||
|  |         } | ||
|  | 
 | ||
|  |         // return the value, but first update its place in the most | ||
|  |         // recently used list | ||
|  |         typename list_type::iterator j = i->second.second; | ||
|  |         if(j != m_list.begin()){ | ||
|  |             // move item to the front of the most recently used list | ||
|  |             m_list.erase(j); | ||
|  |             m_list.push_front(key); | ||
|  | 
 | ||
|  |             // update iterator in map | ||
|  |             j = m_list.begin(); | ||
|  |             const value_type &value = i->second.first; | ||
|  |             m_map[key] = std::make_pair(value, j); | ||
|  | 
 | ||
|  |             // return the value | ||
|  |             return value; | ||
|  |         } | ||
|  |         else { | ||
|  |             // the item is already at the front of the most recently | ||
|  |             // used list so just return it | ||
|  |             return i->second.first; | ||
|  |         } | ||
|  |     } | ||
|  | 
 | ||
|  |     void clear() | ||
|  |     { | ||
|  |         m_map.clear(); | ||
|  |         m_list.clear(); | ||
|  |     } | ||
|  | 
 | ||
|  | private: | ||
|  |     void evict() | ||
|  |     { | ||
|  |         // evict item from the end of most recently used list | ||
|  |         typename list_type::iterator i = --m_list.end(); | ||
|  |         m_map.erase(*i); | ||
|  |         m_list.erase(i); | ||
|  |     } | ||
|  | 
 | ||
|  | private: | ||
|  |     map_type m_map; | ||
|  |     list_type m_list; | ||
|  |     size_t m_capacity; | ||
|  | }; | ||
|  | 
 | ||
|  | } // end detail namespace | ||
|  | } // end compute namespace | ||
|  | } // end boost namespace | ||
|  | 
 | ||
|  | #endif // BOOST_COMPUTE_DETAIL_LRU_CACHE_HPP |