PageRenderTime 11ms CodeModel.GetById 2ms app.highlight 6ms RepoModel.GetById 1ms app.codeStats 0ms

/indra/llcommon/llkeyusetracker.h

https://bitbucket.org/lindenlab/viewer-beta/
C++ Header | 215 lines | 152 code | 24 blank | 39 comment | 14 complexity | 61acb6e9d1b5db6c6fe316c152a3bb87 MD5 | raw file
  1/** 
  2 * @file llkeyusetracker.h
  3 * @brief Declaration of the LLKeyUseTracker class.
  4 *
  5 * $LicenseInfo:firstyear=2003&license=viewerlgpl$
  6 * Second Life Viewer Source Code
  7 * Copyright (C) 2010, Linden Research, Inc.
  8 * 
  9 * This library is free software; you can redistribute it and/or
 10 * modify it under the terms of the GNU Lesser General Public
 11 * License as published by the Free Software Foundation;
 12 * version 2.1 of the License only.
 13 * 
 14 * This library is distributed in the hope that it will be useful,
 15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 17 * Lesser General Public License for more details.
 18 * 
 19 * You should have received a copy of the GNU Lesser General Public
 20 * License along with this library; if not, write to the Free Software
 21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 22 * 
 23 * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
 24 * $/LicenseInfo$
 25 */
 26
 27#ifndef LL_KEYUSETRACKER_H
 28#define LL_KEYUSETRACKER_H
 29
 30// This is a generic cache for an arbitrary data type indexed against an
 31// arbitrary key type. The cache length is determined by expiration time
 32// tince against last use and set size. The age of elements and the size
 33// of the cache are queryable.
 34//
 35// This is implemented as a list, which makes search O(n). If you reuse this
 36// for something with a large dataset, consider reimplementing with a Boost
 37// multimap based on both a map(key) and priority queue(last_use).
 38
 39template <class TKey, class TData>
 40class KeyUseTrackerNodeImpl
 41{
 42public:
 43	U64 mLastUse;
 44	U32 mUseCount;
 45	TKey mKey;
 46	TData mData;
 47
 48	KeyUseTrackerNodeImpl( TKey k, TData d ) :
 49		mLastUse(0),
 50		mUseCount(0),
 51		mKey( k ),
 52		mData( d )
 53	{
 54	}
 55};
 56
 57
 58template <class TKey, class TData>
 59class LLKeyUseTracker
 60{
 61	typedef KeyUseTrackerNodeImpl<TKey,TData> TKeyUseTrackerNode;
 62	typedef std::list<TKeyUseTrackerNode *> TKeyList;
 63	TKeyList mKeyList;
 64	U64 mMemUsecs;
 65	U64 mLastExpire;
 66	U32 mMaxCount;
 67	U32 mCount;
 68
 69	static U64 getTime()
 70	{
 71		// This function operates on a frame basis, not instantaneous.
 72		// We can rely on its output for determining first use in a
 73		// frame.
 74		return LLFrameTimer::getTotalTime();
 75	}
 76
 77	void ageKeys()
 78	{
 79		U64 now = getTime();
 80		if( now == mLastExpire )
 81		{
 82			return;
 83		}
 84		mLastExpire = now;
 85
 86		while( !mKeyList.empty() && (now - mKeyList.front()->mLastUse > mMemUsecs ) )
 87		{
 88			delete mKeyList.front();
 89			mKeyList.pop_front();
 90			mCount--;
 91		}
 92	}
 93
 94	TKeyUseTrackerNode *findNode( TKey key )
 95	{
 96		ageKeys();
 97
 98		typename TKeyList::iterator i;
 99		for( i = mKeyList.begin(); i != mKeyList.end(); i++ )
100		{
101			if( (*i)->mKey == key )
102				return *i;
103		}
104
105		return NULL;
106	}
107
108	TKeyUseTrackerNode *removeNode( TKey key )
109	{
110		TKeyUseTrackerNode *i;
111		i = findNode( key );
112		if( i )
113		{
114			mKeyList.remove( i );
115			mCount--;
116			return i;
117		}
118
119		return NULL;
120	}
121
122public:
123	LLKeyUseTracker( U32 memory_seconds, U32 max_count ) :
124		mLastExpire(0),
125		mMaxCount( max_count ),
126		mCount(0)
127	{
128		mMemUsecs = ((U64)memory_seconds) * 1000000;
129	}
130
131	~LLKeyUseTracker()
132	{
133		// Flush list
134		while( !mKeyList.empty() )
135		{
136			delete mKeyList.front();
137			mKeyList.pop_front();
138			mCount--;
139		}
140	}
141
142	void markUse( TKey key, TData data )
143	{
144		TKeyUseTrackerNode *node = removeNode( key );
145		if( !node )
146		{
147			node = new TKeyUseTrackerNode(key, data);
148		}
149		else
150		{
151			// Update data
152			node->mData = data;
153		}
154		node->mLastUse = getTime();
155		node->mUseCount++;
156		mKeyList.push_back( node );
157		mCount++;
158
159		// Too many items? Drop head
160		if( mCount > mMaxCount )
161		{
162			delete mKeyList.front();
163			mKeyList.pop_front();
164			mCount--;
165		}
166	}
167
168	void forgetKey( TKey key )
169	{
170		TKeyUseTrackerNode *node = removeNode( key );
171		if( node )
172		{
173			delete node;
174		}
175	}
176
177	U32 getUseCount( TKey key )
178	{
179		TKeyUseTrackerNode *node = findNode( key );
180		if( node )
181		{
182			return node->mUseCount;
183		}
184		return 0;
185	}
186
187	U64 getTimeSinceUse( TKey key )
188	{
189		TKeyUseTrackerNode *node = findNode( key );
190		if( node )
191		{
192			U64 now = getTime();
193			U64 delta = now - node->mLastUse;
194			return (U32)( delta / 1000000 );
195		}
196		return 0;
197	}
198
199	TData *getLastUseData( TKey key )
200	{
201		TKeyUseTrackerNode *node = findNode( key );
202		if( node )
203		{
204			return &node->mData;
205		}
206		return NULL;
207	}
208
209	U32 getKeyCount()
210	{
211		return mCount;
212	}
213};
214
215#endif