PageRenderTime 81ms CodeModel.GetById 34ms RepoModel.GetById 0ms app.codeStats 1ms

/js/lib/Socket.IO-node/support/expresso/deps/jscoverage/js/jshash.cpp

http://github.com/onedayitwillmake/RealtimeMultiplayerNodeJs
C++ | 476 lines | 350 code | 56 blank | 70 comment | 57 complexity | 3fa1df16ff7543d4c526f28746ce1903 MD5 | raw file
Possible License(s): GPL-2.0, LGPL-2.1, MPL-2.0-no-copyleft-exception, BSD-3-Clause
  1. /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
  2. *
  3. * ***** BEGIN LICENSE BLOCK *****
  4. * Version: MPL 1.1/GPL 2.0/LGPL 2.1
  5. *
  6. * The contents of this file are subject to the Mozilla Public License Version
  7. * 1.1 (the "License"); you may not use this file except in compliance with
  8. * the License. You may obtain a copy of the License at
  9. * http://www.mozilla.org/MPL/
  10. *
  11. * Software distributed under the License is distributed on an "AS IS" basis,
  12. * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  13. * for the specific language governing rights and limitations under the
  14. * License.
  15. *
  16. * The Original Code is Mozilla Communicator client code, released
  17. * March 31, 1998.
  18. *
  19. * The Initial Developer of the Original Code is
  20. * Netscape Communications Corporation.
  21. * Portions created by the Initial Developer are Copyright (C) 1998
  22. * the Initial Developer. All Rights Reserved.
  23. *
  24. * Contributor(s):
  25. *
  26. * Alternatively, the contents of this file may be used under the terms of
  27. * either of the GNU General Public License Version 2 or later (the "GPL"),
  28. * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  29. * in which case the provisions of the GPL or the LGPL are applicable instead
  30. * of those above. If you wish to allow use of your version of this file only
  31. * under the terms of either the GPL or the LGPL, and not to allow others to
  32. * use your version of this file under the terms of the MPL, indicate your
  33. * decision by deleting the provisions above and replace them with the notice
  34. * and other provisions required by the GPL or the LGPL. If you do not delete
  35. * the provisions above, a recipient may use your version of this file under
  36. * the terms of any one of the MPL, the GPL or the LGPL.
  37. *
  38. * ***** END LICENSE BLOCK ***** */
  39. /*
  40. * PR hash table package.
  41. */
  42. #include "jsstddef.h"
  43. #include <stdlib.h>
  44. #include <string.h>
  45. #include "jstypes.h"
  46. #include "jsbit.h"
  47. #include "jsutil.h" /* Added by JSIFY */
  48. #include "jshash.h" /* Added by JSIFY */
  49. /* Compute the number of buckets in ht */
  50. #define NBUCKETS(ht) JS_BIT(JS_HASH_BITS - (ht)->shift)
  51. /* The smallest table has 16 buckets */
  52. #define MINBUCKETSLOG2 4
  53. #define MINBUCKETS JS_BIT(MINBUCKETSLOG2)
  54. /* Compute the maximum entries given n buckets that we will tolerate, ~90% */
  55. #define OVERLOADED(n) ((n) - ((n) >> 3))
  56. /* Compute the number of entries below which we shrink the table by half */
  57. #define UNDERLOADED(n) (((n) > MINBUCKETS) ? ((n) >> 2) : 0)
  58. /*
  59. ** Stubs for default hash allocator ops.
  60. */
  61. static void *
  62. DefaultAllocTable(void *pool, size_t size)
  63. {
  64. return malloc(size);
  65. }
  66. static void
  67. DefaultFreeTable(void *pool, void *item)
  68. {
  69. free(item);
  70. }
  71. static JSHashEntry *
  72. DefaultAllocEntry(void *pool, const void *key)
  73. {
  74. return (JSHashEntry*) malloc(sizeof(JSHashEntry));
  75. }
  76. static void
  77. DefaultFreeEntry(void *pool, JSHashEntry *he, uintN flag)
  78. {
  79. if (flag == HT_FREE_ENTRY)
  80. free(he);
  81. }
  82. static JSHashAllocOps defaultHashAllocOps = {
  83. DefaultAllocTable, DefaultFreeTable,
  84. DefaultAllocEntry, DefaultFreeEntry
  85. };
  86. JS_PUBLIC_API(JSHashTable *)
  87. JS_NewHashTable(uint32 n, JSHashFunction keyHash,
  88. JSHashComparator keyCompare, JSHashComparator valueCompare,
  89. JSHashAllocOps *allocOps, void *allocPriv)
  90. {
  91. JSHashTable *ht;
  92. size_t nb;
  93. if (n <= MINBUCKETS) {
  94. n = MINBUCKETSLOG2;
  95. } else {
  96. n = JS_CeilingLog2(n);
  97. if ((int32)n < 0)
  98. return NULL;
  99. }
  100. if (!allocOps) allocOps = &defaultHashAllocOps;
  101. ht = (JSHashTable*) allocOps->allocTable(allocPriv, sizeof *ht);
  102. if (!ht)
  103. return NULL;
  104. memset(ht, 0, sizeof *ht);
  105. ht->shift = JS_HASH_BITS - n;
  106. n = JS_BIT(n);
  107. nb = n * sizeof(JSHashEntry *);
  108. ht->buckets = (JSHashEntry**) allocOps->allocTable(allocPriv, nb);
  109. if (!ht->buckets) {
  110. allocOps->freeTable(allocPriv, ht);
  111. return NULL;
  112. }
  113. memset(ht->buckets, 0, nb);
  114. ht->keyHash = keyHash;
  115. ht->keyCompare = keyCompare;
  116. ht->valueCompare = valueCompare;
  117. ht->allocOps = allocOps;
  118. ht->allocPriv = allocPriv;
  119. return ht;
  120. }
  121. JS_PUBLIC_API(void)
  122. JS_HashTableDestroy(JSHashTable *ht)
  123. {
  124. uint32 i, n;
  125. JSHashEntry *he, **hep;
  126. JSHashAllocOps *allocOps = ht->allocOps;
  127. void *allocPriv = ht->allocPriv;
  128. n = NBUCKETS(ht);
  129. for (i = 0; i < n; i++) {
  130. hep = &ht->buckets[i];
  131. while ((he = *hep) != NULL) {
  132. *hep = he->next;
  133. allocOps->freeEntry(allocPriv, he, HT_FREE_ENTRY);
  134. }
  135. }
  136. #ifdef DEBUG
  137. memset(ht->buckets, 0xDB, n * sizeof ht->buckets[0]);
  138. #endif
  139. allocOps->freeTable(allocPriv, ht->buckets);
  140. #ifdef DEBUG
  141. memset(ht, 0xDB, sizeof *ht);
  142. #endif
  143. allocOps->freeTable(allocPriv, ht);
  144. }
  145. /*
  146. * Multiplicative hash, from Knuth 6.4.
  147. */
  148. #define BUCKET_HEAD(ht, keyHash) \
  149. (&(ht)->buckets[((keyHash) * JS_GOLDEN_RATIO) >> (ht)->shift])
  150. JS_PUBLIC_API(JSHashEntry **)
  151. JS_HashTableRawLookup(JSHashTable *ht, JSHashNumber keyHash, const void *key)
  152. {
  153. JSHashEntry *he, **hep, **hep0;
  154. #ifdef JS_HASHMETER
  155. ht->nlookups++;
  156. #endif
  157. hep = hep0 = BUCKET_HEAD(ht, keyHash);
  158. while ((he = *hep) != NULL) {
  159. if (he->keyHash == keyHash && ht->keyCompare(key, he->key)) {
  160. /* Move to front of chain if not already there */
  161. if (hep != hep0) {
  162. *hep = he->next;
  163. he->next = *hep0;
  164. *hep0 = he;
  165. }
  166. return hep0;
  167. }
  168. hep = &he->next;
  169. #ifdef JS_HASHMETER
  170. ht->nsteps++;
  171. #endif
  172. }
  173. return hep;
  174. }
  175. static JSBool
  176. Resize(JSHashTable *ht, uint32 newshift)
  177. {
  178. size_t nb, nentries, i;
  179. JSHashEntry **oldbuckets, *he, *next, **hep;
  180. #ifdef DEBUG
  181. size_t nold = NBUCKETS(ht);
  182. #endif
  183. JS_ASSERT(newshift < JS_HASH_BITS);
  184. nb = (size_t)1 << (JS_HASH_BITS - newshift);
  185. /* Integer overflow protection. */
  186. if (nb > (size_t)-1 / sizeof(JSHashEntry*))
  187. return JS_FALSE;
  188. nb *= sizeof(JSHashEntry*);
  189. oldbuckets = ht->buckets;
  190. ht->buckets = (JSHashEntry**)ht->allocOps->allocTable(ht->allocPriv, nb);
  191. if (!ht->buckets) {
  192. ht->buckets = oldbuckets;
  193. return JS_FALSE;
  194. }
  195. memset(ht->buckets, 0, nb);
  196. ht->shift = newshift;
  197. nentries = ht->nentries;
  198. for (i = 0; nentries != 0; i++) {
  199. for (he = oldbuckets[i]; he; he = next) {
  200. JS_ASSERT(nentries != 0);
  201. --nentries;
  202. next = he->next;
  203. hep = BUCKET_HEAD(ht, he->keyHash);
  204. /*
  205. * Since he comes from the old table, it must be unique and we
  206. * simply add it to the head of bucket chain without chain lookup.
  207. */
  208. he->next = *hep;
  209. *hep = he;
  210. }
  211. }
  212. #ifdef DEBUG
  213. memset(oldbuckets, 0xDB, nold * sizeof oldbuckets[0]);
  214. #endif
  215. ht->allocOps->freeTable(ht->allocPriv, oldbuckets);
  216. return JS_TRUE;
  217. }
  218. JS_PUBLIC_API(JSHashEntry *)
  219. JS_HashTableRawAdd(JSHashTable *ht, JSHashEntry **hep,
  220. JSHashNumber keyHash, const void *key, void *value)
  221. {
  222. uint32 n;
  223. JSHashEntry *he;
  224. /* Grow the table if it is overloaded */
  225. n = NBUCKETS(ht);
  226. if (ht->nentries >= OVERLOADED(n)) {
  227. if (!Resize(ht, ht->shift - 1))
  228. return NULL;
  229. #ifdef JS_HASHMETER
  230. ht->ngrows++;
  231. #endif
  232. hep = JS_HashTableRawLookup(ht, keyHash, key);
  233. }
  234. /* Make a new key value entry */
  235. he = ht->allocOps->allocEntry(ht->allocPriv, key);
  236. if (!he)
  237. return NULL;
  238. he->keyHash = keyHash;
  239. he->key = key;
  240. he->value = value;
  241. he->next = *hep;
  242. *hep = he;
  243. ht->nentries++;
  244. return he;
  245. }
  246. JS_PUBLIC_API(JSHashEntry *)
  247. JS_HashTableAdd(JSHashTable *ht, const void *key, void *value)
  248. {
  249. JSHashNumber keyHash;
  250. JSHashEntry *he, **hep;
  251. keyHash = ht->keyHash(key);
  252. hep = JS_HashTableRawLookup(ht, keyHash, key);
  253. if ((he = *hep) != NULL) {
  254. /* Hit; see if values match */
  255. if (ht->valueCompare(he->value, value)) {
  256. /* key,value pair is already present in table */
  257. return he;
  258. }
  259. if (he->value)
  260. ht->allocOps->freeEntry(ht->allocPriv, he, HT_FREE_VALUE);
  261. he->value = value;
  262. return he;
  263. }
  264. return JS_HashTableRawAdd(ht, hep, keyHash, key, value);
  265. }
  266. JS_PUBLIC_API(void)
  267. JS_HashTableRawRemove(JSHashTable *ht, JSHashEntry **hep, JSHashEntry *he)
  268. {
  269. uint32 n;
  270. *hep = he->next;
  271. ht->allocOps->freeEntry(ht->allocPriv, he, HT_FREE_ENTRY);
  272. /* Shrink table if it's underloaded */
  273. n = NBUCKETS(ht);
  274. if (--ht->nentries < UNDERLOADED(n)) {
  275. Resize(ht, ht->shift + 1);
  276. #ifdef JS_HASHMETER
  277. ht->nshrinks++;
  278. #endif
  279. }
  280. }
  281. JS_PUBLIC_API(JSBool)
  282. JS_HashTableRemove(JSHashTable *ht, const void *key)
  283. {
  284. JSHashNumber keyHash;
  285. JSHashEntry *he, **hep;
  286. keyHash = ht->keyHash(key);
  287. hep = JS_HashTableRawLookup(ht, keyHash, key);
  288. if ((he = *hep) == NULL)
  289. return JS_FALSE;
  290. /* Hit; remove element */
  291. JS_HashTableRawRemove(ht, hep, he);
  292. return JS_TRUE;
  293. }
  294. JS_PUBLIC_API(void *)
  295. JS_HashTableLookup(JSHashTable *ht, const void *key)
  296. {
  297. JSHashNumber keyHash;
  298. JSHashEntry *he, **hep;
  299. keyHash = ht->keyHash(key);
  300. hep = JS_HashTableRawLookup(ht, keyHash, key);
  301. if ((he = *hep) != NULL) {
  302. return he->value;
  303. }
  304. return NULL;
  305. }
  306. /*
  307. ** Iterate over the entries in the hash table calling func for each
  308. ** entry found. Stop if "f" says to (return value & JS_ENUMERATE_STOP).
  309. ** Return a count of the number of elements scanned.
  310. */
  311. JS_PUBLIC_API(int)
  312. JS_HashTableEnumerateEntries(JSHashTable *ht, JSHashEnumerator f, void *arg)
  313. {
  314. JSHashEntry *he, **hep, **bucket;
  315. uint32 nlimit, n, nbuckets, newlog2;
  316. int rv;
  317. nlimit = ht->nentries;
  318. n = 0;
  319. for (bucket = ht->buckets; n != nlimit; ++bucket) {
  320. hep = bucket;
  321. while ((he = *hep) != NULL) {
  322. JS_ASSERT(n < nlimit);
  323. rv = f(he, n, arg);
  324. n++;
  325. if (rv & HT_ENUMERATE_REMOVE) {
  326. *hep = he->next;
  327. ht->allocOps->freeEntry(ht->allocPriv, he, HT_FREE_ENTRY);
  328. --ht->nentries;
  329. } else {
  330. hep = &he->next;
  331. }
  332. if (rv & HT_ENUMERATE_STOP) {
  333. goto out;
  334. }
  335. }
  336. }
  337. out:
  338. /* Shrink table if removal of entries made it underloaded */
  339. if (ht->nentries != nlimit) {
  340. JS_ASSERT(ht->nentries < nlimit);
  341. nbuckets = NBUCKETS(ht);
  342. if (MINBUCKETS < nbuckets && ht->nentries < UNDERLOADED(nbuckets)) {
  343. newlog2 = JS_CeilingLog2(ht->nentries);
  344. if (newlog2 < MINBUCKETSLOG2)
  345. newlog2 = MINBUCKETSLOG2;
  346. /* Check that we really shrink the table. */
  347. JS_ASSERT(JS_HASH_BITS - ht->shift > newlog2);
  348. Resize(ht, JS_HASH_BITS - newlog2);
  349. }
  350. }
  351. return (int)n;
  352. }
  353. #ifdef JS_HASHMETER
  354. #include <stdio.h>
  355. JS_PUBLIC_API(void)
  356. JS_HashTableDumpMeter(JSHashTable *ht, JSHashEnumerator dump, FILE *fp)
  357. {
  358. double sqsum, mean, sigma;
  359. uint32 nchains, nbuckets;
  360. uint32 i, n, maxChain, maxChainLen;
  361. JSHashEntry *he;
  362. sqsum = 0;
  363. nchains = 0;
  364. maxChain = maxChainLen = 0;
  365. nbuckets = NBUCKETS(ht);
  366. for (i = 0; i < nbuckets; i++) {
  367. he = ht->buckets[i];
  368. if (!he)
  369. continue;
  370. nchains++;
  371. for (n = 0; he; he = he->next)
  372. n++;
  373. sqsum += n * n;
  374. if (n > maxChainLen) {
  375. maxChainLen = n;
  376. maxChain = i;
  377. }
  378. }
  379. mean = JS_MeanAndStdDev(nchains, ht->nentries, sqsum, &sigma);
  380. fprintf(fp, "\nHash table statistics:\n");
  381. fprintf(fp, " number of lookups: %u\n", ht->nlookups);
  382. fprintf(fp, " number of entries: %u\n", ht->nentries);
  383. fprintf(fp, " number of grows: %u\n", ht->ngrows);
  384. fprintf(fp, " number of shrinks: %u\n", ht->nshrinks);
  385. fprintf(fp, " mean steps per hash: %g\n", (double)ht->nsteps
  386. / ht->nlookups);
  387. fprintf(fp, "mean hash chain length: %g\n", mean);
  388. fprintf(fp, " standard deviation: %g\n", sigma);
  389. fprintf(fp, " max hash chain length: %u\n", maxChainLen);
  390. fprintf(fp, " max hash chain: [%u]\n", maxChain);
  391. for (he = ht->buckets[maxChain], i = 0; he; he = he->next, i++)
  392. if (dump(he, i, fp) != HT_ENUMERATE_NEXT)
  393. break;
  394. }
  395. #endif /* JS_HASHMETER */
  396. JS_PUBLIC_API(int)
  397. JS_HashTableDump(JSHashTable *ht, JSHashEnumerator dump, FILE *fp)
  398. {
  399. int count;
  400. count = JS_HashTableEnumerateEntries(ht, dump, fp);
  401. #ifdef JS_HASHMETER
  402. JS_HashTableDumpMeter(ht, dump, fp);
  403. #endif
  404. return count;
  405. }
  406. JS_PUBLIC_API(JSHashNumber)
  407. JS_HashString(const void *key)
  408. {
  409. JSHashNumber h;
  410. const unsigned char *s;
  411. h = 0;
  412. for (s = (const unsigned char *)key; *s; s++)
  413. h = JS_ROTATE_LEFT32(h, 4) ^ *s;
  414. return h;
  415. }
  416. JS_PUBLIC_API(int)
  417. JS_CompareValues(const void *v1, const void *v2)
  418. {
  419. return v1 == v2;
  420. }