diff options
Diffstat (limited to 'linden/indra/llcommon/llkeyusetracker.h')
-rw-r--r-- | linden/indra/llcommon/llkeyusetracker.h | 220 |
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 | |||
44 | template <class TKey, class TData> | ||
45 | class KeyUseTrackerNodeImpl | ||
46 | { | ||
47 | public: | ||
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 | |||
63 | template <class TKey, class TData> | ||
64 | class 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 | |||
127 | public: | ||
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 | ||