PageRenderTime 68ms CodeModel.GetById 16ms app.highlight 48ms RepoModel.GetById 2ms app.codeStats 0ms

/indra/llcommon/llstringtable.cpp

https://bitbucket.org/lindenlab/viewer-beta/
C++ | 358 lines | 298 code | 25 blank | 35 comment | 43 complexity | e425ef4541afddafc16fa27ba8071909 MD5 | raw file
  1/** 
  2 * @file llstringtable.cpp
  3 * @brief The LLStringTable class provides a _fast_ method for finding
  4 * unique copies of strings.
  5 *
  6 * $LicenseInfo:firstyear=2001&license=viewerlgpl$
  7 * Second Life Viewer Source Code
  8 * Copyright (C) 2010, Linden Research, Inc.
  9 * 
 10 * This library is free software; you can redistribute it and/or
 11 * modify it under the terms of the GNU Lesser General Public
 12 * License as published by the Free Software Foundation;
 13 * version 2.1 of the License only.
 14 * 
 15 * This library is distributed in the hope that it will be useful,
 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 18 * Lesser General Public License for more details.
 19 * 
 20 * You should have received a copy of the GNU Lesser General Public
 21 * License along with this library; if not, write to the Free Software
 22 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 23 * 
 24 * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
 25 * $/LicenseInfo$
 26 */
 27
 28#include "linden_common.h"
 29
 30#include "llstringtable.h"
 31#include "llstl.h"
 32
 33LLStringTable gStringTable(32768);
 34
 35LLStringTableEntry::LLStringTableEntry(const char *str)
 36: mString(NULL), mCount(1)
 37{
 38	// Copy string
 39	U32 length = (U32)strlen(str) + 1;	 /*Flawfinder: ignore*/
 40	length = llmin(length, MAX_STRINGS_LENGTH);
 41	mString = new char[length];
 42	strncpy(mString, str, length);	 /*Flawfinder: ignore*/
 43	mString[length - 1] = 0;
 44}
 45
 46LLStringTableEntry::~LLStringTableEntry()
 47{
 48	delete [] mString;
 49	mCount = 0;
 50}
 51
 52LLStringTable::LLStringTable(int tablesize)
 53: mUniqueEntries(0)
 54{
 55	S32 i;
 56	if (!tablesize)
 57		tablesize = 4096; // some arbitrary default
 58	// Make sure tablesize is power of 2
 59	for (i = 31; i>0; i--)
 60	{
 61		if (tablesize & (1<<i))
 62		{
 63			if (tablesize >= (3<<(i-1)))
 64				tablesize = (1<<(i+1));
 65			else
 66				tablesize = (1<<i);
 67			break;
 68		}
 69	}
 70	mMaxEntries = tablesize;
 71
 72#if !STRING_TABLE_HASH_MAP
 73	// ALlocate strings
 74	mStringList = new string_list_ptr_t[mMaxEntries];
 75	// Clear strings
 76	for (i = 0; i < mMaxEntries; i++)
 77	{
 78		mStringList[i] = NULL;
 79	}
 80#endif
 81}
 82
 83LLStringTable::~LLStringTable()
 84{
 85#if !STRING_TABLE_HASH_MAP
 86	if (mStringList)
 87	{
 88		for (S32 i = 0; i < mMaxEntries; i++)
 89		{
 90			if (mStringList[i])
 91			{
 92				string_list_t::iterator iter;
 93				for (iter = mStringList[i]->begin(); iter != mStringList[i]->end(); iter++)
 94					delete *iter; // *iter = (LLStringTableEntry*)
 95			}
 96			delete mStringList[i];
 97		}
 98		delete [] mStringList;
 99		mStringList = NULL;
100	}
101#else
102	// Need to clean up the string hash
103	for_each(mStringHash.begin(), mStringHash.end(), DeletePairedPointer());
104	mStringHash.clear();
105#endif
106}
107
108
109static U32 hash_my_string(const char *str, int max_entries)
110{
111	U32 retval = 0;
112#if 0
113	while (*str)
114	{
115		retval <<= 1;
116		retval += *str++;
117	}
118#else
119	while (*str)
120	{
121		retval = (retval<<4) + *str;
122		U32 x = (retval & 0xf0000000);
123		if (x) retval = retval ^ (x>>24);
124		retval = retval & (~x);
125		str++;
126	}
127#endif
128	return (retval & (max_entries-1)); // max_entries is gauranteed to be power of 2
129}
130
131char* LLStringTable::checkString(const std::string& str)
132{
133	return checkString(str.c_str());
134}
135
136char* LLStringTable::checkString(const char *str)
137{
138    LLStringTableEntry* entry = checkStringEntry(str);
139    if (entry)
140    {
141	return entry->mString;
142    }
143    else
144    {
145	return NULL;
146    }
147}
148
149LLStringTableEntry* LLStringTable::checkStringEntry(const std::string& str)
150{
151    return checkStringEntry(str.c_str());
152}
153
154LLStringTableEntry* LLStringTable::checkStringEntry(const char *str)
155{
156	if (str)
157	{
158		char *ret_val;
159		LLStringTableEntry	*entry;
160		U32					hash_value = hash_my_string(str, mMaxEntries);
161#if STRING_TABLE_HASH_MAP
162#if 1 // Microsoft
163		string_hash_t::iterator lower = mStringHash.lower_bound(hash_value);
164		string_hash_t::iterator upper = mStringHash.upper_bound(hash_value);
165#else // stlport
166		std::pair<string_hash_t::iterator, string_hash_t::iterator> P = mStringHash.equal_range(hash_value);
167		string_hash_t::iterator lower = P.first;
168		string_hash_t::iterator upper = P.second;
169#endif
170		for (string_hash_t::iterator iter = lower; iter != upper; iter++)
171		{
172			entry = iter->second;
173			ret_val = entry->mString;
174			if (!strncmp(ret_val, str, MAX_STRINGS_LENGTH))
175			{
176				return entry;
177			}
178		}
179#else
180		string_list_t		*strlist = mStringList[hash_value];
181		if (strlist)
182		{
183			string_list_t::iterator iter;
184			for (iter = strlist->begin(); iter != strlist->end(); iter++)
185			{
186				entry = *iter;
187				ret_val = entry->mString;
188				if (!strncmp(ret_val, str, MAX_STRINGS_LENGTH))
189				{
190					return entry;
191				}
192			}
193		}
194#endif
195	}
196	return NULL;
197}
198
199char* LLStringTable::addString(const std::string& str)
200{
201	//RN: safe to use temporary c_str since string is copied
202	return addString(str.c_str());
203}
204
205char* LLStringTable::addString(const char *str)
206{
207
208    LLStringTableEntry* entry = addStringEntry(str);
209    if (entry)
210    {
211	return entry->mString;
212    }
213    else
214    {
215	return NULL;
216    }
217}
218
219LLStringTableEntry* LLStringTable::addStringEntry(const std::string& str)
220{
221    return addStringEntry(str.c_str());
222}
223
224LLStringTableEntry* LLStringTable::addStringEntry(const char *str)
225{
226	if (str)
227	{
228		char *ret_val = NULL;
229		LLStringTableEntry	*entry;
230		U32					hash_value = hash_my_string(str, mMaxEntries);
231#if STRING_TABLE_HASH_MAP
232#if 1 // Microsoft
233		string_hash_t::iterator lower = mStringHash.lower_bound(hash_value);
234		string_hash_t::iterator upper = mStringHash.upper_bound(hash_value);
235#else // stlport
236		std::pair<string_hash_t::iterator, string_hash_t::iterator> P = mStringHash.equal_range(hash_value);
237		string_hash_t::iterator lower = P.first;
238		string_hash_t::iterator upper = P.second;
239#endif
240		for (string_hash_t::iterator iter = lower; iter != upper; iter++)
241		{
242			entry = iter->second;
243			ret_val = entry->mString;
244			if (!strncmp(ret_val, str, MAX_STRINGS_LENGTH))
245			{
246				entry->incCount();
247				return entry;
248			}
249		}
250
251		// not found, so add!
252		LLStringTableEntry* newentry = new LLStringTableEntry(str);
253		ret_val = newentry->mString;
254		mStringHash.insert(string_hash_t::value_type(hash_value, newentry));
255#else
256		string_list_t		*strlist = mStringList[hash_value];
257
258		if (strlist)
259		{
260			string_list_t::iterator iter;
261			for (iter = strlist->begin(); iter != strlist->end(); iter++)
262			{
263				entry = *iter;
264				ret_val = entry->mString;
265				if (!strncmp(ret_val, str, MAX_STRINGS_LENGTH))
266				{
267					entry->incCount();
268					return entry;
269				}
270			}
271		}
272		else
273		{
274			mStringList[hash_value] = new string_list_t;
275			strlist = mStringList[hash_value];
276		}
277
278		// not found, so add!
279		LLStringTableEntry *newentry = new LLStringTableEntry(str);
280		//ret_val = newentry->mString;
281		strlist->push_front(newentry);
282#endif
283		mUniqueEntries++;
284		return newentry;
285	}
286	else
287	{
288		return NULL;
289	}
290}
291
292void LLStringTable::removeString(const char *str)
293{
294	if (str)
295	{
296		char *ret_val;
297		LLStringTableEntry	*entry;
298		U32					hash_value = hash_my_string(str, mMaxEntries);
299#if STRING_TABLE_HASH_MAP
300		{
301#if 1 // Microsoft
302			string_hash_t::iterator lower = mStringHash.lower_bound(hash_value);
303			string_hash_t::iterator upper = mStringHash.upper_bound(hash_value);
304#else // stlport
305			std::pair<string_hash_t::iterator, string_hash_t::iterator> P = mStringHash.equal_range(hash_value);
306			string_hash_t::iterator lower = P.first;
307			string_hash_t::iterator upper = P.second;
308#endif
309			for (string_hash_t::iterator iter = lower; iter != upper; iter++)
310			{
311				entry = iter->second;
312				ret_val = entry->mString;
313				if (!strncmp(ret_val, str, MAX_STRINGS_LENGTH))
314				{
315					if (!entry->decCount())
316					{
317						mUniqueEntries--;
318						if (mUniqueEntries < 0)
319						{
320							llerror("LLStringTable:removeString trying to remove too many strings!", 0);
321						}
322						delete iter->second;
323						mStringHash.erase(iter);
324					}
325					return;
326				}
327			}
328		}
329#else
330		string_list_t		*strlist = mStringList[hash_value];
331
332		if (strlist)
333		{
334			string_list_t::iterator iter;
335			for (iter = strlist->begin(); iter != strlist->end(); iter++)
336			{
337				entry = *iter;
338				ret_val = entry->mString;
339				if (!strncmp(ret_val, str, MAX_STRINGS_LENGTH))
340				{
341					if (!entry->decCount())
342					{
343						mUniqueEntries--;
344						if (mUniqueEntries < 0)
345						{
346							llerror("LLStringTable:removeString trying to remove too many strings!", 0);
347						}
348						strlist->remove(entry);
349						delete entry;
350					}
351					return;
352				}
353			}
354		}
355#endif
356	}
357}
358