PageRenderTime 34ms CodeModel.GetById 17ms RepoModel.GetById 0ms 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
Possible License(s): LGPL-2.1
  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. #include "linden_common.h"
  28. #include "llstringtable.h"
  29. #include "llstl.h"
  30. LLStringTable gStringTable(32768);
  31. LLStringTableEntry::LLStringTableEntry(const char *str)
  32. : mString(NULL), mCount(1)
  33. {
  34. // Copy string
  35. U32 length = (U32)strlen(str) + 1; /*Flawfinder: ignore*/
  36. length = llmin(length, MAX_STRINGS_LENGTH);
  37. mString = new char[length];
  38. strncpy(mString, str, length); /*Flawfinder: ignore*/
  39. mString[length - 1] = 0;
  40. }
  41. LLStringTableEntry::~LLStringTableEntry()
  42. {
  43. delete [] mString;
  44. mCount = 0;
  45. }
  46. LLStringTable::LLStringTable(int tablesize)
  47. : mUniqueEntries(0)
  48. {
  49. S32 i;
  50. if (!tablesize)
  51. tablesize = 4096; // some arbitrary default
  52. // Make sure tablesize is power of 2
  53. for (i = 31; i>0; i--)
  54. {
  55. if (tablesize & (1<<i))
  56. {
  57. if (tablesize >= (3<<(i-1)))
  58. tablesize = (1<<(i+1));
  59. else
  60. tablesize = (1<<i);
  61. break;
  62. }
  63. }
  64. mMaxEntries = tablesize;
  65. #if !STRING_TABLE_HASH_MAP
  66. // ALlocate strings
  67. mStringList = new string_list_ptr_t[mMaxEntries];
  68. // Clear strings
  69. for (i = 0; i < mMaxEntries; i++)
  70. {
  71. mStringList[i] = NULL;
  72. }
  73. #endif
  74. }
  75. LLStringTable::~LLStringTable()
  76. {
  77. #if !STRING_TABLE_HASH_MAP
  78. if (mStringList)
  79. {
  80. for (S32 i = 0; i < mMaxEntries; i++)
  81. {
  82. if (mStringList[i])
  83. {
  84. string_list_t::iterator iter;
  85. for (iter = mStringList[i]->begin(); iter != mStringList[i]->end(); iter++)
  86. delete *iter; // *iter = (LLStringTableEntry*)
  87. }
  88. delete mStringList[i];
  89. }
  90. delete [] mStringList;
  91. mStringList = NULL;
  92. }
  93. #else
  94. // Need to clean up the string hash
  95. for_each(mStringHash.begin(), mStringHash.end(), DeletePairedPointer());
  96. mStringHash.clear();
  97. #endif
  98. }
  99. static U32 hash_my_string(const char *str, int max_entries)
  100. {
  101. U32 retval = 0;
  102. #if 0
  103. while (*str)
  104. {
  105. retval <<= 1;
  106. retval += *str++;
  107. }
  108. #else
  109. while (*str)
  110. {
  111. retval = (retval<<4) + *str;
  112. U32 x = (retval & 0xf0000000);
  113. if (x) retval = retval ^ (x>>24);
  114. retval = retval & (~x);
  115. str++;
  116. }
  117. #endif
  118. return (retval & (max_entries-1)); // max_entries is gauranteed to be power of 2
  119. }
  120. char* LLStringTable::checkString(const std::string& str)
  121. {
  122. return checkString(str.c_str());
  123. }
  124. char* LLStringTable::checkString(const char *str)
  125. {
  126. LLStringTableEntry* entry = checkStringEntry(str);
  127. if (entry)
  128. {
  129. return entry->mString;
  130. }
  131. else
  132. {
  133. return NULL;
  134. }
  135. }
  136. LLStringTableEntry* LLStringTable::checkStringEntry(const std::string& str)
  137. {
  138. return checkStringEntry(str.c_str());
  139. }
  140. LLStringTableEntry* LLStringTable::checkStringEntry(const char *str)
  141. {
  142. if (str)
  143. {
  144. char *ret_val;
  145. LLStringTableEntry *entry;
  146. U32 hash_value = hash_my_string(str, mMaxEntries);
  147. #if STRING_TABLE_HASH_MAP
  148. #if 1 // Microsoft
  149. string_hash_t::iterator lower = mStringHash.lower_bound(hash_value);
  150. string_hash_t::iterator upper = mStringHash.upper_bound(hash_value);
  151. #else // stlport
  152. std::pair<string_hash_t::iterator, string_hash_t::iterator> P = mStringHash.equal_range(hash_value);
  153. string_hash_t::iterator lower = P.first;
  154. string_hash_t::iterator upper = P.second;
  155. #endif
  156. for (string_hash_t::iterator iter = lower; iter != upper; iter++)
  157. {
  158. entry = iter->second;
  159. ret_val = entry->mString;
  160. if (!strncmp(ret_val, str, MAX_STRINGS_LENGTH))
  161. {
  162. return entry;
  163. }
  164. }
  165. #else
  166. string_list_t *strlist = mStringList[hash_value];
  167. if (strlist)
  168. {
  169. string_list_t::iterator iter;
  170. for (iter = strlist->begin(); iter != strlist->end(); iter++)
  171. {
  172. entry = *iter;
  173. ret_val = entry->mString;
  174. if (!strncmp(ret_val, str, MAX_STRINGS_LENGTH))
  175. {
  176. return entry;
  177. }
  178. }
  179. }
  180. #endif
  181. }
  182. return NULL;
  183. }
  184. char* LLStringTable::addString(const std::string& str)
  185. {
  186. //RN: safe to use temporary c_str since string is copied
  187. return addString(str.c_str());
  188. }
  189. char* LLStringTable::addString(const char *str)
  190. {
  191. LLStringTableEntry* entry = addStringEntry(str);
  192. if (entry)
  193. {
  194. return entry->mString;
  195. }
  196. else
  197. {
  198. return NULL;
  199. }
  200. }
  201. LLStringTableEntry* LLStringTable::addStringEntry(const std::string& str)
  202. {
  203. return addStringEntry(str.c_str());
  204. }
  205. LLStringTableEntry* LLStringTable::addStringEntry(const char *str)
  206. {
  207. if (str)
  208. {
  209. char *ret_val = NULL;
  210. LLStringTableEntry *entry;
  211. U32 hash_value = hash_my_string(str, mMaxEntries);
  212. #if STRING_TABLE_HASH_MAP
  213. #if 1 // Microsoft
  214. string_hash_t::iterator lower = mStringHash.lower_bound(hash_value);
  215. string_hash_t::iterator upper = mStringHash.upper_bound(hash_value);
  216. #else // stlport
  217. std::pair<string_hash_t::iterator, string_hash_t::iterator> P = mStringHash.equal_range(hash_value);
  218. string_hash_t::iterator lower = P.first;
  219. string_hash_t::iterator upper = P.second;
  220. #endif
  221. for (string_hash_t::iterator iter = lower; iter != upper; iter++)
  222. {
  223. entry = iter->second;
  224. ret_val = entry->mString;
  225. if (!strncmp(ret_val, str, MAX_STRINGS_LENGTH))
  226. {
  227. entry->incCount();
  228. return entry;
  229. }
  230. }
  231. // not found, so add!
  232. LLStringTableEntry* newentry = new LLStringTableEntry(str);
  233. ret_val = newentry->mString;
  234. mStringHash.insert(string_hash_t::value_type(hash_value, newentry));
  235. #else
  236. string_list_t *strlist = mStringList[hash_value];
  237. if (strlist)
  238. {
  239. string_list_t::iterator iter;
  240. for (iter = strlist->begin(); iter != strlist->end(); iter++)
  241. {
  242. entry = *iter;
  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. else
  252. {
  253. mStringList[hash_value] = new string_list_t;
  254. strlist = mStringList[hash_value];
  255. }
  256. // not found, so add!
  257. LLStringTableEntry *newentry = new LLStringTableEntry(str);
  258. //ret_val = newentry->mString;
  259. strlist->push_front(newentry);
  260. #endif
  261. mUniqueEntries++;
  262. return newentry;
  263. }
  264. else
  265. {
  266. return NULL;
  267. }
  268. }
  269. void LLStringTable::removeString(const char *str)
  270. {
  271. if (str)
  272. {
  273. char *ret_val;
  274. LLStringTableEntry *entry;
  275. U32 hash_value = hash_my_string(str, mMaxEntries);
  276. #if STRING_TABLE_HASH_MAP
  277. {
  278. #if 1 // Microsoft
  279. string_hash_t::iterator lower = mStringHash.lower_bound(hash_value);
  280. string_hash_t::iterator upper = mStringHash.upper_bound(hash_value);
  281. #else // stlport
  282. std::pair<string_hash_t::iterator, string_hash_t::iterator> P = mStringHash.equal_range(hash_value);
  283. string_hash_t::iterator lower = P.first;
  284. string_hash_t::iterator upper = P.second;
  285. #endif
  286. for (string_hash_t::iterator iter = lower; iter != upper; iter++)
  287. {
  288. entry = iter->second;
  289. ret_val = entry->mString;
  290. if (!strncmp(ret_val, str, MAX_STRINGS_LENGTH))
  291. {
  292. if (!entry->decCount())
  293. {
  294. mUniqueEntries--;
  295. if (mUniqueEntries < 0)
  296. {
  297. llerror("LLStringTable:removeString trying to remove too many strings!", 0);
  298. }
  299. delete iter->second;
  300. mStringHash.erase(iter);
  301. }
  302. return;
  303. }
  304. }
  305. }
  306. #else
  307. string_list_t *strlist = mStringList[hash_value];
  308. if (strlist)
  309. {
  310. string_list_t::iterator iter;
  311. for (iter = strlist->begin(); iter != strlist->end(); iter++)
  312. {
  313. entry = *iter;
  314. ret_val = entry->mString;
  315. if (!strncmp(ret_val, str, MAX_STRINGS_LENGTH))
  316. {
  317. if (!entry->decCount())
  318. {
  319. mUniqueEntries--;
  320. if (mUniqueEntries < 0)
  321. {
  322. llerror("LLStringTable:removeString trying to remove too many strings!", 0);
  323. }
  324. strlist->remove(entry);
  325. delete entry;
  326. }
  327. return;
  328. }
  329. }
  330. }
  331. #endif
  332. }
  333. }