erlang各种有用的函数包括一些有用nif封装,还有一些性能测试case。
Nie możesz wybrać więcej, niż 25 tematów Tematy muszą się zaczynać od litery lub cyfry, mogą zawierać myślniki ('-') i mogą mieć do 35 znaków.

257 wiersze
6.6 KiB

5 lat temu
  1. #include "epqueue.h"
  2. #include "epqueue_item.h"
  3. #include "epqueue_nif.h"
  4. #include "priority_queue.h"
  5. #include "critical_section.h"
  6. #include "nif_utils.h"
  7. #include "macros.h"
  8. #include <string.h>
  9. struct epqueue
  10. {
  11. CriticalSection* crit;
  12. PriorityQueue* queue;
  13. ERL_NIF_TERM owner_pid;
  14. };
  15. void nif_epqueue_free(ErlNifEnv* env, void* obj)
  16. {
  17. UNUSED(env);
  18. epqueue* qinst = static_cast<epqueue*>(obj);
  19. if(qinst->queue)
  20. delete qinst->queue;
  21. if(qinst->crit)
  22. delete qinst->crit;
  23. }
  24. bool internal_insert(epqueue* q, queue_item* item)
  25. {
  26. CritScope ss(q->crit);
  27. return q->queue->insert(item);
  28. }
  29. bool internal_remove(epqueue* q, queue_item* item)
  30. {
  31. CritScope ss(q->crit);
  32. if(item->heap_index == -1)
  33. return false;
  34. return q->queue->remove(item, item->heap_index);
  35. }
  36. queue_item* internal_pop(epqueue* q)
  37. {
  38. CritScope ss(q->crit);
  39. return static_cast<queue_item*>(q->queue->pop());
  40. }
  41. bool is_owner(ErlNifEnv* env, epqueue* q)
  42. {
  43. if(q->owner_pid == 0)
  44. return true;
  45. ErlNifPid self;
  46. if(enif_self(env, &self) && !enif_is_identical(q->owner_pid, enif_make_pid(env, &self)))
  47. return false;
  48. return true;
  49. }
  50. ERL_NIF_TERM nif_epqueue_new(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
  51. {
  52. UNUSED(argc);
  53. epqueue_data* data = static_cast<epqueue_data*>(enif_priv_data(env));
  54. if(!enif_is_list(env, argv[0]))
  55. return enif_make_badarg(env);
  56. bool use_lock = false;
  57. ERL_NIF_TERM settings_list = argv[0];
  58. ERL_NIF_TERM head;
  59. while(enif_get_list_cell(env, settings_list, &head, &settings_list))
  60. {
  61. const ERL_NIF_TERM *items;
  62. int arity;
  63. if(!enif_get_tuple(env, head, &arity, &items) || arity != 2)
  64. return enif_make_badarg(env);
  65. if(enif_is_identical(items[0], ATOMS.atomGlobalLock))
  66. use_lock = enif_is_identical(items[1], ATOMS.atomTrue);
  67. else
  68. return enif_make_badarg(env);
  69. }
  70. epqueue* qinst = static_cast<epqueue*>(enif_alloc_resource(data->resPQueueInstance, sizeof(epqueue)));
  71. if(qinst == NULL)
  72. return make_error(env, "enif_alloc_resource failed");
  73. memset(qinst, 0, sizeof(epqueue));
  74. if(use_lock)
  75. {
  76. qinst->crit = new EnifCriticalSection();
  77. qinst->owner_pid = 0;
  78. }
  79. else
  80. {
  81. qinst->crit = new NullCriticalSection();
  82. ErlNifPid self;
  83. enif_self(env, &self);
  84. qinst->owner_pid = enif_make_pid(env, &self);
  85. }
  86. qinst->queue = new PriorityQueue(epqueue_item_less, epqueue_item_update_pos, enif_release_resource);
  87. ERL_NIF_TERM term = enif_make_resource(env, qinst);
  88. enif_release_resource(qinst);
  89. return enif_make_tuple2(env, ATOMS.atomOk, term);
  90. }
  91. ERL_NIF_TERM nif_epqueue_size(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
  92. {
  93. UNUSED(argc);
  94. epqueue_data* data = static_cast<epqueue_data*>(enif_priv_data(env));
  95. epqueue* inst = NULL;
  96. if(!enif_get_resource(env, argv[0], data->resPQueueInstance, reinterpret_cast<void**>(&inst)))
  97. return enif_make_badarg(env);
  98. if(!is_owner(env, inst))
  99. return enif_make_badarg(env);
  100. CritScope ss(inst->crit);
  101. return enif_make_int(env, inst->queue->size());
  102. }
  103. ERL_NIF_TERM nif_epqueue_insert(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
  104. {
  105. UNUSED(argc);
  106. epqueue_data* data = static_cast<epqueue_data*>(enif_priv_data(env));
  107. epqueue* inst;
  108. ErlNifBinary data_bin;
  109. long priority;
  110. if(!enif_get_resource(env, argv[0], data->resPQueueInstance, reinterpret_cast<void**>(&inst)))
  111. return enif_make_badarg(env);
  112. if(!is_owner(env, inst))
  113. return enif_make_badarg(env);
  114. if(!enif_get_long(env, argv[2], &priority))
  115. return enif_make_badarg(env);
  116. if(!enif_term_to_binary(env, argv[1], &data_bin))
  117. return enif_make_badarg(env);
  118. queue_item* item = epqueue_item_new(data, data_bin, priority);
  119. if(item == NULL)
  120. {
  121. enif_release_binary(&data_bin);
  122. return make_error(env, "failed to allocate a new item");
  123. }
  124. if(!internal_insert(inst, item))
  125. {
  126. enif_release_resource(&item);
  127. return make_error(env, "failed to insert new item in the queue");
  128. }
  129. ERL_NIF_TERM ref = enif_make_resource(env, item);
  130. return enif_make_tuple2(env, ATOMS.atomOk, ref);
  131. }
  132. ERL_NIF_TERM nif_epqueue_remove(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
  133. {
  134. UNUSED(argc);
  135. epqueue_data* data = static_cast<epqueue_data*>(enif_priv_data(env));
  136. epqueue* inst = NULL;
  137. queue_item* item = NULL;
  138. if(!enif_get_resource(env, argv[0], data->resPQueueInstance, reinterpret_cast<void**>(&inst)))
  139. return enif_make_badarg(env);
  140. if(!is_owner(env, inst))
  141. return enif_make_badarg(env);
  142. if(!enif_get_resource(env, argv[1], data->resPQueueItem, reinterpret_cast<void**>(&item)))
  143. return enif_make_badarg(env);
  144. if(!internal_remove(inst, item))
  145. return ATOMS.atomFalse;
  146. enif_release_resource(&item);
  147. return ATOMS.atomTrue;
  148. }
  149. ERL_NIF_TERM nif_epqueue_pop(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
  150. {
  151. UNUSED(argc);
  152. epqueue_data* data = static_cast<epqueue_data*>(enif_priv_data(env));
  153. epqueue* inst = NULL;
  154. if(!enif_get_resource(env, argv[0], data->resPQueueInstance, reinterpret_cast<void**>(&inst)))
  155. return enif_make_badarg(env);
  156. if(!is_owner(env, inst))
  157. return enif_make_badarg(env);
  158. queue_item* item = internal_pop(inst);
  159. if(item == NULL)
  160. return ATOMS.atomUndefined;
  161. ERL_NIF_TERM bin_term;
  162. if(enif_binary_to_term(env, item->data.data, item->data.size, &bin_term, 0) == 0)
  163. {
  164. enif_release_resource(item);
  165. return make_error(env, "failed to decode data");
  166. }
  167. enif_release_resource(item);
  168. return enif_make_tuple3(env, ATOMS.atomOk, bin_term, enif_make_long(env, item->priority));
  169. }
  170. ERL_NIF_TERM nif_epqueue_peek(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
  171. {
  172. UNUSED(argc);
  173. epqueue_data* data = static_cast<epqueue_data*>(enif_priv_data(env));
  174. epqueue* inst = NULL;
  175. if(!enif_get_resource(env, argv[0], data->resPQueueInstance, reinterpret_cast<void**>(&inst)))
  176. return enif_make_badarg(env);
  177. if(!is_owner(env, inst))
  178. return enif_make_badarg(env);
  179. CritScope ss(inst->crit);
  180. queue_item* item = static_cast<queue_item*>(inst->queue->peek());
  181. if(item == NULL)
  182. return ATOMS.atomUndefined;
  183. ERL_NIF_TERM bin_term;
  184. if(enif_binary_to_term(env, item->data.data, item->data.size, &bin_term, 0) == 0)
  185. return make_error(env, "failed to decode data");
  186. return enif_make_tuple3(env, ATOMS.atomOk, bin_term, enif_make_int64(env, item->priority));
  187. }