it_bus_pdk/bounded_cache.h

00001 #ifndef _BOUNDED_CACHE_H_
00002 #define _BOUNDED_CACHE_H_
00003 
00004 // @Copyright 2002 IONA Technologies, Plc. All Rights Reserved.
00005 //
00006 // A hashtable that enforces a maximum
00007 //
00008 // Maximum: if adding an element causes the size to grow beyond the
00009 // maximum, the least recently used values are removed. max==0
00010 // means the cache is unbounded.
00011 //
00012 
00013 #include <it_dsa/hash_map.h>
00014 #include <it_dsa/list.h>
00015 #include <it_bus/types.h>
00016 
00017 namespace IT_Bus
00018 { 
00019     template<class Data>
00020     class Evictor
00021     {
00022       public:
00023         virtual void evict(Data data) = 0;
00024     };
00025 
00026     template<class Key, class Data, class HashFn, class Equal>
00027     class BoundedCache 
00028     {
00029       public:
00030         BoundedCache(
00031             size_t max_sz, 
00032             Evictor<Data>* evictor
00033         ) : m_evictor(evictor), 
00034             m_max(max_sz)
00035         {
00036             // complete
00037         }
00038 
00039         ~BoundedCache()
00040         {
00041             if (size() == 0)
00042             {
00043                 return;
00044             }
00045 
00046             QueueIterator queue_iter = m_queue.begin();
00047 
00048             while (queue_iter != m_queue.end())
00049             {
00050                 DataKeyPair pair = (*queue_iter);
00051                 m_queue.erase(queue_iter++);               
00052                 MapIterator i = m_map.find(*pair.second);
00053                 m_map.erase(i);
00054             }
00055 
00056         }
00057     
00058         Boolean insert(
00059             const Key& key, 
00060             const Data& data
00061         )
00062         {
00063             IT_Pair<MapIterator, IT_Bool> result;
00064             result = m_map.insert(IT_TYPENAME HashMap::value_type(key, data));
00065             if (result.second)
00066             {
00067                 DataKeyPair pair(data, &key);
00068                 m_queue.push_back(pair);
00069                 enforce_max();
00070             }            
00071             return result.second;
00072         }    
00073 
00074         Boolean remove(const Key& key)
00075         {
00076             if (size() == 0)
00077             {
00078                return false;
00079             }
00080   
00081             MapIterator i = m_map.find(key);
00082             if (i == m_map.end())
00083             {
00084                 return false;
00085             }
00086 
00087             m_map.erase(i);
00088 
00089             QueueIterator queue_iter = m_queue.begin();
00090 
00091             while (queue_iter != m_queue.end())
00092             {
00093                 if (*(*queue_iter).second == key)
00094                 {
00095                     DataKeyPair pair = (*queue_iter);
00096                     m_queue.erase(queue_iter);
00097                     assert(m_queue.size() == m_map.size());
00098                     return true;
00099                 }
00100                 queue_iter++;
00101             }
00102 
00103             assert(m_queue.size() == m_map.size());            
00104             return false;            
00105         }    
00106 
00107         Data* find(const Key& key)
00108         {
00109             if (size() == 0)
00110             {
00111                return 0;
00112             }
00113   
00114             MapIterator i = m_map.find(key);
00115             if (i == m_map.end())
00116             {
00117                 return 0;
00118             }
00119             else
00120             {
00121                 QueueIterator queue_iter = m_queue.begin();
00122 
00123                 while (queue_iter != m_queue.end())
00124                 {
00125                     if (*(*queue_iter).second == key)
00126                     {
00127                         DataKeyPair move = (*queue_iter);
00128                         m_queue.erase(queue_iter);
00129                         m_queue.push_back(move);
00130 
00131                         assert(m_queue.size() == m_map.size());
00132                         return &((*i).second);
00133                     }
00134                     queue_iter++;
00135                 }
00136 
00137                 assert(0);
00138                 return 0;
00139             }
00140         }
00141 
00142         const Data* find(const Key& key) const
00143         {
00144             if (size() == 0)
00145             {
00146                return 0;
00147             }
00148   
00149             MapIterator i = m_map.find(key);
00150             if (i == m_map.end())
00151             {
00152                 return 0;
00153             }
00154             else
00155             {
00156                 QueueIterator queue_iter = m_queue.begin();
00157 
00158                 while (queue_iter != m_queue.end())
00159                 {
00160                     if ((*queue_iter).second == key)
00161                     {
00162                         DataKeyPair move = (*queue_iter);
00163                         m_queue.erase(queue_iter);
00164                         m_queue.push_back(move);
00165 
00166                         assert(m_queue.size() == m_map.size());
00167                         return &((*i).second);
00168                     }
00169                     queue_iter++;
00170                 }
00171 
00172                 assert(0);
00173                 return 0;
00174             }
00175         }
00176 
00177 
00178         size_t size() const
00179         {
00180             return m_map.size();
00181         }
00182 
00183         size_t max() const
00184         {
00185             return m_max;
00186         }
00187 
00188         void max(size_t max_sz)
00189         {
00190             if (m_max > max_sz)
00191             {
00192                 // Silently ignore change.
00193                 return;
00194             }
00195 
00196             m_max = max_sz;
00197 
00198             // If we do eventually allow this then the 
00199             // eviction needs to be done in a batch job
00200             // to ensure that the queue size is always
00201             // the same as the map size.
00202             while (m_map.size() > m_max)
00203             {
00204                 enforce_max();
00205             }
00206         }
00207 
00208       private:
00209         typedef IT_HashMap<Key, Data, HashFn, Equal> HashMap;
00210         typedef IT_TYPENAME HashMap::iterator MapIterator;
00211         typedef IT_Pair<Data, const Key*> DataKeyPair;
00212         typedef IT_List<DataKeyPair> Queue;
00213         typedef IT_TYPENAME Queue::iterator QueueIterator;
00214 
00215         void enforce_max()
00216         {
00217             if (max() == 0)
00218             { 
00219                 return;
00220             }
00221 
00222             if (size() > max())
00223             {
00224                 DataKeyPair data = m_queue.front();
00225                 m_queue.pop_front();
00226 
00227                 MapIterator i = m_map.find(*data.second);
00228     
00229                 m_map.erase(i);
00230                 m_evictor->evict(data.first);
00231             }
00232             assert(m_queue.size() == m_map.size());
00233         }    
00234 
00235 
00236         HashMap             m_map;
00237         Queue               m_queue;
00238         Evictor<Data>*      m_evictor;
00239         size_t              m_max;
00240 
00241         // Not defined prevent accidental use.
00242         BoundedCache(const BoundedCache&);
00243         IT_Bus::Boolean operator == (const BoundedCache&);
00244     };
00245 
00246 }
00247 
00248 #endif  

Generated on Tue Mar 20 15:27:45 2007 for Artix by  doxygen 1.5.1-p1