hashtab.c 20 KB

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