erlang各种有用的函数包括一些有用nif封装,还有一些性能测试case。
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

364 lines
9.4 KiB

  1. //
  2. // Created by fox on 2017/8/10.
  3. //
  4. #ifndef USENIF
  5. #define USENIF 1
  6. #endif
  7. #include <string.h>
  8. #include "erl_nif.h"
  9. #include "skiplist.h"
  10. // all pointer to skiplist would be stored here
  11. static skiplist **p_array;
  12. static size_t p_array_size = 0;
  13. #define enif_get_value enif_get_int
  14. #define enif_make_value enif_make_int
  15. // store a new pointer
  16. int store_new_pointer(skiplist *p)
  17. {
  18. if (p_array_size == 0) {
  19. // init it
  20. p_array_size = 2;
  21. p_array = (skiplist **)icalloc(p_array_size * sizeof(skiplist *));
  22. p_array[0] = p;
  23. return 0;
  24. }
  25. // find the empty pos
  26. for (int i = 0; i < p_array_size; ++i) {
  27. if (p_array[i] == NULL) {
  28. p_array[i] = p;
  29. return i;
  30. }
  31. }
  32. // reallocate array
  33. size_t old_size = p_array_size;
  34. p_array_size *= 2;
  35. p_array = (skiplist **)realloc(p_array, sizeof(skiplist *) * p_array_size);
  36. memset(p_array+old_size, 0, sizeof(skiplist *) * old_size);
  37. p_array[old_size] = p;
  38. return (int)old_size;
  39. }
  40. inline skiplist *get_pointer(ErlNifEnv* env, ERL_NIF_TERM arg);
  41. skiplist *get_pointer(ErlNifEnv* env, ERL_NIF_TERM arg)
  42. {
  43. int index;
  44. if (!enif_get_int(env, arg, &index))
  45. return NULL;
  46. if (0 <= index && index < p_array_size)
  47. return p_array[index];
  48. return NULL;
  49. }
  50. static ERL_NIF_TERM new(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
  51. {
  52. skiplist *list = skiplist_init();
  53. int pointer_pos = store_new_pointer(list);
  54. ERL_NIF_TERM res = enif_make_int(env, pointer_pos);
  55. return res;
  56. }
  57. static ERL_NIF_TERM free1(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
  58. {
  59. int index;
  60. if (!enif_get_int(env, argv[0], &index))
  61. return enif_make_badarg(env);
  62. if (index < 0 || index >= p_array_size)
  63. return enif_make_badarg(env);
  64. skiplist_free(p_array[index]);
  65. p_array[index] = NULL;
  66. ERL_NIF_TERM res;
  67. enif_make_existing_atom(env, "ok", &res, ERL_NIF_LATIN1);
  68. return res;
  69. }
  70. static ERL_NIF_TERM insert(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
  71. {
  72. skiplist *list = get_pointer(env, argv[0]);
  73. if (!list)
  74. return enif_make_badarg(env);
  75. int score;
  76. vtype value;
  77. if (!enif_get_int(env, argv[1], &score))
  78. return enif_make_badarg(env);
  79. if (!enif_get_value(env, argv[2], &value))
  80. return enif_make_badarg(env);
  81. int res0 = skiplist_insert(list, score, value);
  82. ERL_NIF_TERM res = enif_make_int(env, res0);
  83. return res;
  84. }
  85. static ERL_NIF_TERM update(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
  86. {
  87. skiplist *list = get_pointer(env, argv[0]);
  88. if (!list)
  89. return enif_make_badarg(env);
  90. int score, old_score;
  91. vtype value;
  92. if (!enif_get_int(env, argv[1], &score))
  93. return enif_make_badarg(env);
  94. if (!enif_get_value(env, argv[2], &value))
  95. return enif_make_badarg(env);
  96. if (!enif_get_int(env, argv[3], &old_score))
  97. return enif_make_badarg(env);
  98. int res0 = skiplist_update(list, score, value, old_score);
  99. ERL_NIF_TERM res = enif_make_int(env, res0);
  100. return res;
  101. }
  102. static ERL_NIF_TERM delete(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
  103. {
  104. skiplist *list = get_pointer(env, argv[0]);
  105. if (!list)
  106. return enif_make_badarg(env);
  107. int socre;
  108. vtype value;
  109. if (!enif_get_int(env, argv[1], &socre))
  110. return enif_make_badarg(env);
  111. if (!enif_get_value(env, argv[2], &value))
  112. return enif_make_badarg(env);
  113. int res0 = skiplist_delete(list, socre, value);
  114. ERL_NIF_TERM res = enif_make_int(env, res0);
  115. return res;
  116. }
  117. static ERL_NIF_TERM to_list(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
  118. {
  119. skiplist *list = get_pointer(env, argv[0]);
  120. if (!list)
  121. return enif_make_badarg(env);
  122. snode *x = list->header->level[0].forward;
  123. snode **nodes = (snode **)malloc(sizeof(snode *) * (list->size + 1));
  124. while (x) {
  125. *nodes = x;
  126. ++nodes;
  127. x = x->level[0].forward;
  128. }
  129. ERL_NIF_TERM res = enif_make_list(env, 0);
  130. for (int i = list->size-1; i >= 0; --i) {
  131. --nodes;
  132. ERL_NIF_TERM item = enif_make_tuple(
  133. env,
  134. 2,
  135. enif_make_int(env, (*nodes)->score),
  136. enif_make_value(env, (*nodes)->value));
  137. res = enif_make_list_cell(env, item, res);
  138. }
  139. free(nodes);
  140. return res;
  141. }
  142. static ERL_NIF_TERM size1(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
  143. {
  144. skiplist *list = get_pointer(env, argv[0]);
  145. if (!list)
  146. return enif_make_badarg(env);
  147. ERL_NIF_TERM res = enif_make_int(env, list->size);
  148. return res;
  149. }
  150. // first index of the score
  151. static ERL_NIF_TERM index_of_score(ErlNifEnv *env, int argc, const ERL_NIF_TERM *argv)
  152. {
  153. skiplist *list = get_pointer(env, argv[0]);
  154. if (!list)
  155. return enif_make_badarg(env);
  156. int socre;
  157. if (!enif_get_int(env, argv[1], &socre))
  158. return enif_make_badarg(env);
  159. int res0 = skiplist_index_of_score(list, socre);
  160. ERL_NIF_TERM res = enif_make_int(env, res0);
  161. return res;
  162. }
  163. static ERL_NIF_TERM at(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
  164. {
  165. skiplist *list = get_pointer(env, argv[0]);
  166. if (!list)
  167. return enif_make_badarg(env);
  168. int index;
  169. if (!enif_get_int(env, argv[1], &index))
  170. return enif_make_badarg(env);
  171. snode *x = skiplist_at(list, index);
  172. ERL_NIF_TERM res;
  173. if (x) {
  174. res = enif_make_tuple(
  175. env,
  176. 2,
  177. enif_make_int(env, x->score),
  178. enif_make_value(env, x->value));
  179. } else {
  180. enif_make_existing_atom(env, "error", &res, ERL_NIF_LATIN1);
  181. }
  182. return res;
  183. }
  184. static ERL_NIF_TERM range_by_score(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
  185. {
  186. skiplist *list = get_pointer(env, argv[0]);
  187. if (!list)
  188. return enif_make_badarg(env);
  189. int score1, score2;
  190. if (!enif_get_int(env, argv[1], &score1))
  191. return enif_make_badarg(env);
  192. if (!enif_get_int(env, argv[2], &score2))
  193. return enif_make_badarg(env);
  194. skiplist_search_ret res0;
  195. skiplist_search(list, score1, &res0);
  196. ERL_NIF_TERM ret_list = enif_make_list(env, 0);
  197. for (snode *node = res0.node; node && node->score <= score2; node = node->level[0].forward) {
  198. ret_list = enif_make_list_cell(env,
  199. enif_make_tuple(env,
  200. 2,
  201. enif_make_int(env, node->score),
  202. enif_make_value(env, node->value)),
  203. ret_list);
  204. }
  205. ERL_NIF_TERM ret_list1;
  206. enif_make_reverse_list(env, ret_list, &ret_list1);
  207. return enif_make_tuple(
  208. env,
  209. 2,
  210. enif_make_int(env, res0.index),
  211. ret_list1);
  212. }
  213. static ERL_NIF_TERM range_1(
  214. ErlNifEnv* env,
  215. const ERL_NIF_TERM argv[],
  216. ERL_NIF_TERM (*func_make_item)(ErlNifEnv *, snode *))
  217. {
  218. skiplist *list = get_pointer(env, argv[0]);
  219. if (!list)
  220. return enif_make_badarg(env);
  221. int start, len;
  222. if (!enif_get_int(env, argv[1], &start))
  223. return enif_make_badarg(env);
  224. if (!enif_get_int(env, argv[2], &len))
  225. return enif_make_badarg(env);
  226. int n = list->size - start + 1;
  227. int alloc_size = n < len ? n : len;
  228. ERL_NIF_TERM res = enif_make_list(env, 0);
  229. if (alloc_size <= 0) {
  230. return res;
  231. }
  232. snode **nodes = (snode **)malloc(sizeof(snode *) * (alloc_size + 1));
  233. // get the nodes
  234. snode *x = skiplist_at(list, start);
  235. for (n = 0; n < alloc_size; n++) {
  236. *nodes = x;
  237. ++nodes;
  238. x = x->level[0].forward;
  239. }
  240. for (n = 0; n < alloc_size; n++) {
  241. --nodes;
  242. res = enif_make_list_cell(env, func_make_item(env, *nodes), res);
  243. }
  244. free(nodes);
  245. return res;
  246. }
  247. inline static ERL_NIF_TERM range_make_item(ErlNifEnv* env, snode *node);
  248. static ERL_NIF_TERM range_make_item(ErlNifEnv* env, snode *node)
  249. {
  250. return enif_make_value(env, node->value);
  251. }
  252. /* int p_list: identification of skiplist
  253. * int start: >= 1, start index of skiplist
  254. * int len: >= 1, max items to return
  255. * return: [node]
  256. */
  257. static ERL_NIF_TERM range(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
  258. {
  259. return range_1(env, argv, range_make_item);
  260. }
  261. inline static ERL_NIF_TERM range_with_score_make_item(ErlNifEnv* env, snode *node);
  262. static ERL_NIF_TERM range_with_score_make_item(ErlNifEnv* env, snode *node)
  263. {
  264. return enif_make_tuple(
  265. env,
  266. 2,
  267. enif_make_int(env, node->score),
  268. enif_make_value(env, node->value));
  269. }
  270. /* int p_list: identification of skiplist
  271. * int start: >= 1, start index of skiplist
  272. * int len: >= 1, max items to return
  273. * return: [{score, node}]
  274. */
  275. static ERL_NIF_TERM range_with_score(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
  276. {
  277. return range_1(env, argv, range_with_score_make_item);
  278. }
  279. static ErlNifFunc nif_funcs[] = {
  280. {"new", 0, new},
  281. {"free", 1, free1},
  282. {"insert", 3, insert},
  283. {"update", 4, update},
  284. {"delete", 3, delete},
  285. {"to_list", 1, to_list},
  286. {"size", 1, size1},
  287. {"index_of_score", 2, index_of_score},
  288. {"at", 2, at},
  289. {"range", 3, range},
  290. {"range_with_score", 3, range_with_score},
  291. {"range_by_score", 3, range_by_score},
  292. };
  293. ERL_NIF_INIT(skiplist, nif_funcs, NULL, NULL, NULL, NULL)