aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/linden/indra/llcommon/llstringtable.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'linden/indra/llcommon/llstringtable.cpp')
-rw-r--r--linden/indra/llcommon/llstringtable.cpp342
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
34LLStringTable gStringTable(32768);
35
36LLStringTable::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
67LLStringTable::~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
93static 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
115char* LLStringTable::checkString(const std::string& str)
116{
117 return checkString(str.c_str());
118}
119
120char* 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
133LLStringTableEntry* LLStringTable::checkStringEntry(const std::string& str)
134{
135 return checkStringEntry(str.c_str());
136}
137
138LLStringTableEntry* 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
183char* 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
189char* 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
203LLStringTableEntry* LLStringTable::addStringEntry(const std::string& str)
204{
205 return addStringEntry(str.c_str());
206}
207
208LLStringTableEntry* 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
276void 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