erlang各种有用的函数包括一些有用nif封装,还有一些性能测试case。
Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.

318 строки
6.1 KiB

5 лет назад
  1. // Licensed under the Apache License, Version 2.0 (the "License"); you may not
  2. // use this file except in compliance with the License. You may obtain a copy of
  3. // the License at
  4. //
  5. // http://www.apache.org/licenses/LICENSE-2.0
  6. //
  7. // Unless required by applicable law or agreed to in writing, software
  8. // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
  9. // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
  10. // License for the specific language governing permissions and limitations under
  11. // the License.
  12. #include <assert.h>
  13. #include <stdint.h>
  14. #include <stdio.h>
  15. #include <stdlib.h>
  16. #include <string.h>
  17. #include "hqueue.h"
  18. struct hqueue
  19. {
  20. int version;
  21. uint32_t idx;
  22. uint32_t max_elems;
  23. uint32_t heap_size;
  24. hqnode_t* heap; // one based index
  25. };
  26. struct hqnode
  27. {
  28. double priority;
  29. void* value;
  30. };
  31. static inline void
  32. hqueue_exchange(hqueue_t* hqueue, int i, int j)
  33. {
  34. hqnode_t tmp;
  35. tmp = hqueue->heap[i];
  36. hqueue->heap[i] = hqueue->heap[j];
  37. hqueue->heap[j] = tmp;
  38. return;
  39. }
  40. static inline int
  41. hqueue_less(hqueue_t* hqueue, int i, int j)
  42. {
  43. return hqueue->heap[i].priority < hqueue->heap[j].priority;
  44. }
  45. static void
  46. hqueue_fix_up(hqueue_t* hqueue, int k)
  47. {
  48. while(k > 1 && hqueue_less(hqueue, k/2, k)) {
  49. hqueue_exchange(hqueue, k/2, k);
  50. k = k/2;
  51. }
  52. return;
  53. }
  54. static void
  55. hqueue_fix_down(hqueue_t* hqueue, int k)
  56. {
  57. int j;
  58. int n = hqueue->idx;
  59. while(2*k <= n) {
  60. j = 2*k;
  61. if(j < n && hqueue_less(hqueue, j, j+1)) {
  62. j++;
  63. }
  64. if(!hqueue_less(hqueue, k, j)) {
  65. break;
  66. }
  67. hqueue_exchange(hqueue, k, j);
  68. k = j;
  69. }
  70. return;
  71. }
  72. hqueue_t*
  73. hqueue_new(uint32_t max_elems, uint32_t heap_size)
  74. {
  75. hqueue_t* hqueue = NULL;
  76. size_t total_heap_size;
  77. if(max_elems == 0 || heap_size == 0) {
  78. return NULL;
  79. }
  80. if(max_elems < heap_size) {
  81. heap_size = max_elems;
  82. }
  83. hqueue = HQUEUE_ALLOC(sizeof(hqueue_t));
  84. if(hqueue == NULL) {
  85. return NULL;
  86. }
  87. memset(hqueue, '\0', sizeof(hqueue_t));
  88. hqueue->version = HQ_VERSION;
  89. hqueue->max_elems = max_elems;
  90. hqueue->heap_size = heap_size;
  91. hqueue->idx = 0;
  92. total_heap_size = sizeof(hqnode_t) * (hqueue->heap_size+1);
  93. hqueue->heap = (hqnode_t*) HQUEUE_ALLOC(total_heap_size);
  94. if(hqueue->heap == NULL ) {
  95. HQUEUE_FREE(hqueue);
  96. return NULL;
  97. }
  98. memset(hqueue->heap, '\0', total_heap_size);
  99. return hqueue;
  100. }
  101. void
  102. hqueue_free(hqueue_t* hqueue)
  103. {
  104. HQUEUE_FREE(hqueue->heap);
  105. HQUEUE_FREE(hqueue);
  106. return;
  107. }
  108. void
  109. hqueue_free2(hqueue_t* hqueue, void (*free_node)(void* node))
  110. {
  111. uint32_t i;
  112. for(i = 1; i < hqueue->heap_size + 1; i++) {
  113. if(i <= hqueue->idx) {
  114. free_node(hqueue->heap[i].value);
  115. } else {
  116. assert(hqueue->heap[i].value == NULL && "inactive elements must be NULL");
  117. }
  118. }
  119. hqueue_free(hqueue);
  120. return;
  121. }
  122. // Extraction order is undefined for entries with duplicate priorities
  123. int
  124. hqueue_extract_max(hqueue_t* hqueue, double* priority, void** value)
  125. {
  126. if(hqueue->idx <= 0) {
  127. return 0;
  128. }
  129. hqueue_exchange(hqueue, 1, hqueue->idx);
  130. *priority = hqueue->heap[hqueue->idx].priority;
  131. *value = hqueue->heap[hqueue->idx].value;
  132. hqueue->heap[hqueue->idx].value = NULL;
  133. hqueue->idx--; // heap uses one based index, so we decrement after
  134. hqueue_fix_down(hqueue, 1);
  135. return 1;
  136. }
  137. void
  138. hqueue_get_elem(hqueue_t* hqueue, uint32_t idx, double *priority, void** value)
  139. {
  140. *priority = hqueue->heap[idx].priority;
  141. *value = hqueue->heap[idx].value;
  142. return;
  143. }
  144. static int
  145. hqueue_maybe_resize(hqueue_t* hqueue)
  146. {
  147. uint32_t min_resize;
  148. if(hqueue->idx + 1 > hqueue->heap_size) {
  149. if(hqueue->idx * HQ_SCALE_FACTOR > hqueue->max_elems) {
  150. min_resize = hqueue->max_elems;
  151. } else {
  152. min_resize = hqueue->idx * HQ_SCALE_FACTOR;
  153. }
  154. return hqueue_resize_heap(hqueue, min_resize);
  155. }
  156. return 1;
  157. }
  158. int
  159. hqueue_insert(hqueue_t* hqueue, double priority, void* value)
  160. {
  161. if(hqueue->idx >= hqueue->max_elems) {
  162. return 0;
  163. }
  164. if(!hqueue_maybe_resize(hqueue)) {
  165. return 0;
  166. }
  167. hqueue->idx++; // heap uses one based index, so we increment first
  168. hqueue->heap[hqueue->idx].priority = priority;
  169. hqueue->heap[hqueue->idx].value = value;
  170. hqueue_fix_up(hqueue, hqueue->idx);
  171. return 1;
  172. }
  173. uint32_t
  174. hqueue_size(hqueue_t* hqueue)
  175. {
  176. return hqueue->idx;
  177. }
  178. uint32_t
  179. hqueue_heap_size(hqueue_t* hqueue)
  180. {
  181. return hqueue->heap_size;
  182. }
  183. uint32_t
  184. hqueue_max_elems(hqueue_t* hqueue)
  185. {
  186. return hqueue->max_elems;
  187. }
  188. void
  189. hqueue_scale_by(hqueue_t* hqueue, double factor)
  190. {
  191. uint32_t i;
  192. for(i = 1; i <= hqueue->idx && i <= hqueue->heap_size; i++) {
  193. hqueue->heap[i].priority *= factor;
  194. }
  195. return;
  196. }
  197. uint32_t
  198. hqueue_resize_heap(hqueue_t* hqueue, uint32_t new_heap_size)
  199. {
  200. uint32_t old_heap_size;
  201. size_t total_heap_size;
  202. hqnode_t* tmp_heap;
  203. uint32_t i;
  204. if(hqueue->idx > new_heap_size) {
  205. return 0;
  206. }
  207. total_heap_size = sizeof(hqnode_t) * (new_heap_size+1);
  208. old_heap_size = hqueue->heap_size;
  209. if((tmp_heap = (hqnode_t*) HQUEUE_ALLOC(total_heap_size)) == NULL) {
  210. return 0;
  211. }
  212. memset(tmp_heap, '\0', total_heap_size);
  213. for(i = 1; i <= hqueue->idx && i <= old_heap_size; i++) {
  214. if(i <= hqueue->idx) {
  215. tmp_heap[i] = hqueue->heap[i];
  216. hqueue->heap[i].value = NULL;
  217. } else {
  218. assert(hqueue->heap[i].value == NULL &&
  219. "unexpected NULL element during heap resize");
  220. }
  221. }
  222. HQUEUE_FREE(hqueue->heap);
  223. hqueue->heap = tmp_heap;
  224. hqueue->heap_size = new_heap_size;
  225. return old_heap_size;
  226. }
  227. int
  228. hqueue_set_max_elems(hqueue_t* hqueue, uint32_t new_max_elems)
  229. {
  230. uint32_t old_max_elems;
  231. if(hqueue->heap_size > new_max_elems) {
  232. if(!hqueue_resize_heap(hqueue, new_max_elems)) {
  233. return 0;
  234. }
  235. }
  236. old_max_elems = hqueue->max_elems;
  237. hqueue->max_elems = new_max_elems;
  238. return old_max_elems;
  239. }