hashtab.c 19 KB

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