aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/linden/indra/llcommon/llkeyusetracker.h
diff options
context:
space:
mode:
Diffstat (limited to 'linden/indra/llcommon/llkeyusetracker.h')
-rw-r--r--linden/indra/llcommon/llkeyusetracker.h220
1 files changed, 220 insertions, 0 deletions
diff --git a/linden/indra/llcommon/llkeyusetracker.h b/linden/indra/llcommon/llkeyusetracker.h
new file mode 100644
index 0000000..c37ba24
--- /dev/null
+++ b/linden/indra/llcommon/llkeyusetracker.h
@@ -0,0 +1,220 @@
1/**
2 * @file llkeyusetracker.h
3 * @brief Declaration of the LLKeyUseTracker class.
4 *
5 * $LicenseInfo:firstyear=2003&license=viewergpl$
6 *
7 * Copyright (c) 2003-2008, Linden Research, Inc.
8 *
9 * Second Life Viewer Source Code
10 * The source code in this file ("Source Code") is provided by Linden Lab
11 * to you under the terms of the GNU General Public License, version 2.0
12 * ("GPL"), unless you have obtained a separate licensing agreement
13 * ("Other License"), formally executed by you and Linden Lab. Terms of
14 * the GPL can be found in doc/GPL-license.txt in this distribution, or
15 * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
16 *
17 * There are special exceptions to the terms and conditions of the GPL as
18 * it is applied to this Source Code. View the full text of the exception
19 * in the file doc/FLOSS-exception.txt in this software distribution, or
20 * online at http://secondlifegrid.net/programs/open_source/licensing/flossexception
21 *
22 * By copying, modifying or distributing this software, you acknowledge
23 * that you have read and understood your obligations described above,
24 * and agree to abide by those obligations.
25 *
26 * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
27 * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
28 * COMPLETENESS OR PERFORMANCE.
29 * $/LicenseInfo$
30 */
31
32#ifndef LL_KEYUSETRACKER_H
33#define LL_KEYUSETRACKER_H
34
35// This is a generic cache for an arbitrary data type indexed against an
36// arbitrary key type. The cache length is determined by expiration time
37// tince against last use and set size. The age of elements and the size
38// of the cache are queryable.
39//
40// This is implemented as a list, which makes search O(n). If you reuse this
41// for something with a large dataset, consider reimplementing with a Boost
42// multimap based on both a map(key) and priority queue(last_use).
43
44template <class TKey, class TData>
45class KeyUseTrackerNodeImpl
46{
47public:
48 U64 mLastUse;
49 U32 mUseCount;
50 TKey mKey;
51 TData mData;
52
53 KeyUseTrackerNodeImpl( TKey k, TData d ) :
54 mLastUse(0),
55 mUseCount(0),
56 mKey( k ),
57 mData( d )
58 {
59 }
60};
61
62
63template <class TKey, class TData>
64class LLKeyUseTracker
65{
66 typedef KeyUseTrackerNodeImpl<TKey,TData> TKeyUseTrackerNode;
67 typedef std::list<TKeyUseTrackerNode *> TKeyList;
68 TKeyList mKeyList;
69 U64 mMemUsecs;
70 U64 mLastExpire;
71 U32 mMaxCount;
72 U32 mCount;
73
74 static U64 getTime()
75 {
76 // This function operates on a frame basis, not instantaneous.
77 // We can rely on its output for determining first use in a
78 // frame.
79 return LLFrameTimer::getTotalTime();
80 }
81
82 void ageKeys()
83 {
84 U64 now = getTime();
85 if( now == mLastExpire )
86 {
87 return;
88 }
89 mLastExpire = now;
90
91 while( !mKeyList.empty() && (now - mKeyList.front()->mLastUse > mMemUsecs ) )
92 {
93 delete mKeyList.front();
94 mKeyList.pop_front();
95 mCount--;
96 }
97 }
98
99 TKeyUseTrackerNode *findNode( TKey key )
100 {
101 ageKeys();
102
103 typename TKeyList::iterator i;
104 for( i = mKeyList.begin(); i != mKeyList.end(); i++ )
105 {
106 if( (*i)->mKey == key )
107 return *i;
108 }
109
110 return NULL;
111 }
112
113 TKeyUseTrackerNode *removeNode( TKey key )
114 {
115 TKeyUseTrackerNode *i;
116 i = findNode( key );
117 if( i )
118 {
119 mKeyList.remove( i );
120 mCount--;
121 return i;
122 }
123
124 return NULL;
125 }
126
127public:
128 LLKeyUseTracker( U32 memory_seconds, U32 max_count ) :
129 mLastExpire(0),
130 mMaxCount( max_count ),
131 mCount(0)
132 {
133 mMemUsecs = ((U64)memory_seconds) * 1000000;
134 }
135
136 ~LLKeyUseTracker()
137 {
138 // Flush list
139 while( !mKeyList.empty() )
140 {
141 delete mKeyList.front();
142 mKeyList.pop_front();
143 mCount--;
144 }
145 }
146
147 void markUse( TKey key, TData data )
148 {
149 TKeyUseTrackerNode *node = removeNode( key );
150 if( !node )
151 {
152 node = new TKeyUseTrackerNode(key, data);
153 }
154 else
155 {
156 // Update data
157 node->mData = data;
158 }
159 node->mLastUse = getTime();
160 node->mUseCount++;
161 mKeyList.push_back( node );
162 mCount++;
163
164 // Too many items? Drop head
165 if( mCount > mMaxCount )
166 {
167 delete mKeyList.front();
168 mKeyList.pop_front();
169 mCount--;
170 }
171 }
172
173 void forgetKey( TKey key )
174 {
175 TKeyUseTrackerNode *node = removeNode( key );
176 if( node )
177 {
178 delete node;
179 }
180 }
181
182 U32 getUseCount( TKey key )
183 {
184 TKeyUseTrackerNode *node = findNode( key );
185 if( node )
186 {
187 return node->mUseCount;
188 }
189 return 0;
190 }
191
192 U64 getTimeSinceUse( TKey key )
193 {
194 TKeyUseTrackerNode *node = findNode( key );
195 if( node )
196 {
197 U64 now = getTime();
198 U64 delta = now - node->mLastUse;
199 return (U32)( delta / 1000000 );
200 }
201 return 0;
202 }
203
204 TData *getLastUseData( TKey key )
205 {
206 TKeyUseTrackerNode *node = findNode( key );
207 if( node )
208 {
209 return &node->mData;
210 }
211 return NULL;
212 }
213
214 U32 getKeyCount()
215 {
216 return mCount;
217 }
218};
219
220#endif