UNIVERS  15.3
UNIVERS base processing software API
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
lru_cache.h
Go to the documentation of this file.
1 /***************************************************************************
2  * Copyright (C) 2004-2011 by Patrick Audley *
3  * paudley@blackcat.ca *
4  * http://patrickaudley.com *
5  * *
6  ***************************************************************************/
53 #ifndef _lru_cache_h
54 #define _lru_cache_h
55 
56 #include <stdio.h>
57 #include <map>
58 #include <list>
59 #include <vector>
60 #include <cstddef>
61 #ifdef _REENTRANT
62 #include <boost/thread/mutex.hpp>
64 #define SCOPED_MUTEX boost::mutex::scoped_lock lock(this->_mutex);
65 #else
66 #define SCOPED_MUTEX
68 #endif
69 
70 template < class T >
71 struct Countfn {
72  unsigned long operator()( const T& ) { return 1; }
73 };
74 
75 
86 template< class Key, class Data, class Sizefn = Countfn< Data > > class LRUCache {
87  public:
88  typedef std::list< std::pair< Key, Data > > List;
89  typedef typename List::iterator List_Iter;
90  typedef typename List::const_iterator List_cIter;
91  typedef std::vector< Key > Key_List;
92  typedef typename Key_List::iterator Key_List_Iter;
93  typedef typename Key_List::const_iterator Key_List_cIter;
94  typedef std::map< Key, List_Iter > Map;
95  typedef std::pair< Key, List_Iter > Pair;
96  typedef typename Map::iterator Map_Iter;
97  typedef typename Map::const_iterator Map_cIter;
98 
99  private:
100 
101  List _list;
102  Map _index;
103  unsigned long _max_size;
104  unsigned long _curr_size;
105 
106 #ifdef _REENTRANT
107  boost::mutex _mutex;
108 #endif
109 
110  public:
111 
115  LRUCache( const unsigned long Size ) :
116  _max_size( Size ),
117  _curr_size( 0 ) {}
118 
119  LRUCache( const LRUCache &that) {
120  *this = that;
121  }
122 
123  LRUCache& operator=(const LRUCache &that) {
124  if (this == &that)
125  return *this;
126 
127  _list = that._list;
128  _index.clear();
129  for (List_Iter it = _list.begin(); it != _list.end(); ++it)
130  _index.insert(std::make_pair(it->first, it));
131  _max_size = that._max_size;
132  _curr_size = that._curr_size;
133 
134  return *this;
135  }
136 
138  ~LRUCache() { clear(); }
139 
143  inline unsigned long size( void ) const { return _curr_size; }
144 
148  inline unsigned long max_size( void ) const { return _max_size; }
149 
151  void clear( void ) {
152  SCOPED_MUTEX;
153  _list.clear();
154  _index.clear();
155  _curr_size = 0;
156  };
157 
162 #ifdef _REENTRANT
163  inline bool exists( const Key &key ) {
164  SCOPED_MUTEX;
165 #else
166  inline bool exists( const Key &key ) const {
167 #endif
168  return _index.find( key ) != _index.end();
169  }
170 
174  inline void remove( const Key &key ) {
175 #ifdef _REENTRANT
176  SCOPED_MUTEX;
177 #endif
178  Map_Iter miter = _index.find( key );
179  if( miter == _index.end() ) return;
180  _remove( miter );
181  }
182 
186  inline void touch( const Key &key ) {
187  SCOPED_MUTEX;
188  _touch( key );
189  }
190 
196  inline Data *fetch_ptr( const Key &key, bool touch_data = true ) {
197  SCOPED_MUTEX;
198  Map_Iter miter = _index.find( key );
199  if( miter == _index.end() ) return NULL;
200  if (touch_data)
201  _list.splice( _list.begin(), _list, miter->second ); // Do a touch inline.
202  return &(miter->second->second);
203  }
204 
210  inline Data fetch( const Key &key, bool touch_data = true ) {
211  SCOPED_MUTEX;
212  Map_Iter miter = _index.find( key );
213  if( miter == _index.end() )
214  return Data();
215  Data tmp = miter->second->second;
216  if( touch_data )
217  _list.splice( _list.begin(), _list, miter->second ); // Do a touch inline.
218  return tmp;
219  }
220 
227  inline bool fetch( const Key &key, Data &data, bool touch_data = true ) {
228  SCOPED_MUTEX;
229  Map_Iter miter = _index.find( key );
230  if( miter == _index.end() ) return false;
231  if( touch_data )
232  _list.splice( _list.begin(), _list, miter->second ); // Do a touch inline.
233  data = miter->second->second;
234  return true;
235  }
236 
242  inline void insert( const Key &key, const Data &data ) {
243  SCOPED_MUTEX;
244  // Touch the key, if it exists, then replace the content.
245  Map_Iter miter = _touch( key );
246  if( miter != _index.end() )
247  _remove( miter );
248 
249  // Ok, do the actual insert at the head of the list
250  _list.push_front( std::make_pair( key, data ) );
251  List_Iter liter = _list.begin();
252 
253  // Store the index
254  _index.insert( std::make_pair( key, liter ) );
255  _curr_size += Sizefn()( data );
256 
257  //fprintf(stderr, "cache: insert: %p, %p\n",
258  // &(_list.begin()->second),
259  // &(_index.find(key)->second->second));
260 
261  // Check to see if we need to remove an element due to exceeding max_size
262  while( _curr_size > _max_size ) {
263  // Remove the last element.
264  liter = _list.end();
265  --liter;
266  _remove( liter->first );
267  }
268  }
269 
270  void info()
271  {
272  List_Iter lit = _list.begin();
273  for (size_t i=0; i<_curr_size; ++i, ++lit)
274  {
275  Key k1 = lit->first;
276  void *ptr1 = &(lit->second);
277  Key k2 = _index.find(k1)->first;
278  void *ptr2 = &(_index.find(k1)->second->second);
279  fprintf(stderr, "cache: info: [%zu]: %zu, %zu (%zu) | %p, %p (%zu).\n",
280  i, k1, k2, k1 - k2, ptr1, ptr2, (char*)ptr1 - (char*)ptr2);
281  }
282  }
283 
287  inline const Key_List get_all_keys( void ) {
288  SCOPED_MUTEX;
289  Key_List ret;
290  for( List_cIter liter = _list.begin(); liter != _list.end(); liter++ )
291  ret.push_back( liter->first );
292  return ret;
293  }
294 
295  private:
296 
301  inline Map_Iter _touch( const Key &key ) {
302  Map_Iter miter = _index.find( key );
303  if( miter == _index.end() ) return miter;
304 
305  //fprintf(stderr, "cache: _touch: #1 %zu, %p, begin %zu %p.\n",
306  // key, &(miter->second->second),
307  // _list.begin()->first, &(_list.begin()->second));
308 
309  // Move the found node to the head of the list.
310  _list.splice( _list.begin(), _list, miter->second );
311 
312  //fprintf(stderr, "cache: _touch: #2 %zu, %p.\n",
313  // key, &(miter->second->second));
314 
315  return miter;
316  }
317 
322  inline void _remove( const Map_Iter &miter ) {
323  _curr_size -= Sizefn()( miter->second->second );
324  _list.erase( miter->second );
325  _index.erase( miter );
326  }
327 
331  inline void _remove( const Key &key ) {
332  Map_Iter miter = _index.find( key );
333  _remove( miter );
334  }
335  };
336 
337 #endif // _lru_cache_h
338 
void insert(const Key &key, const Data &data)
Inserts a key-data pair into the cache and removes entries if neccessary.
Definition: lru_cache.h:242
Key_List::const_iterator Key_List_cIter
Main cache iterator (const)
Definition: lru_cache.h:93
Map::iterator Map_Iter
Index iterator.
Definition: lru_cache.h:96
Map::const_iterator Map_cIter
Index iterator (const)
Definition: lru_cache.h:97
Key_List::iterator Key_List_Iter
Main cache iterator.
Definition: lru_cache.h:92
bool fetch(const Key &key, Data &data, bool touch_data=true)
Fetches a pointer to cache data.
Definition: lru_cache.h:227
std::list< std::pair< Key, Data > > List
Main cache storage typedef.
Definition: lru_cache.h:88
const Key_List get_all_keys(void)
Get a list of keys.
Definition: lru_cache.h:287
void touch(const Key &key)
Touches a key in the Cache and makes it the most recently used.
Definition: lru_cache.h:186
unsigned long size(void) const
Gets the current abstract size of the cache.
Definition: lru_cache.h:143
List::const_iterator List_cIter
Main cache iterator (const)
Definition: lru_cache.h:90
std::vector< Key > Key_List
List of keys.
Definition: lru_cache.h:91
LRUCache(const unsigned long Size)
Creates a cache that holds at most Size worth of elements.
Definition: lru_cache.h:115
Data fetch(const Key &key, bool touch_data=true)
Fetches a copy of cached data.
Definition: lru_cache.h:210
Data * fetch_ptr(const Key &key, bool touch_data=true)
Fetches a pointer to cache data.
Definition: lru_cache.h:196
List::iterator List_Iter
Main cache iterator.
Definition: lru_cache.h:89
#define SCOPED_MUTEX
If we aren&#39;t reentrant then don&#39;t do anything.
Definition: lru_cache.h:67
unsigned long max_size(void) const
Gets the maximum sbstract size of the cache.
Definition: lru_cache.h:148
std::pair< Key, List_Iter > Pair
Pair of Map elements.
Definition: lru_cache.h:95
void clear(void)
Clears all storage and indices.
Definition: lru_cache.h:151
Template cache with an LRU removal policy.
Definition: lru_cache.h:86
std::map< Key, List_Iter > Map
Index typedef.
Definition: lru_cache.h:94
~LRUCache()
Destructor - cleans up both index and storage.
Definition: lru_cache.h:138
Definition: lru_cache.h:71
bool exists(const Key &key) const
Checks for the existance of a key in the cache.
Definition: lru_cache.h:166