llkeyusetracker.h

Go to the documentation of this file.
00001 
00032 #ifndef LL_KEYUSETRACKER_H
00033 #define LL_KEYUSETRACKER_H
00034 
00035 // This is a generic cache for an arbitrary data type indexed against an
00036 // arbitrary key type. The cache length is determined by expiration time
00037 // tince against last use and set size. The age of elements and the size
00038 // of the cache are queryable.
00039 //
00040 // This is implemented as a list, which makes search O(n). If you reuse this
00041 // for something with a large dataset, consider reimplementing with a Boost
00042 // multimap based on both a map(key) and priority queue(last_use).
00043 
00044 template <class TKey, class TData>
00045 class KeyUseTrackerNodeImpl
00046 {
00047 public:
00048         U64 mLastUse;
00049         U32 mUseCount;
00050         TKey mKey;
00051         TData mData;
00052 
00053         KeyUseTrackerNodeImpl( TKey k, TData d ) :
00054                 mLastUse(0),
00055                 mUseCount(0),
00056                 mKey( k ),
00057                 mData( d )
00058         {
00059         }
00060 };
00061 
00062 
00063 template <class TKey, class TData>
00064 class LLKeyUseTracker
00065 {
00066         typedef KeyUseTrackerNodeImpl<TKey,TData> TKeyUseTrackerNode;
00067         typedef std::list<TKeyUseTrackerNode *> TKeyList;
00068         TKeyList mKeyList;
00069         U64 mMemUsecs;
00070         U64 mLastExpire;
00071         U32 mMaxCount;
00072         U32 mCount;
00073 
00074         static U64 getTime()
00075         {
00076                 // This function operates on a frame basis, not instantaneous.
00077                 // We can rely on its output for determining first use in a
00078                 // frame.
00079                 return LLFrameTimer::getTotalTime();
00080         }
00081 
00082         void ageKeys()
00083         {
00084                 U64 now = getTime();
00085                 if( now == mLastExpire )
00086                 {
00087                         return;
00088                 }
00089                 mLastExpire = now;
00090 
00091                 while( !mKeyList.empty() && (now - mKeyList.front()->mLastUse > mMemUsecs ) )
00092                 {
00093                         delete mKeyList.front();
00094                         mKeyList.pop_front();
00095                         mCount--;
00096                 }
00097         }
00098 
00099         TKeyUseTrackerNode *findNode( TKey key )
00100         {
00101                 ageKeys();
00102 
00103                 typename TKeyList::iterator i;
00104                 for( i = mKeyList.begin(); i != mKeyList.end(); i++ )
00105                 {
00106                         if( (*i)->mKey == key )
00107                                 return *i;
00108                 }
00109 
00110                 return NULL;
00111         }
00112 
00113         TKeyUseTrackerNode *removeNode( TKey key )
00114         {
00115                 TKeyUseTrackerNode *i;
00116                 i = findNode( key );
00117                 if( i )
00118                 {
00119                         mKeyList.remove( i );
00120                         mCount--;
00121                         return i;
00122                 }
00123 
00124                 return NULL;
00125         }
00126 
00127 public:
00128         LLKeyUseTracker( U32 memory_seconds, U32 max_count ) :
00129                 mLastExpire(0),
00130                 mMaxCount( max_count ),
00131                 mCount(0)
00132         {
00133                 mMemUsecs = ((U64)memory_seconds) * 1000000;
00134         }
00135 
00136         ~LLKeyUseTracker()
00137         {
00138                 // Flush list
00139                 while( !mKeyList.empty() )
00140                 {
00141                         delete mKeyList.front();
00142                         mKeyList.pop_front();
00143                         mCount--;
00144                 }
00145         }
00146 
00147         void markUse( TKey key, TData data )
00148         {
00149                 TKeyUseTrackerNode *node = removeNode( key );
00150                 if( !node )
00151                 {
00152                         node = new TKeyUseTrackerNode(key, data);
00153                 }
00154                 else
00155                 {
00156                         // Update data
00157                         node->mData = data;
00158                 }
00159                 node->mLastUse = getTime();
00160                 node->mUseCount++;
00161                 mKeyList.push_back( node );
00162                 mCount++;
00163 
00164                 // Too many items? Drop head
00165                 if( mCount > mMaxCount )
00166                 {
00167                         delete mKeyList.front();
00168                         mKeyList.pop_front();
00169                         mCount--;
00170                 }
00171         }
00172 
00173         void forgetKey( TKey key )
00174         {
00175                 TKeyUseTrackerNode *node = removeNode( key );
00176                 if( node )
00177                 {
00178                         delete node;
00179                 }
00180         }
00181 
00182         U32 getUseCount( TKey key )
00183         {
00184                 TKeyUseTrackerNode *node = findNode( key );
00185                 if( node )
00186                 {
00187                         return node->mUseCount;
00188                 }
00189                 return 0;
00190         }
00191 
00192         U64 getTimeSinceUse( TKey key )
00193         {
00194                 TKeyUseTrackerNode *node = findNode( key );
00195                 if( node )
00196                 {
00197                         U64 now = getTime();
00198                         U64 delta = now - node->mLastUse;
00199                         return (U32)( delta / 1000000 );
00200                 }
00201                 return 0;
00202         }
00203 
00204         TData *getLastUseData( TKey key )
00205         {
00206                 TKeyUseTrackerNode *node = findNode( key );
00207                 if( node )
00208                 {
00209                         return &node->mData;
00210                 }
00211                 return NULL;
00212         }
00213 
00214         U32 getKeyCount()
00215         {
00216                 return mCount;
00217         }
00218 };
00219 
00220 #endif

Generated on Fri May 16 08:32:03 2008 for SecondLife by  doxygen 1.5.5