diff options
Diffstat (limited to 'linden/indra/llcommon/llstringtable.cpp')
-rw-r--r-- | linden/indra/llcommon/llstringtable.cpp | 342 |
1 files changed, 342 insertions, 0 deletions
diff --git a/linden/indra/llcommon/llstringtable.cpp b/linden/indra/llcommon/llstringtable.cpp new file mode 100644 index 0000000..4a76ed6 --- /dev/null +++ b/linden/indra/llcommon/llstringtable.cpp | |||
@@ -0,0 +1,342 @@ | |||
1 | /** | ||
2 | * @file llstringtable.cpp | ||
3 | * @brief The LLStringTable class provides a _fast_ method for finding | ||
4 | * unique copies of strings. | ||
5 | * | ||
6 | * Copyright (c) 2001-2007, Linden Research, Inc. | ||
7 | * | ||
8 | * The source code in this file ("Source Code") is provided by Linden Lab | ||
9 | * to you under the terms of the GNU General Public License, version 2.0 | ||
10 | * ("GPL"), unless you have obtained a separate licensing agreement | ||
11 | * ("Other License"), formally executed by you and Linden Lab. Terms of | ||
12 | * the GPL can be found in doc/GPL-license.txt in this distribution, or | ||
13 | * online at http://secondlife.com/developers/opensource/gplv2 | ||
14 | * | ||
15 | * There are special exceptions to the terms and conditions of the GPL as | ||
16 | * it is applied to this Source Code. View the full text of the exception | ||
17 | * in the file doc/FLOSS-exception.txt in this software distribution, or | ||
18 | * online at http://secondlife.com/developers/opensource/flossexception | ||
19 | * | ||
20 | * By copying, modifying or distributing this software, you acknowledge | ||
21 | * that you have read and understood your obligations described above, | ||
22 | * and agree to abide by those obligations. | ||
23 | * | ||
24 | * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO | ||
25 | * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, | ||
26 | * COMPLETENESS OR PERFORMANCE. | ||
27 | */ | ||
28 | |||
29 | #include "linden_common.h" | ||
30 | |||
31 | #include "llstringtable.h" | ||
32 | #include "llstl.h" | ||
33 | |||
34 | LLStringTable gStringTable(32768); | ||
35 | |||
36 | LLStringTable::LLStringTable(int tablesize) | ||
37 | : mUniqueEntries(0) | ||
38 | { | ||
39 | S32 i; | ||
40 | if (!tablesize) | ||
41 | tablesize = 4096; // some arbitrary default | ||
42 | // Make sure tablesize is power of 2 | ||
43 | for (i = 31; i>0; i--) | ||
44 | { | ||
45 | if (tablesize & (1<<i)) | ||
46 | { | ||
47 | if (tablesize >= (3<<(i-1))) | ||
48 | tablesize = (1<<(i+1)); | ||
49 | else | ||
50 | tablesize = (1<<i); | ||
51 | break; | ||
52 | } | ||
53 | } | ||
54 | mMaxEntries = tablesize; | ||
55 | |||
56 | #if !STRING_TABLE_HASH_MAP | ||
57 | // ALlocate strings | ||
58 | mStringList = new string_list_ptr_t[mMaxEntries]; | ||
59 | // Clear strings | ||
60 | for (i = 0; i < mMaxEntries; i++) | ||
61 | { | ||
62 | mStringList[i] = NULL; | ||
63 | } | ||
64 | #endif | ||
65 | } | ||
66 | |||
67 | LLStringTable::~LLStringTable() | ||
68 | { | ||
69 | #if !STRING_TABLE_HASH_MAP | ||
70 | if (mStringList) | ||
71 | { | ||
72 | for (S32 i = 0; i < mMaxEntries; i++) | ||
73 | { | ||
74 | if (mStringList[i]) | ||
75 | { | ||
76 | string_list_t::iterator iter; | ||
77 | for (iter = mStringList[i]->begin(); iter != mStringList[i]->end(); iter++) | ||
78 | delete *iter; // *iter = (LLStringTableEntry*) | ||
79 | } | ||
80 | delete mStringList[i]; | ||
81 | } | ||
82 | delete [] mStringList; | ||
83 | mStringList = NULL; | ||
84 | } | ||
85 | #else | ||
86 | // Need to clean up the string hash | ||
87 | for_each(mStringHash.begin(), mStringHash.end(), DeletePairedPointer()); | ||
88 | mStringHash.clear(); | ||
89 | #endif | ||
90 | } | ||
91 | |||
92 | |||
93 | static U32 hash_my_string(const char *str, int max_entries) | ||
94 | { | ||
95 | U32 retval = 0; | ||
96 | #if 0 | ||
97 | while (*str) | ||
98 | { | ||
99 | retval <<= 1; | ||
100 | retval += *str++; | ||
101 | } | ||
102 | #else | ||
103 | while (*str) | ||
104 | { | ||
105 | retval = (retval<<4) + *str; | ||
106 | U32 x = (retval & 0xf0000000); | ||
107 | if (x) retval = retval ^ (x>>24); | ||
108 | retval = retval & (~x); | ||
109 | str++; | ||
110 | } | ||
111 | #endif | ||
112 | return (retval & (max_entries-1)); // max_entries is gauranteed to be power of 2 | ||
113 | } | ||
114 | |||
115 | char* LLStringTable::checkString(const std::string& str) | ||
116 | { | ||
117 | return checkString(str.c_str()); | ||
118 | } | ||
119 | |||
120 | char* LLStringTable::checkString(const char *str) | ||
121 | { | ||
122 | LLStringTableEntry* entry = checkStringEntry(str); | ||
123 | if (entry) | ||
124 | { | ||
125 | return entry->mString; | ||
126 | } | ||
127 | else | ||
128 | { | ||
129 | return NULL; | ||
130 | } | ||
131 | } | ||
132 | |||
133 | LLStringTableEntry* LLStringTable::checkStringEntry(const std::string& str) | ||
134 | { | ||
135 | return checkStringEntry(str.c_str()); | ||
136 | } | ||
137 | |||
138 | LLStringTableEntry* LLStringTable::checkStringEntry(const char *str) | ||
139 | { | ||
140 | if (str) | ||
141 | { | ||
142 | char *ret_val; | ||
143 | LLStringTableEntry *entry; | ||
144 | U32 hash_value = hash_my_string(str, mMaxEntries); | ||
145 | #if STRING_TABLE_HASH_MAP | ||
146 | #if 1 // Microsoft | ||
147 | string_hash_t::iterator lower = mStringHash.lower_bound(hash_value); | ||
148 | string_hash_t::iterator upper = mStringHash.upper_bound(hash_value); | ||
149 | #else // stlport | ||
150 | std::pair<string_hash_t::iterator, string_hash_t::iterator> P = mStringHash.equal_range(hash_value); | ||
151 | string_hash_t::iterator lower = P.first; | ||
152 | string_hash_t::iterator upper = P.second; | ||
153 | #endif | ||
154 | for (string_hash_t::iterator iter = lower; iter != upper; iter++) | ||
155 | { | ||
156 | entry = iter->second; | ||
157 | ret_val = entry->mString; | ||
158 | if (!strncmp(ret_val, str, MAX_STRINGS_LENGTH)) | ||
159 | { | ||
160 | return entry; | ||
161 | } | ||
162 | } | ||
163 | #else | ||
164 | string_list_t *strlist = mStringList[hash_value]; | ||
165 | if (strlist) | ||
166 | { | ||
167 | string_list_t::iterator iter; | ||
168 | for (iter = strlist->begin(); iter != strlist->end(); iter++) | ||
169 | { | ||
170 | entry = *iter; | ||
171 | ret_val = entry->mString; | ||
172 | if (!strncmp(ret_val, str, MAX_STRINGS_LENGTH)) | ||
173 | { | ||
174 | return entry; | ||
175 | } | ||
176 | } | ||
177 | } | ||
178 | #endif | ||
179 | } | ||
180 | return NULL; | ||
181 | } | ||
182 | |||
183 | char* LLStringTable::addString(const std::string& str) | ||
184 | { | ||
185 | //RN: safe to use temporary c_str since string is copied | ||
186 | return addString(str.c_str()); | ||
187 | } | ||
188 | |||
189 | char* LLStringTable::addString(const char *str) | ||
190 | { | ||
191 | |||
192 | LLStringTableEntry* entry = addStringEntry(str); | ||
193 | if (entry) | ||
194 | { | ||
195 | return entry->mString; | ||
196 | } | ||
197 | else | ||
198 | { | ||
199 | return NULL; | ||
200 | } | ||
201 | } | ||
202 | |||
203 | LLStringTableEntry* LLStringTable::addStringEntry(const std::string& str) | ||
204 | { | ||
205 | return addStringEntry(str.c_str()); | ||
206 | } | ||
207 | |||
208 | LLStringTableEntry* LLStringTable::addStringEntry(const char *str) | ||
209 | { | ||
210 | if (str) | ||
211 | { | ||
212 | char *ret_val = NULL; | ||
213 | LLStringTableEntry *entry; | ||
214 | U32 hash_value = hash_my_string(str, mMaxEntries); | ||
215 | #if STRING_TABLE_HASH_MAP | ||
216 | #if 1 // Microsoft | ||
217 | string_hash_t::iterator lower = mStringHash.lower_bound(hash_value); | ||
218 | string_hash_t::iterator upper = mStringHash.upper_bound(hash_value); | ||
219 | #else // stlport | ||
220 | std::pair<string_hash_t::iterator, string_hash_t::iterator> P = mStringHash.equal_range(hash_value); | ||
221 | string_hash_t::iterator lower = P.first; | ||
222 | string_hash_t::iterator upper = P.second; | ||
223 | #endif | ||
224 | for (string_hash_t::iterator iter = lower; iter != upper; iter++) | ||
225 | { | ||
226 | entry = iter->second; | ||
227 | ret_val = entry->mString; | ||
228 | if (!strncmp(ret_val, str, MAX_STRINGS_LENGTH)) | ||
229 | { | ||
230 | entry->incCount(); | ||
231 | return entry; | ||
232 | } | ||
233 | } | ||
234 | |||
235 | // not found, so add! | ||
236 | LLStringTableEntry* newentry = new LLStringTableEntry(str); | ||
237 | ret_val = newentry->mString; | ||
238 | mStringHash.insert(string_hash_t::value_type(hash_value, newentry)); | ||
239 | #else | ||
240 | string_list_t *strlist = mStringList[hash_value]; | ||
241 | |||
242 | if (strlist) | ||
243 | { | ||
244 | string_list_t::iterator iter; | ||
245 | for (iter = strlist->begin(); iter != strlist->end(); iter++) | ||
246 | { | ||
247 | entry = *iter; | ||
248 | ret_val = entry->mString; | ||
249 | if (!strncmp(ret_val, str, MAX_STRINGS_LENGTH)) | ||
250 | { | ||
251 | entry->incCount(); | ||
252 | return entry; | ||
253 | } | ||
254 | } | ||
255 | } | ||
256 | else | ||
257 | { | ||
258 | mStringList[hash_value] = new string_list_t; | ||
259 | strlist = mStringList[hash_value]; | ||
260 | } | ||
261 | |||
262 | // not found, so add! | ||
263 | LLStringTableEntry *newentry = new LLStringTableEntry(str); | ||
264 | //ret_val = newentry->mString; | ||
265 | strlist->push_front(newentry); | ||
266 | #endif | ||
267 | mUniqueEntries++; | ||
268 | return newentry; | ||
269 | } | ||
270 | else | ||
271 | { | ||
272 | return NULL; | ||
273 | } | ||
274 | } | ||
275 | |||
276 | void LLStringTable::removeString(const char *str) | ||
277 | { | ||
278 | if (str) | ||
279 | { | ||
280 | char *ret_val; | ||
281 | LLStringTableEntry *entry; | ||
282 | U32 hash_value = hash_my_string(str, mMaxEntries); | ||
283 | #if STRING_TABLE_HASH_MAP | ||
284 | { | ||
285 | #if 1 // Microsoft | ||
286 | string_hash_t::iterator lower = mStringHash.lower_bound(hash_value); | ||
287 | string_hash_t::iterator upper = mStringHash.upper_bound(hash_value); | ||
288 | #else // stlport | ||
289 | std::pair<string_hash_t::iterator, string_hash_t::iterator> P = mStringHash.equal_range(hash_value); | ||
290 | string_hash_t::iterator lower = P.first; | ||
291 | string_hash_t::iterator upper = P.second; | ||
292 | #endif | ||
293 | for (string_hash_t::iterator iter = lower; iter != upper; iter++) | ||
294 | { | ||
295 | entry = iter->second; | ||
296 | ret_val = entry->mString; | ||
297 | if (!strncmp(ret_val, str, MAX_STRINGS_LENGTH)) | ||
298 | { | ||
299 | if (!entry->decCount()) | ||
300 | { | ||
301 | mUniqueEntries--; | ||
302 | if (mUniqueEntries < 0) | ||
303 | { | ||
304 | llerror("LLStringTable:removeString trying to remove too many strings!", 0); | ||
305 | } | ||
306 | delete iter->second; | ||
307 | mStringHash.erase(iter); | ||
308 | } | ||
309 | return; | ||
310 | } | ||
311 | } | ||
312 | } | ||
313 | #else | ||
314 | string_list_t *strlist = mStringList[hash_value]; | ||
315 | |||
316 | if (strlist) | ||
317 | { | ||
318 | string_list_t::iterator iter; | ||
319 | for (iter = strlist->begin(); iter != strlist->end(); iter++) | ||
320 | { | ||
321 | entry = *iter; | ||
322 | ret_val = entry->mString; | ||
323 | if (!strncmp(ret_val, str, MAX_STRINGS_LENGTH)) | ||
324 | { | ||
325 | if (!entry->decCount()) | ||
326 | { | ||
327 | mUniqueEntries--; | ||
328 | if (mUniqueEntries < 0) | ||
329 | { | ||
330 | llerror("LLStringTable:removeString trying to remove too many strings!", 0); | ||
331 | } | ||
332 | strlist->remove(entry); | ||
333 | delete entry; | ||
334 | } | ||
335 | return; | ||
336 | } | ||
337 | } | ||
338 | } | ||
339 | #endif | ||
340 | } | ||
341 | } | ||
342 | |||