lru_cache.hpp 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139
  1. //---------------------------------------------------------------------------//
  2. // Copyright (c) 2013 Kyle Lutz <kyle.r.lutz@gmail.com>
  3. //
  4. // Distributed under the Boost Software License, Version 1.0
  5. // See accompanying file LICENSE_1_0.txt or copy at
  6. // http://www.boost.org/LICENSE_1_0.txt
  7. //
  8. // See http://boostorg.github.com/compute for more information.
  9. //---------------------------------------------------------------------------//
  10. #ifndef BOOST_COMPUTE_DETAIL_LRU_CACHE_HPP
  11. #define BOOST_COMPUTE_DETAIL_LRU_CACHE_HPP
  12. #include <map>
  13. #include <list>
  14. #include <utility>
  15. #include <boost/optional.hpp>
  16. namespace boost {
  17. namespace compute {
  18. namespace detail {
  19. // a cache which evicts the least recently used item when it is full
  20. template<class Key, class Value>
  21. class lru_cache
  22. {
  23. public:
  24. typedef Key key_type;
  25. typedef Value value_type;
  26. typedef std::list<key_type> list_type;
  27. typedef std::map<
  28. key_type,
  29. std::pair<value_type, typename list_type::iterator>
  30. > map_type;
  31. lru_cache(size_t capacity)
  32. : m_capacity(capacity)
  33. {
  34. }
  35. ~lru_cache()
  36. {
  37. }
  38. size_t size() const
  39. {
  40. return m_map.size();
  41. }
  42. size_t capacity() const
  43. {
  44. return m_capacity;
  45. }
  46. bool empty() const
  47. {
  48. return m_map.empty();
  49. }
  50. bool contains(const key_type &key)
  51. {
  52. return m_map.find(key) != m_map.end();
  53. }
  54. void insert(const key_type &key, const value_type &value)
  55. {
  56. typename map_type::iterator i = m_map.find(key);
  57. if(i == m_map.end()){
  58. // insert item into the cache, but first check if it is full
  59. if(size() >= m_capacity){
  60. // cache is full, evict the least recently used item
  61. evict();
  62. }
  63. // insert the new item
  64. m_list.push_front(key);
  65. m_map[key] = std::make_pair(value, m_list.begin());
  66. }
  67. }
  68. boost::optional<value_type> get(const key_type &key)
  69. {
  70. // lookup value in the cache
  71. typename map_type::iterator i = m_map.find(key);
  72. if(i == m_map.end()){
  73. // value not in cache
  74. return boost::none;
  75. }
  76. // return the value, but first update its place in the most
  77. // recently used list
  78. typename list_type::iterator j = i->second.second;
  79. if(j != m_list.begin()){
  80. // move item to the front of the most recently used list
  81. m_list.erase(j);
  82. m_list.push_front(key);
  83. // update iterator in map
  84. j = m_list.begin();
  85. const value_type &value = i->second.first;
  86. m_map[key] = std::make_pair(value, j);
  87. // return the value
  88. return value;
  89. }
  90. else {
  91. // the item is already at the front of the most recently
  92. // used list so just return it
  93. return i->second.first;
  94. }
  95. }
  96. void clear()
  97. {
  98. m_map.clear();
  99. m_list.clear();
  100. }
  101. private:
  102. void evict()
  103. {
  104. // evict item from the end of most recently used list
  105. typename list_type::iterator i = --m_list.end();
  106. m_map.erase(*i);
  107. m_list.erase(i);
  108. }
  109. private:
  110. map_type m_map;
  111. list_type m_list;
  112. size_t m_capacity;
  113. };
  114. } // end detail namespace
  115. } // end compute namespace
  116. } // end boost namespace
  117. #endif // BOOST_COMPUTE_DETAIL_LRU_CACHE_HPP