heap.c 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327
  1. /*
  2. * Asterisk -- An open source telephony toolkit.
  3. *
  4. * Copyright (C) 2009, Digium, Inc.
  5. *
  6. * Russell Bryant <russell@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 Max Heap data structure
  21. *
  22. * \author Russell Bryant <russell@digium.com>
  23. */
  24. /*** MODULEINFO
  25. <support_level>core</support_level>
  26. ***/
  27. #include "asterisk.h"
  28. ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
  29. #include "asterisk/heap.h"
  30. #include "asterisk/utils.h"
  31. #include "asterisk/cli.h"
  32. struct ast_heap {
  33. ast_rwlock_t lock;
  34. ast_heap_cmp_fn cmp_fn;
  35. ssize_t index_offset;
  36. size_t cur_len;
  37. size_t avail_len;
  38. void **heap;
  39. };
  40. static inline int left_node(int i)
  41. {
  42. return 2 * i;
  43. }
  44. static inline int right_node(int i)
  45. {
  46. return 2 * i + 1;
  47. }
  48. static inline int parent_node(int i)
  49. {
  50. return i / 2;
  51. }
  52. static inline void *heap_get(struct ast_heap *h, int i)
  53. {
  54. return h->heap[i - 1];
  55. }
  56. static inline ssize_t get_index(struct ast_heap *h, void *elm)
  57. {
  58. ssize_t *index;
  59. if (h->index_offset < 0) {
  60. return -1;
  61. }
  62. index = elm + h->index_offset;
  63. return *index;
  64. }
  65. static inline void heap_set(struct ast_heap *h, int i, void *elm)
  66. {
  67. h->heap[i - 1] = elm;
  68. if (h->index_offset >= 0) {
  69. ssize_t *index = elm + h->index_offset;
  70. *index = i;
  71. }
  72. }
  73. int ast_heap_verify(struct ast_heap *h)
  74. {
  75. unsigned int i;
  76. for (i = 1; i <= (h->cur_len / 2); i++) {
  77. int l = left_node(i);
  78. int r = right_node(i);
  79. if (l <= h->cur_len) {
  80. if (h->cmp_fn(heap_get(h, i), heap_get(h, l)) < 0) {
  81. return -1;
  82. }
  83. }
  84. if (r <= h->cur_len) {
  85. if (h->cmp_fn(heap_get(h, i), heap_get(h, r)) < 0) {
  86. return -1;
  87. }
  88. }
  89. }
  90. return 0;
  91. }
  92. #ifdef __AST_DEBUG_MALLOC
  93. struct ast_heap *_ast_heap_create(unsigned int init_height, ast_heap_cmp_fn cmp_fn,
  94. ssize_t index_offset, const char *file, int lineno, const char *func)
  95. #else
  96. struct ast_heap *ast_heap_create(unsigned int init_height, ast_heap_cmp_fn cmp_fn,
  97. ssize_t index_offset)
  98. #endif
  99. {
  100. struct ast_heap *h;
  101. if (!cmp_fn) {
  102. ast_log(LOG_ERROR, "A comparison function must be provided\n");
  103. return NULL;
  104. }
  105. if (!init_height) {
  106. init_height = 8;
  107. }
  108. if (!(h =
  109. #ifdef __AST_DEBUG_MALLOC
  110. __ast_calloc(1, sizeof(*h), file, lineno, func)
  111. #else
  112. ast_calloc(1, sizeof(*h))
  113. #endif
  114. )) {
  115. return NULL;
  116. }
  117. h->cmp_fn = cmp_fn;
  118. h->index_offset = index_offset;
  119. h->avail_len = (1 << init_height) - 1;
  120. if (!(h->heap =
  121. #ifdef __AST_DEBUG_MALLOC
  122. __ast_malloc(h->avail_len * sizeof(void *), file, lineno, func)
  123. #else
  124. ast_malloc(h->avail_len * sizeof(void *))
  125. #endif
  126. )) {
  127. ast_free(h);
  128. return NULL;
  129. }
  130. ast_rwlock_init(&h->lock);
  131. return h;
  132. }
  133. struct ast_heap *ast_heap_destroy(struct ast_heap *h)
  134. {
  135. ast_free(h->heap);
  136. h->heap = NULL;
  137. ast_rwlock_destroy(&h->lock);
  138. ast_free(h);
  139. return NULL;
  140. }
  141. /*!
  142. * \brief Add a row of additional storage for the heap.
  143. */
  144. static int grow_heap(struct ast_heap *h
  145. #ifdef __AST_DEBUG_MALLOC
  146. , const char *file, int lineno, const char *func
  147. #endif
  148. )
  149. {
  150. void **new_heap;
  151. size_t new_len = h->avail_len * 2 + 1;
  152. #ifdef __AST_DEBUG_MALLOC
  153. new_heap = __ast_realloc(h->heap, new_len * sizeof(void *), file, lineno, func);
  154. #else
  155. new_heap = ast_realloc(h->heap, new_len * sizeof(void *));
  156. #endif
  157. if (!new_heap) {
  158. return -1;
  159. }
  160. h->heap = new_heap;
  161. h->avail_len = new_len;
  162. return 0;
  163. }
  164. static inline void heap_swap(struct ast_heap *h, int i, int j)
  165. {
  166. void *tmp;
  167. tmp = heap_get(h, i);
  168. heap_set(h, i, heap_get(h, j));
  169. heap_set(h, j, tmp);
  170. }
  171. static inline void max_heapify(struct ast_heap *h, int i)
  172. {
  173. for (;;) {
  174. int l = left_node(i);
  175. int r = right_node(i);
  176. int max;
  177. if (l <= h->cur_len && h->cmp_fn(heap_get(h, l), heap_get(h, i)) > 0) {
  178. max = l;
  179. } else {
  180. max = i;
  181. }
  182. if (r <= h->cur_len && h->cmp_fn(heap_get(h, r), heap_get(h, max)) > 0) {
  183. max = r;
  184. }
  185. if (max == i) {
  186. break;
  187. }
  188. heap_swap(h, i, max);
  189. i = max;
  190. }
  191. }
  192. static int bubble_up(struct ast_heap *h, int i)
  193. {
  194. while (i > 1 && h->cmp_fn(heap_get(h, parent_node(i)), heap_get(h, i)) < 0) {
  195. heap_swap(h, i, parent_node(i));
  196. i = parent_node(i);
  197. }
  198. return i;
  199. }
  200. #ifdef __AST_DEBUG_MALLOC
  201. int _ast_heap_push(struct ast_heap *h, void *elm, const char *file, int lineno, const char *func)
  202. #else
  203. int ast_heap_push(struct ast_heap *h, void *elm)
  204. #endif
  205. {
  206. if (h->cur_len == h->avail_len && grow_heap(h
  207. #ifdef __AST_DEBUG_MALLOC
  208. , file, lineno, func
  209. #endif
  210. )) {
  211. return -1;
  212. }
  213. heap_set(h, ++(h->cur_len), elm);
  214. bubble_up(h, h->cur_len);
  215. return 0;
  216. }
  217. static void *_ast_heap_remove(struct ast_heap *h, unsigned int index)
  218. {
  219. void *ret;
  220. if (!index || index > h->cur_len) {
  221. return NULL;
  222. }
  223. ret = heap_get(h, index);
  224. heap_set(h, index, heap_get(h, (h->cur_len)--));
  225. index = bubble_up(h, index);
  226. max_heapify(h, index);
  227. return ret;
  228. }
  229. void *ast_heap_remove(struct ast_heap *h, void *elm)
  230. {
  231. ssize_t i = get_index(h, elm);
  232. if (i == -1) {
  233. return NULL;
  234. }
  235. return _ast_heap_remove(h, i);
  236. }
  237. void *ast_heap_pop(struct ast_heap *h)
  238. {
  239. return _ast_heap_remove(h, 1);
  240. }
  241. void *ast_heap_peek(struct ast_heap *h, unsigned int index)
  242. {
  243. if (!h->cur_len || !index || index > h->cur_len) {
  244. return NULL;
  245. }
  246. return heap_get(h, index);
  247. }
  248. size_t ast_heap_size(struct ast_heap *h)
  249. {
  250. return h->cur_len;
  251. }
  252. int __ast_heap_wrlock(struct ast_heap *h, const char *file, const char *func, int line)
  253. {
  254. return __ast_rwlock_wrlock(file, line, func, &h->lock, "&h->lock");
  255. }
  256. int __ast_heap_rdlock(struct ast_heap *h, const char *file, const char *func, int line)
  257. {
  258. return __ast_rwlock_rdlock(file, line, func, &h->lock, "&h->lock");
  259. }
  260. int __ast_heap_unlock(struct ast_heap *h, const char *file, const char *func, int line)
  261. {
  262. return __ast_rwlock_unlock(file, line, func, &h->lock, "&h->lock");
  263. }