OSSIM - Open Source Software Image Map  Version 1.9.0 (20180803)
ItemCache.h
Go to the documentation of this file.
1 #ifndef ossimItemCache_HEADER
2 #define ossimItemCache_HEADER
3 #include <ossim/base/RWLock.h>
4 #include <map>
5 #include <memory>
6 #include <mutex>
7 
8 namespace ossim
9 {
67  template<class ItemType>
68  class ItemCache
69  {
70  public:
71  typename std::shared_ptr<ItemType> SharedItemType;
80  struct Node
81  {
82  ossim_uint64 m_lruId;
83  ossimString m_cacheId;
84  std::shared_ptr<ItemType> m_item;
85  };
86  typedef std::map<ossimString, std::shared_ptr<Node> > CacheType;
87  typedef std::map<ossim_uint64, std::shared_ptr<Node> > LruType;
88 
97  std::shared_ptr<ItemType> getItem(const ossimString& key);
98  std::shared_ptr<const ItemType> getItem(const ossimString& key)const;
99 
106  void addItem(const ossimString& key,
107  std::shared_ptr<ItemType> item);
108 
115  std::shared_ptr<ItemType> removeItem(const ossimString& key);
116 
121  void reset();
122 
128  void setMinAndMaxItemsToCache(ossim_uint32 minItemsToCache, ossim_uint32 maxItemsToCache);
129 
133  ossim_uint32 getMaxItemsToCache()const;
134 
138  ossim_uint32 getMinItemsToCache()const;
139 
140  protected:
141  mutable RWLock m_itemCacheMutex;
142  mutable RWLock m_lruCacheMutex;
143  mutable ossim_uint64 m_currentId{0};
144  CacheType m_cache;
145  mutable LruType m_lruCache;
146  ossim_uint32 m_maxItemsToCache{100};
147  ossim_uint32 m_minItemsToCache{80};
148 
157  void protectedAddItem(const ossimString& key,
158  std::shared_ptr<ItemType> item);
159 
164  void shrinkCache();
165 
172  void touchNode(std::shared_ptr<Node> node)const;
173 
180  std::shared_ptr<Node> removeItemFromCache(const ossimString& key);
181 
188  std::shared_ptr<Node> removeItemFromLruCache(ossim_uint64 key)const;
189 
196  ossim_uint64 nextId()const;
197  };
198 
199  template<class ItemType>
200  typename std::shared_ptr<ItemType> ItemCache<ItemType>::getItem(const ossimString& key)
201  {
202  ossim::ScopeReadLock lock(m_itemCacheMutex);
203  std::shared_ptr<ItemType> result;
204  typename CacheType::iterator iter = m_cache.find(key);
205  if(iter != m_cache.end())
206  {
207  result = iter->second->m_item;
208  touchNode(iter->second);
209  }
210  return result;
211  }
212 
213  template<class ItemType>
214  typename std::shared_ptr<const ItemType> ItemCache<ItemType>::getItem(const ossimString& key)const
215  {
216  ossim::ScopeReadLock lock(m_itemCacheMutex);
217  std::shared_ptr<const ItemType> result;
218  typename CacheType::const_iterator iter = m_cache.find(key);
219  if(iter != m_cache.end())
220  {
221  result = iter->second->m_item;
222  touchNode(iter->second);
223  }
224  return result;
225  }
226 
227  template<class ItemType>
228  void ItemCache<ItemType>::addItem(const ossimString& key,
229  std::shared_ptr<ItemType> item)
230  {
231  ossim::ScopeWriteLock lock(m_itemCacheMutex);
232  protectedAddItem(key, item);
233  }
234  template<class ItemType>
235  typename std::shared_ptr<ItemType> ItemCache<ItemType>::removeItem(const ossimString& key)
236  {
237  ossim::ScopeWriteLock lock(m_itemCacheMutex);
238  std::shared_ptr<ItemType> result;
239  std::shared_ptr<Node> node = removeItemFromCache(key);
240  if(node)
241  {
242  result = node->m_item;
243  removeItemFromLruCache(node->m_lruId);
244  }
245 
246  return result;
247  }
248 
249  template<class ItemType>
250  void ItemCache<ItemType>::protectedAddItem(const ossimString& key,
251  std::shared_ptr<ItemType> item)
252  {
253  if(m_cache.size() > m_maxItemsToCache)
254  {
255  shrinkCache();
256  }
257  typename CacheType::iterator iter = m_cache.find(key);
258  if(iter!= m_cache.end())
259  {
260  // update the item and LRU
261  //
262  std::shared_ptr<Node> node = iter->second;
263  node->m_item = item;
264 
265  touchNode(node);
266  }
267  else
268  {
269  std::shared_ptr<Node> nodePtr = std::make_shared<Node>();
270  nodePtr->m_cacheId = key;
271  nodePtr->m_item = item;
272  nodePtr->m_lruId = nextId();
273  m_cache.insert(std::make_pair(key, nodePtr));
274  {
275  ossim::ScopeWriteLock lock(m_lruCacheMutex);
276  if(m_lruCache.size() > 0)
277  {
278  m_lruCache.insert(--m_lruCache.end(),
279  std::make_pair(nodePtr->m_lruId,
280  nodePtr));
281  }
282  else
283  {
284  m_lruCache.insert(std::make_pair(nodePtr->m_lruId,
285  nodePtr));
286  }
287  }
288  }
289  }
290 
291  template<class ItemType>
292  void ItemCache<ItemType>::touchNode(std::shared_ptr<Node> node)const
293  {
294  m_lruCache.erase(node->m_lruId);
295  node->m_lruId = nextId();
296  {
297  ossim::ScopeWriteLock lock(m_lruCacheMutex);
298  if(m_lruCache.size() > 0)
299  {
300  m_lruCache.insert(m_lruCache.end(), std::make_pair(node->m_lruId, node));
301  }
302  else
303  {
304  m_lruCache.insert(std::make_pair(node->m_lruId, node));
305  }
306  }
307  }
308 
309  template<class ItemType>
310  ossim_uint64 ItemCache<ItemType>::nextId()const
311  {
312  return m_currentId++;
313  }
314 
315  template<class ItemType>
316  void ItemCache<ItemType>::setMinAndMaxItemsToCache(ossim_uint32 maxItemsToCache,
317  ossim_uint32 minItemsToCache)
318  {
319  ossim::ScopeWriteLock lock(m_itemCacheMutex);
320  m_maxItemsToCache = maxItemsToCache;
321  m_minItemsToCache = minItemsToCache;
322  }
323  template<class ItemType>
324  void ItemCache<ItemType>::reset()
325  {
326  ossim::ScopeWriteLock lock(m_itemCacheMutex);
327  m_cache.clear();
328  m_lruCache.clear();
329  m_currentId = 0;
330  }
331 
332  template<class ItemType>
333  void ItemCache<ItemType>::shrinkCache()
334  {
335  if(m_minItemsToCache < 1)
336  {
337  m_lruCache.clear();
338  m_cache.clear();
339  }
340  else
341  {
342  typename LruType::iterator iter = m_lruCache.begin();
343  ossim_uint32 previousSize = m_cache.size();
344  while((m_cache.size() > m_minItemsToCache)&&
345  (iter != m_lruCache.end()))
346  {
347  removeItemFromCache(iter->second->m_cacheId);
348  iter = m_lruCache.erase(iter);
349 
350  // sanity check to make sure we continue to shrink at
351  // each iteration
352  // avoids infinite loop
353  if(m_cache.size() >= previousSize)
354  {
355  break;
356  }
357  }
358  }
359  }
360 
361  template<class ItemType>
362  ossim_uint32 ItemCache<ItemType>::getMaxItemsToCache()const
363  {
364  ossim::ScopeReadLock lock(m_itemCacheMutex);
365  return m_maxItemsToCache;
366  }
367 
368  template<class ItemType>
369  ossim_uint32 ItemCache<ItemType>::getMinItemsToCache()const
370  {
371  ossim::ScopeReadLock lock(m_itemCacheMutex);
372  return m_minItemsToCache;
373  }
374 
375  template<class ItemType>
376  std::shared_ptr< typename ItemCache<ItemType>::Node> ItemCache<ItemType>::removeItemFromCache(const ossimString& key)
377  {
378  std::shared_ptr<Node> result;
379 
380  typename CacheType::iterator iter = m_cache.find(key);
381  if(iter != m_cache.end())
382  {
383  result = iter->second;
384  m_cache.erase(iter);
385  }
386 
387  return result;
388  }
389 
390  template<class ItemType>
391  std::shared_ptr<typename ItemCache<ItemType>::Node> ItemCache<ItemType>::removeItemFromLruCache(ossim_uint64 key)const
392  {
393  std::shared_ptr<Node> result;
394 
395  typename LruType::iterator iter = m_lruCache.find(key);
396  if(iter != m_lruCache.end())
397  {
398  result = iter->second;
399  m_lruCache.erase(iter);
400  }
401 
402  return result;
403  }
404 
405 }
406 
407 
408 
409 #endif
This code was derived from https://gist.github.com/mshockwave.
Definition: Barrier.h:8
unsigned long long ossim_uint64
unsigned int ossim_uint32