hashtab.c 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908
  1. /*
  2. * Asterisk -- An open source telephony toolkit.
  3. *
  4. * Copyright (C) 2007, Digium, Inc.
  5. *
  6. * Steve Murphy <murf@digium.com>
  7. *
  8. * See http://www.asterisk.org for more information about
  9. * the Asterisk project. Please do not directly contact
  10. * any of the maintainers of this project for assistance;
  11. * the project provides a web site, mailing lists and IRC
  12. * channels for your use.
  13. *
  14. * This program is free software, distributed under the terms of
  15. * the GNU General Public License Version 2. See the LICENSE file
  16. * at the top of the source tree.
  17. */
  18. /*! \file
  19. *
  20. * \brief code to implement generic hash tables
  21. *
  22. * \author Steve Murphy <murf@digium.com>
  23. */
  24. /*** MODULEINFO
  25. <support_level>core</support_level>
  26. ***/
  27. #include "asterisk.h"
  28. ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
  29. #include <ctype.h>
  30. #include "asterisk/lock.h"
  31. #include "asterisk/frame.h"
  32. #include "asterisk/channel.h"
  33. #include "asterisk/cli.h"
  34. #include "asterisk/term.h"
  35. #include "asterisk/utils.h"
  36. #include "asterisk/threadstorage.h"
  37. #include "asterisk/linkedlists.h"
  38. #include "asterisk/hashtab.h"
  39. #ifndef __AST_DEBUG_MALLOC
  40. void *_ast_mem_backtrace_buffer[_AST_MEM_BACKTRACE_BUFLEN];
  41. #endif
  42. #if (defined(MALLOC_DEBUG) && !defined(STANDALONE))
  43. static void _ast_hashtab_resize(struct ast_hashtab *tab, const char *file, int lineno, const char *func);
  44. #define ast_hashtab_resize(a) _ast_hashtab_resize(a,__FILE__, __LINE__, __PRETTY_FUNCTION__)
  45. #else
  46. static void ast_hashtab_resize(struct ast_hashtab *tab);
  47. #endif
  48. static void *ast_hashtab_lookup_internal(struct ast_hashtab *tab, const void *obj, unsigned int h);
  49. /* some standard, default routines for general use */
  50. int ast_hashtab_compare_strings(const void *a, const void *b)
  51. {
  52. return strcmp(a, b);
  53. }
  54. int ast_hashtab_compare_strings_nocase(const void *a, const void *b)
  55. {
  56. return strcasecmp(a, b);
  57. }
  58. int ast_hashtab_compare_ints(const void *a, const void *b)
  59. {
  60. int ai = *((int *) a);
  61. int bi = *((int *) b);
  62. if (ai < bi)
  63. return -1;
  64. return !(ai == bi);
  65. }
  66. int ast_hashtab_compare_shorts(const void *a, const void *b)
  67. {
  68. short as = *((short *) a);
  69. short bs = *((short *) b);
  70. if (as < bs)
  71. return -1;
  72. return !(as == bs);
  73. }
  74. int ast_hashtab_resize_java(struct ast_hashtab *tab)
  75. {
  76. double loadfactor = (double) tab->hash_tab_elements / (double) tab->hash_tab_size;
  77. return (loadfactor > 0.75);
  78. }
  79. int ast_hashtab_resize_tight(struct ast_hashtab *tab)
  80. {
  81. return (tab->hash_tab_elements > tab->hash_tab_size); /* this is quicker than division */
  82. }
  83. int ast_hashtab_resize_none(struct ast_hashtab *tab) /* always return 0 -- no resizing */
  84. {
  85. return 0;
  86. }
  87. int ast_is_prime(int num)
  88. {
  89. int tnum, limit;
  90. if (!(num & 0x1)) /* even number -- not prime */
  91. return 0;
  92. /* Loop through ODD numbers starting with 3 */
  93. tnum = 3;
  94. limit = num;
  95. while (tnum < limit) {
  96. if (!(num % tnum))
  97. return 0;
  98. /* really, we only need to check sqrt(num) numbers */
  99. limit = num / tnum;
  100. /* we only check odd numbers */
  101. tnum = tnum + 2;
  102. }
  103. /* if we made it through the loop, the number is a prime */
  104. return 1;
  105. }
  106. int ast_hashtab_newsize_java(struct ast_hashtab *tab)
  107. {
  108. int i = (tab->hash_tab_size << 1); /* multiply by two */
  109. while (!ast_is_prime(i))
  110. i++;
  111. return i;
  112. }
  113. int ast_hashtab_newsize_tight(struct ast_hashtab *tab)
  114. {
  115. int x = (tab->hash_tab_size << 1);
  116. int i = (tab->hash_tab_size + x);
  117. while (!ast_is_prime(i))
  118. i++;
  119. return i;
  120. }
  121. int ast_hashtab_newsize_none(struct ast_hashtab *tab) /* always return current size -- no resizing */
  122. {
  123. return tab->hash_tab_size;
  124. }
  125. unsigned int ast_hashtab_hash_string(const void *obj)
  126. {
  127. unsigned char *str = (unsigned char *) obj;
  128. unsigned int total;
  129. for (total = 0; *str; str++) {
  130. unsigned int tmp = total;
  131. total <<= 1; /* multiply by 2 */
  132. total += tmp; /* multiply by 3 */
  133. total <<= 2; /* multiply by 12 */
  134. total += tmp; /* multiply by 13 */
  135. total += ((unsigned int)(*str));
  136. }
  137. return total;
  138. }
  139. unsigned int ast_hashtab_hash_string_sax(const void *obj) /* from Josh */
  140. {
  141. const unsigned char *str = obj;
  142. unsigned int total = 0, c = 0;
  143. while ((c = *str++))
  144. total ^= (total << 5) + (total >> 2) + (total << 10) + c;
  145. return total;
  146. }
  147. unsigned int ast_hashtab_hash_string_nocase(const void *obj)
  148. {
  149. const unsigned char *str = obj;
  150. unsigned int total;
  151. for (total = 0; *str; str++) {
  152. unsigned int tmp = total;
  153. unsigned int charval = toupper(*str);
  154. /* hopefully, the following is faster than multiplication by 7 */
  155. /* why do I go to this bother? A good compiler will do this
  156. anyway, if I say total *= 13 */
  157. /* BTW, tried *= 7, and it doesn't do as well in spreading things around! */
  158. total <<= 1; /* multiply by 2 */
  159. total += tmp; /* multiply by 3 */
  160. total <<= 2; /* multiply by 12 */
  161. total += tmp; /* multiply by 13 */
  162. total += (charval);
  163. }
  164. return total;
  165. }
  166. unsigned int ast_hashtab_hash_int(const int x)
  167. {
  168. return x;
  169. }
  170. unsigned int ast_hashtab_hash_short(const short x)
  171. {
  172. /* hmmmm.... modulus is best < 65535 !! */
  173. return x;
  174. }
  175. struct ast_hashtab *
  176. #if (defined(MALLOC_DEBUG) && !defined(STANDALONE))
  177. _ast_hashtab_create
  178. #else
  179. ast_hashtab_create
  180. #endif
  181. (int initial_buckets,
  182. int (*compare)(const void *a, const void *b),
  183. int (*resize)(struct ast_hashtab *),
  184. int (*newsize)(struct ast_hashtab *tab),
  185. unsigned int (*hash)(const void *obj),
  186. int do_locking
  187. #if (defined(MALLOC_DEBUG) && !defined(STANDALONE))
  188. , const char *file, int lineno, const char *function
  189. #endif
  190. )
  191. {
  192. struct ast_hashtab *ht;
  193. #if (defined(MALLOC_DEBUG) && !defined(STANDALONE))
  194. if (!(ht = __ast_calloc(1, sizeof(*ht), file, lineno, function)))
  195. #else
  196. if (!(ht = ast_calloc(1, sizeof(*ht))))
  197. #endif
  198. return NULL;
  199. while (!ast_is_prime(initial_buckets)) /* make sure this is prime */
  200. initial_buckets++;
  201. #if (defined(MALLOC_DEBUG) && !defined(STANDALONE))
  202. if (!(ht->array = __ast_calloc(initial_buckets, sizeof(*(ht->array)), file, lineno, function))) {
  203. #else
  204. if (!(ht->array = ast_calloc(initial_buckets, sizeof(*(ht->array))))) {
  205. #endif
  206. free(ht);
  207. return NULL;
  208. }
  209. ht->hash_tab_size = initial_buckets;
  210. ht->compare = compare;
  211. ht->resize = resize;
  212. ht->newsize = newsize;
  213. ht->hash = hash;
  214. ht->do_locking = do_locking;
  215. if (do_locking)
  216. ast_rwlock_init(&ht->lock);
  217. if (!ht->resize)
  218. ht->resize = ast_hashtab_resize_java;
  219. if (!ht->newsize)
  220. ht->newsize = ast_hashtab_newsize_java;
  221. return ht;
  222. }
  223. #if (defined(MALLOC_DEBUG) && !defined(STANDALONE))
  224. struct ast_hashtab *_ast_hashtab_dup(struct ast_hashtab *tab, void *(*obj_dup_func)(const void *obj), const char *file, int lineno, const char *func)
  225. #else
  226. struct ast_hashtab *ast_hashtab_dup(struct ast_hashtab *tab, void *(*obj_dup_func)(const void *obj))
  227. #endif
  228. {
  229. struct ast_hashtab *ht;
  230. unsigned int i;
  231. if (!(ht = ast_calloc(1, sizeof(*ht))))
  232. return NULL;
  233. if (!(ht->array =
  234. #if (defined(MALLOC_DEBUG) && !defined(STANDALONE))
  235. __ast_calloc(tab->hash_tab_size, sizeof(*(ht->array)), file, lineno, func)
  236. #else
  237. ast_calloc(tab->hash_tab_size, sizeof(*(ht->array)))
  238. #endif
  239. )) {
  240. free(ht);
  241. return NULL;
  242. }
  243. ht->hash_tab_size = tab->hash_tab_size;
  244. ht->compare = tab->compare;
  245. ht->resize = tab->resize;
  246. ht->newsize = tab->newsize;
  247. ht->hash = tab->hash;
  248. ht->do_locking = tab->do_locking;
  249. if (ht->do_locking)
  250. ast_rwlock_init(&ht->lock);
  251. /* now, dup the objects in the buckets and get them into the table */
  252. /* the fast way is to use the existing array index, and not have to hash
  253. the objects again */
  254. for (i = 0; i < ht->hash_tab_size; i++) {
  255. struct ast_hashtab_bucket *b = tab->array[i];
  256. while (b) {
  257. void *newobj = (*obj_dup_func)(b->object);
  258. if (newobj)
  259. #if (defined(MALLOC_DEBUG) && !defined(STANDALONE))
  260. _ast_hashtab_insert_immediate_bucket(ht, newobj, i, file, lineno, func);
  261. #else
  262. ast_hashtab_insert_immediate_bucket(ht, newobj, i);
  263. #endif
  264. b = b->next;
  265. }
  266. }
  267. return ht;
  268. }
  269. static void tlist_del_item(struct ast_hashtab_bucket **head, struct ast_hashtab_bucket *item)
  270. {
  271. /* item had better be in the list! or suffer the weirdness that occurs, later! */
  272. if (*head == item) { /* first item in the list */
  273. *head = item->tnext;
  274. if (item->tnext)
  275. item->tnext->tprev = NULL;
  276. } else {
  277. /* short circuit stuff */
  278. item->tprev->tnext = item->tnext;
  279. if (item->tnext)
  280. item->tnext->tprev = item->tprev;
  281. }
  282. }
  283. static void tlist_add_head(struct ast_hashtab_bucket **head, struct ast_hashtab_bucket *item)
  284. {
  285. if (*head) {
  286. item->tnext = *head;
  287. item->tprev = NULL;
  288. (*head)->tprev = item;
  289. *head = item;
  290. } else {
  291. /* the list is empty */
  292. *head = item;
  293. item->tprev = NULL;
  294. item->tnext = NULL;
  295. }
  296. }
  297. /* user-controlled hashtab locking. Create a hashtab without locking, then call the
  298. following locking routines yourself to lock the table between threads. */
  299. void ast_hashtab_wrlock(struct ast_hashtab *tab)
  300. {
  301. ast_rwlock_wrlock(&tab->lock);
  302. }
  303. void ast_hashtab_rdlock(struct ast_hashtab *tab)
  304. {
  305. ast_rwlock_rdlock(&tab->lock);
  306. }
  307. void ast_hashtab_initlock(struct ast_hashtab *tab)
  308. {
  309. ast_rwlock_init(&tab->lock);
  310. }
  311. void ast_hashtab_destroylock(struct ast_hashtab *tab)
  312. {
  313. ast_rwlock_destroy(&tab->lock);
  314. }
  315. void ast_hashtab_unlock(struct ast_hashtab *tab)
  316. {
  317. ast_rwlock_unlock(&tab->lock);
  318. }
  319. void ast_hashtab_destroy(struct ast_hashtab *tab, void (*objdestroyfunc)(void *obj))
  320. {
  321. /* this func will free the hash table and all its memory. It
  322. doesn't touch the objects stored in it */
  323. if (tab) {
  324. if (tab->do_locking)
  325. ast_rwlock_wrlock(&tab->lock);
  326. if (tab->array) {
  327. /* go thru and destroy the buckets */
  328. struct ast_hashtab_bucket *t;
  329. int i;
  330. while (tab->tlist) {
  331. t = tab->tlist;
  332. if (t->object && objdestroyfunc) {
  333. /* I cast this because I'm not going to MOD it, I'm going to DESTROY
  334. * it.
  335. */
  336. (*objdestroyfunc)((void *) t->object);
  337. }
  338. tlist_del_item(&(tab->tlist), tab->tlist);
  339. free(t);
  340. }
  341. for (i = 0; i < tab->hash_tab_size; i++) {
  342. /* Not totally necessary, but best to destroy old pointers */
  343. tab->array[i] = NULL;
  344. }
  345. free(tab->array);
  346. }
  347. if (tab->do_locking) {
  348. ast_rwlock_unlock(&tab->lock);
  349. ast_rwlock_destroy(&tab->lock);
  350. }
  351. free(tab);
  352. }
  353. }
  354. #if (defined(MALLOC_DEBUG) && !defined(STANDALONE))
  355. int _ast_hashtab_insert_immediate(struct ast_hashtab *tab, const void *obj, const char *file, int lineno, const char *func)
  356. #else
  357. int ast_hashtab_insert_immediate(struct ast_hashtab *tab, const void *obj)
  358. #endif
  359. {
  360. unsigned int h;
  361. int res=0;
  362. if (!tab || !obj)
  363. return res;
  364. if (tab->do_locking)
  365. ast_rwlock_wrlock(&tab->lock);
  366. h = (*tab->hash)(obj) % tab->hash_tab_size;
  367. #if (defined(MALLOC_DEBUG) && !defined(STANDALONE))
  368. res = _ast_hashtab_insert_immediate_bucket(tab, obj, h, file, lineno, func);
  369. #else
  370. res = ast_hashtab_insert_immediate_bucket(tab, obj, h);
  371. #endif
  372. if (tab->do_locking)
  373. ast_rwlock_unlock(&tab->lock);
  374. return res;
  375. }
  376. #if (defined(MALLOC_DEBUG) && !defined(STANDALONE))
  377. int _ast_hashtab_insert_immediate_bucket(struct ast_hashtab *tab, const void *obj, unsigned int h, const char *file, int lineno, const char *func)
  378. #else
  379. int ast_hashtab_insert_immediate_bucket(struct ast_hashtab *tab, const void *obj, unsigned int h)
  380. #endif
  381. {
  382. int c;
  383. struct ast_hashtab_bucket *b;
  384. if (!tab || !obj)
  385. return 0;
  386. for (c = 0, b = tab->array[h]; b; b= b->next)
  387. c++;
  388. if (c + 1 > tab->largest_bucket_size)
  389. tab->largest_bucket_size = c + 1;
  390. if (!(b =
  391. #if (defined(MALLOC_DEBUG) && !defined(STANDALONE))
  392. __ast_calloc(1, sizeof(*b), file, lineno, func)
  393. #else
  394. ast_calloc(1, sizeof(*b))
  395. #endif
  396. )) return 0;
  397. b->object = obj;
  398. b->next = tab->array[h];
  399. tab->array[h] = b;
  400. if (b->next)
  401. b->next->prev = b;
  402. tlist_add_head(&(tab->tlist), b);
  403. tab->hash_tab_elements++;
  404. if ((*tab->resize)(tab))
  405. ast_hashtab_resize(tab);
  406. return 1;
  407. }
  408. #if (defined(MALLOC_DEBUG) && !defined(STANDALONE))
  409. int _ast_hashtab_insert_safe(struct ast_hashtab *tab, const void *obj, const char *file, int lineno, const char *func)
  410. #else
  411. int ast_hashtab_insert_safe(struct ast_hashtab *tab, const void *obj)
  412. #endif
  413. {
  414. /* check to see if the element is already there; insert only if
  415. it is not there. */
  416. /* will force a resize if the resize func returns 1 */
  417. /* returns 1 on success, 0 if there's a problem, or it's already there. */
  418. unsigned int bucket = 0;
  419. if (tab->do_locking)
  420. ast_rwlock_wrlock(&tab->lock);
  421. if (!ast_hashtab_lookup_bucket(tab, obj, &bucket)) {
  422. #if (defined(MALLOC_DEBUG) && !defined(STANDALONE))
  423. int ret2 = _ast_hashtab_insert_immediate_bucket(tab, obj, bucket, file, lineno, func);
  424. #else
  425. int ret2 = ast_hashtab_insert_immediate_bucket(tab, obj, bucket);
  426. #endif
  427. if (tab->do_locking)
  428. ast_rwlock_unlock(&tab->lock);
  429. return ret2;
  430. }
  431. if (tab->do_locking)
  432. ast_rwlock_unlock(&tab->lock);
  433. return 0;
  434. }
  435. void *ast_hashtab_lookup(struct ast_hashtab *tab, const void *obj)
  436. {
  437. /* lookup this object in the hash table. return a ptr if found, or NULL if not */
  438. unsigned int h;
  439. void *ret;
  440. if (!tab || !obj)
  441. return 0;
  442. if (tab->do_locking)
  443. ast_rwlock_rdlock(&tab->lock);
  444. h = (*tab->hash)(obj) % tab->hash_tab_size;
  445. ret = ast_hashtab_lookup_internal(tab,obj,h);
  446. if (tab->do_locking)
  447. ast_rwlock_unlock(&tab->lock);
  448. return ret;
  449. }
  450. void *ast_hashtab_lookup_with_hash(struct ast_hashtab *tab, const void *obj, unsigned int hashval)
  451. {
  452. /* lookup this object in the hash table. return a ptr if found, or NULL if not */
  453. unsigned int h;
  454. void *ret;
  455. if (!tab || !obj)
  456. return 0;
  457. if (tab->do_locking)
  458. ast_rwlock_rdlock(&tab->lock);
  459. h = hashval % tab->hash_tab_size;
  460. ret = ast_hashtab_lookup_internal(tab,obj,h);
  461. if (tab->do_locking)
  462. ast_rwlock_unlock(&tab->lock);
  463. return ret;
  464. }
  465. void *ast_hashtab_lookup_bucket(struct ast_hashtab *tab, const void *obj, unsigned int *bucket)
  466. {
  467. /* lookup this object in the hash table. return a ptr if found, or NULL if not */
  468. unsigned int h;
  469. void *ret;
  470. if (!tab || !obj)
  471. return 0;
  472. h = (*tab->hash)(obj) % tab->hash_tab_size;
  473. ret = ast_hashtab_lookup_internal(tab,obj,h);
  474. *bucket = h;
  475. return ret;
  476. }
  477. static void *ast_hashtab_lookup_internal(struct ast_hashtab *tab, const void *obj, unsigned int h)
  478. {
  479. struct ast_hashtab_bucket *b;
  480. for (b = tab->array[h]; b; b = b->next) {
  481. if (!(*tab->compare)(obj,b->object)) {
  482. /* I can't touch obj in this func, but the outside world is welcome to */
  483. return (void*) b->object;
  484. }
  485. }
  486. return NULL;
  487. }
  488. void ast_hashtab_get_stats(struct ast_hashtab *tab, int *biggest_bucket_size, int *resize_count, int *num_objects, int *num_buckets)
  489. {
  490. /* returns key stats for the table */
  491. if (tab->do_locking)
  492. ast_rwlock_rdlock(&tab->lock);
  493. *biggest_bucket_size = tab->largest_bucket_size;
  494. *resize_count = tab->resize_count;
  495. *num_objects = tab->hash_tab_elements;
  496. *num_buckets = tab->hash_tab_size;
  497. if (tab->do_locking)
  498. ast_rwlock_unlock(&tab->lock);
  499. }
  500. /* this function returns the number of elements stored in the hashtab */
  501. int ast_hashtab_size(struct ast_hashtab *tab)
  502. {
  503. return tab->hash_tab_elements;
  504. }
  505. /* this function returns the size of the bucket array in the hashtab */
  506. int ast_hashtab_capacity( struct ast_hashtab *tab)
  507. {
  508. return tab->hash_tab_size;
  509. }
  510. /* the insert operation calls this, and is wrlock'd when it does. */
  511. /* if you want to call it, you should set the wrlock yourself */
  512. #if (defined(MALLOC_DEBUG) && !defined(STANDALONE))
  513. static void _ast_hashtab_resize(struct ast_hashtab *tab, const char *file, int lineno, const char *func)
  514. #else
  515. static void ast_hashtab_resize(struct ast_hashtab *tab)
  516. #endif
  517. {
  518. /* this function is called either internally, when the resize func returns 1, or
  519. externally by the user to force a resize of the hash table */
  520. int newsize = (*tab->newsize)(tab), i, c;
  521. unsigned int h;
  522. struct ast_hashtab_bucket *b,*bn;
  523. /* Since we keep a DLL of all the buckets in tlist,
  524. all we have to do is free the array, malloc a new one,
  525. and then go thru the tlist array and reassign them into
  526. the bucket arrayj.
  527. */
  528. for (i = 0; i < tab->hash_tab_size; i++) { /* don't absolutely have to do this, but
  529. why leave ptrs laying around */
  530. tab->array[i] = 0; /* erase old ptrs */
  531. }
  532. free(tab->array);
  533. if (!(tab->array =
  534. #if (defined(MALLOC_DEBUG) && !defined(STANDALONE))
  535. __ast_calloc(newsize, sizeof(*(tab->array)), file, lineno, func)
  536. #else
  537. ast_calloc(newsize, sizeof(*(tab->array)))
  538. #endif
  539. ))
  540. return;
  541. /* now sort the buckets into their rightful new slots */
  542. tab->resize_count++;
  543. tab->hash_tab_size = newsize;
  544. tab->largest_bucket_size = 0;
  545. for (b = tab->tlist; b; b = bn) {
  546. b->prev = 0;
  547. bn = b->tnext;
  548. h = (*tab->hash)(b->object) % tab->hash_tab_size;
  549. b->next = tab->array[h];
  550. if (b->next)
  551. b->next->prev = b;
  552. tab->array[h] = b;
  553. }
  554. /* recalc the largest bucket size */
  555. for (i = 0; i < tab->hash_tab_size; i++) {
  556. for (c = 0, b = tab->array[i]; b; b = b->next)
  557. c++;
  558. if (c > tab->largest_bucket_size)
  559. tab->largest_bucket_size = c;
  560. }
  561. }
  562. #if (defined(MALLOC_DEBUG) && !defined(STANDALONE))
  563. struct ast_hashtab_iter *_ast_hashtab_start_traversal(struct ast_hashtab *tab, const char *file, int lineno, const char *func)
  564. #else
  565. struct ast_hashtab_iter *ast_hashtab_start_traversal(struct ast_hashtab *tab)
  566. #endif
  567. {
  568. /* returns an iterator */
  569. struct ast_hashtab_iter *it;
  570. if (!(it =
  571. #if (defined(MALLOC_DEBUG) && !defined(STANDALONE))
  572. __ast_calloc(1, sizeof(*it), file, lineno, func)
  573. #else
  574. ast_calloc(1, sizeof(*it))
  575. #endif
  576. ))
  577. return NULL;
  578. it->next = tab->tlist;
  579. it->tab = tab;
  580. if (tab->do_locking)
  581. ast_rwlock_rdlock(&tab->lock);
  582. return it;
  583. }
  584. /* use this function to get a write lock */
  585. #if (defined(MALLOC_DEBUG) && !defined(STANDALONE))
  586. struct ast_hashtab_iter *_ast_hashtab_start_write_traversal(struct ast_hashtab *tab, const char *file, int lineno, const char *func)
  587. #else
  588. struct ast_hashtab_iter *ast_hashtab_start_write_traversal(struct ast_hashtab *tab)
  589. #endif
  590. {
  591. /* returns an iterator */
  592. struct ast_hashtab_iter *it;
  593. if (!(it =
  594. #if (defined(MALLOC_DEBUG) && !defined(STANDALONE))
  595. __ast_calloc(1, sizeof(*it), file, lineno, func)
  596. #else
  597. ast_calloc(1, sizeof(*it))
  598. #endif
  599. ))
  600. return NULL;
  601. it->next = tab->tlist;
  602. it->tab = tab;
  603. if (tab->do_locking)
  604. ast_rwlock_wrlock(&tab->lock);
  605. return it;
  606. }
  607. void ast_hashtab_end_traversal(struct ast_hashtab_iter *it)
  608. {
  609. if (it->tab->do_locking)
  610. ast_rwlock_unlock(&it->tab->lock);
  611. free(it);
  612. }
  613. void *ast_hashtab_next(struct ast_hashtab_iter *it)
  614. {
  615. /* returns the next object in the list, advances iter one step */
  616. struct ast_hashtab_bucket *retval;
  617. if (it && it->next) { /* there's a next in the bucket list */
  618. retval = it->next;
  619. it->next = retval->tnext;
  620. return (void *) retval->object;
  621. }
  622. return NULL;
  623. }
  624. static void *ast_hashtab_remove_object_internal(struct ast_hashtab *tab, struct ast_hashtab_bucket *b, int h)
  625. {
  626. const void *obj2;
  627. if (b->prev)
  628. b->prev->next = b->next;
  629. else
  630. tab->array[h] = b->next;
  631. if (b->next)
  632. b->next->prev = b->prev;
  633. tlist_del_item(&(tab->tlist), b);
  634. obj2 = b->object;
  635. b->object = b->next = (void*)2;
  636. free(b); /* free up the hashbucket */
  637. tab->hash_tab_elements--;
  638. #ifdef DEBUG
  639. {
  640. int c2;
  641. struct ast_hashtab_bucket *b2;
  642. /* do a little checking */
  643. for (c2 = 0, b2 = tab->tlist; b2; b2 = b2->tnext) {
  644. c2++;
  645. }
  646. if (c2 != tab->hash_tab_elements) {
  647. printf("Hey! we didn't delete right! there are %d elements in the list, and we expected %d\n",
  648. c2, tab->hash_tab_elements);
  649. }
  650. for (c2 = 0, b2 = tab->tlist; b2; b2 = b2->tnext) {
  651. unsigned int obj3 = (unsigned long) obj2;
  652. unsigned int b3 = (unsigned long) b;
  653. if (b2->object == obj2)
  654. printf("Hey-- you've still got a bucket pointing at ht_element %x\n", obj3);
  655. if (b2->next == b)
  656. printf("Hey-- you've still got a bucket with next ptr pointing to deleted bucket %x\n", b3);
  657. if (b2->prev == b)
  658. printf("Hey-- you've still got a bucket with prev ptr pointing to deleted bucket %x\n", b3);
  659. if (b2->tprev == b)
  660. printf("Hey-- you've still got a bucket with tprev ptr pointing to deleted bucket %x\n", b3);
  661. if (b2->tnext == b)
  662. printf("Hey-- you've still got a bucket with tnext ptr pointing to deleted bucket %x\n", b3);
  663. }
  664. }
  665. #endif
  666. return (void *) obj2; /* inside this code, the obj's are untouchable, but outside, they aren't */
  667. }
  668. void *ast_hashtab_remove_object_via_lookup(struct ast_hashtab *tab, void *obj)
  669. {
  670. /* looks up the object; removes the corresponding bucket */
  671. const void *obj2;
  672. if (!tab || !obj)
  673. return 0;
  674. if (tab->do_locking)
  675. ast_rwlock_wrlock(&tab->lock);
  676. obj2 = ast_hashtab_remove_object_via_lookup_nolock(tab,obj);
  677. if (tab->do_locking)
  678. ast_rwlock_unlock(&tab->lock);
  679. return (void *)obj2;
  680. }
  681. void *ast_hashtab_remove_object_via_lookup_nolock(struct ast_hashtab *tab, void *obj)
  682. {
  683. /* looks up the object; removes the corresponding bucket */
  684. unsigned int h;
  685. struct ast_hashtab_bucket *b;
  686. if (!tab || !obj)
  687. return 0;
  688. h = (*tab->hash)(obj) % tab->hash_tab_size;
  689. for (b = tab->array[h]; b; b = b->next) {
  690. if (!(*tab->compare)(obj, b->object)) {
  691. const void *obj2;
  692. obj2 = ast_hashtab_remove_object_internal(tab, b, h);
  693. return (void *) obj2; /* inside this code, the obj's are untouchable, but outside, they aren't */
  694. }
  695. }
  696. return 0;
  697. }
  698. void *ast_hashtab_remove_this_object(struct ast_hashtab *tab, void *obj)
  699. {
  700. /* looks up the object by hash and then comparing pts in bucket list instead of
  701. calling the compare routine; removes the bucket -- a slightly cheaper operation */
  702. /* looks up the object; removes the corresponding bucket */
  703. const void *obj2;
  704. if (!tab || !obj)
  705. return 0;
  706. if (tab->do_locking)
  707. ast_rwlock_wrlock(&tab->lock);
  708. obj2 = ast_hashtab_remove_this_object_nolock(tab,obj);
  709. if (tab->do_locking)
  710. ast_rwlock_unlock(&tab->lock);
  711. return (void *)obj2;
  712. }
  713. void *ast_hashtab_remove_this_object_nolock(struct ast_hashtab *tab, void *obj)
  714. {
  715. /* looks up the object by hash and then comparing pts in bucket list instead of
  716. calling the compare routine; removes the bucket -- a slightly cheaper operation */
  717. /* looks up the object; removes the corresponding bucket */
  718. unsigned int h;
  719. struct ast_hashtab_bucket *b;
  720. if (!tab || !obj)
  721. return 0;
  722. h = (*tab->hash)(obj) % tab->hash_tab_size;
  723. for (b = tab->array[h]; b; b = b->next) {
  724. if (obj == b->object) {
  725. const void *obj2;
  726. obj2 = ast_hashtab_remove_object_internal(tab, b, h);
  727. return (void *) obj2; /* inside this code, the obj's are untouchable, but outside, they aren't */
  728. }
  729. }
  730. return 0;
  731. }