erlang各种有用的函数包括一些有用nif封装,还有一些性能测试case。
Du kan inte välja fler än 25 ämnen Ämnen måste starta med en bokstav eller siffra, kan innehålla bindestreck ('-') och vara max 35 tecken långa.

331 rader
6.2 KiB

5 år sedan
  1. #include "erl_nif.h"
  2. ErlNifResourceType* bsn_type;
  3. ERL_NIF_TERM ATOM_TRUE, ATOM_FALSE, ATOM_NO_MORE;
  4. struct bsn_elem_struct {
  5. ErlNifBinary bin;
  6. unsigned int hash;
  7. };
  8. typedef struct bsn_elem_struct bsn_elem;
  9. typedef struct {
  10. unsigned int count; /* count of elements */
  11. unsigned int max; /* count of slots */
  12. ErlNifMutex *mutex;
  13. bsn_elem* list;
  14. unsigned int (*next_pos)
  15. (void*, unsigned int, unsigned int);
  16. } bsn_res;
  17. inline static ERL_NIF_TERM bool_to_term(int value) {
  18. return value ? ATOM_TRUE : ATOM_FALSE;
  19. }
  20. unsigned int next_pos_linear(bsn_res* r, unsigned int hash, unsigned int step) {
  21. return (hash + step) % (r->max);
  22. }
  23. unsigned int next_pos_quadric(bsn_res* r, unsigned int hash, unsigned int step) {
  24. return (hash + (step*step)) % (r->max);
  25. }
  26. /* Calculate the sum of chars. */
  27. unsigned int
  28. private_hash(const ErlNifBinary* b, unsigned int max)
  29. {
  30. unsigned char* ptr;
  31. unsigned int i, sum = 0;
  32. ptr = b->data;
  33. i = b->size;
  34. for (; i; i--, ptr++)
  35. sum += *ptr;
  36. return sum % max;
  37. }
  38. inline int
  39. private_compare(ErlNifBinary* b1, ErlNifBinary* b2)
  40. {
  41. unsigned char* p1;
  42. unsigned char* p2;
  43. unsigned len;
  44. if (b1->size != b2->size)
  45. return 0;
  46. p1 = b1->data;
  47. p2 = b2->data;
  48. len = b1->size;
  49. while (len) {
  50. if ((*p1) != (*p2))
  51. return 0;
  52. len--; p1++; p2++;
  53. }
  54. return 1;
  55. }
  56. static ERL_NIF_TERM
  57. bsn_new(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
  58. {
  59. int max; /* This value will be set by a client:
  60. if (max<0) -> use quadric algorithm */
  61. bsn_elem* ptr;
  62. bsn_res* r;
  63. if (!enif_get_int(env, argv[0], &max) || (max == 0))
  64. return enif_make_badarg(env);
  65. r = (bsn_res*) enif_alloc_resource(bsn_type, sizeof(bsn_res));
  66. r->mutex = enif_mutex_create("Mutex for the BSN writer");
  67. r->count = 0;
  68. /* Select an algorithm */
  69. if (max>0) {
  70. r->next_pos = &next_pos_linear;
  71. } else if (max<0) {
  72. r->next_pos = &next_pos_quadric;
  73. max *= -1;
  74. }
  75. /* Now max is cells' count in the array. */
  76. r->max = (unsigned int) max;
  77. ptr = enif_alloc(sizeof(bsn_elem) * max);
  78. if (ptr == NULL)
  79. return enif_make_badarg(env);
  80. r->list = ptr;
  81. for (; max; max--, ptr++)
  82. ptr->hash = r->max;
  83. return enif_make_resource(env, r);
  84. }
  85. static ERL_NIF_TERM
  86. bsn_add(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
  87. {
  88. ErlNifBinary bin;
  89. bsn_res* r;
  90. unsigned int pos, hash, max;
  91. int num = 0;
  92. bsn_elem* elem_ptr;
  93. if (!(enif_get_resource(env, argv[0], bsn_type, (void**) &r)
  94. && enif_inspect_binary(env, argv[1], &bin)))
  95. return enif_make_badarg(env);
  96. enif_realloc_binary(&bin, bin.size);
  97. hash = pos = private_hash(&bin, r->max);
  98. enif_mutex_lock(r->mutex);
  99. max = r->max;
  100. while (num < max) {
  101. elem_ptr = &(r->list[pos]);
  102. /* Found free space */
  103. if (elem_ptr->hash == max) {
  104. elem_ptr->bin = bin;
  105. elem_ptr->hash = hash;
  106. break;
  107. }
  108. /* Found elem */
  109. if ((elem_ptr->hash == hash)
  110. && private_compare(&bin, &(elem_ptr->bin))) {
  111. num *= -1;
  112. break;
  113. }
  114. pos = (r->next_pos)(r, hash, num);
  115. num++;
  116. }
  117. if ((num >= 0) && (num < max))
  118. (r->count)++;
  119. enif_mutex_unlock(r->mutex);
  120. /* Error: already added or owerflow */
  121. if (!((num >= 0) && (num < max)))
  122. enif_release_binary(&bin);
  123. if (num >= max)
  124. return ATOM_NO_MORE;
  125. return enif_make_int(env, num);
  126. }
  127. static ERL_NIF_TERM
  128. bsn_search(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
  129. {
  130. ErlNifBinary bin;
  131. bsn_res* r;
  132. unsigned int pos, max, hash;
  133. int num = 1;
  134. bsn_elem* elem_ptr;
  135. if (!(enif_get_resource(env, argv[0], bsn_type, (void**) &r)
  136. && enif_inspect_binary(env, argv[1], &bin)))
  137. return enif_make_badarg(env);
  138. hash = pos = private_hash(&bin, r->max);
  139. enif_mutex_lock(r->mutex);
  140. max = r->max;
  141. while (num < max) {
  142. elem_ptr = &(r->list[pos]);
  143. /* Found free space */
  144. if (elem_ptr->hash == max) {
  145. break;
  146. }
  147. /* Found elem */
  148. if ((elem_ptr->hash == hash)
  149. && private_compare(&bin, &(elem_ptr->bin))) {
  150. num *= -1;
  151. break;
  152. }
  153. pos = (r->next_pos)(r, hash, num);
  154. num++;
  155. }
  156. enif_mutex_unlock(r->mutex);
  157. return enif_make_int(env, num);
  158. }
  159. static ERL_NIF_TERM
  160. bsn_clear(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
  161. {
  162. return enif_make_badarg(env);
  163. }
  164. static ERL_NIF_TERM
  165. bsn_all(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
  166. {
  167. bsn_res* r;
  168. unsigned int max, pos = 0;
  169. ERL_NIF_TERM head, tail;
  170. ErlNifBinary bin;
  171. bsn_elem* elem_ptr;
  172. if (!enif_get_resource(env, argv[0], bsn_type, (void**) &r))
  173. return enif_make_badarg(env);
  174. tail = enif_make_list(env, 0);
  175. enif_mutex_lock(r->mutex);
  176. max = r->max;
  177. elem_ptr = r->list;
  178. do {
  179. if (elem_ptr->hash != max) {
  180. bin = elem_ptr->bin;
  181. enif_realloc_binary(&bin, bin.size);
  182. head = enif_make_binary(env, &bin);
  183. tail = enif_make_list_cell(env, head, tail);
  184. }
  185. elem_ptr++;
  186. pos++;
  187. } while (pos < max);
  188. enif_mutex_unlock(r->mutex);
  189. return tail;
  190. }
  191. static ERL_NIF_TERM
  192. bsn_count(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
  193. {
  194. bsn_res* r;
  195. if (!enif_get_resource(env, argv[0], bsn_type, (void**) &r))
  196. return enif_make_badarg(env);
  197. return enif_make_int(env, r->count);
  198. }
  199. void private_clear_all(bsn_res* r)
  200. {
  201. unsigned int max, num;
  202. bsn_elem* ptr;
  203. num = max = r->max;
  204. ptr = r->list;
  205. while (num) {
  206. if (ptr->hash != max) {
  207. enif_release_binary(&(ptr->bin));
  208. }
  209. ptr++;
  210. num--;
  211. }
  212. }
  213. void
  214. bsn_type_dtor(ErlNifEnv* env, void* obj)
  215. {
  216. bsn_res* r = (bsn_res*) obj;
  217. private_clear_all(r);
  218. enif_mutex_destroy(r->mutex);
  219. enif_free(r->list);
  220. }
  221. int
  222. on_load(ErlNifEnv* env, void** priv, ERL_NIF_TERM info)
  223. {
  224. ATOM_TRUE = enif_make_atom(env, "true");
  225. ATOM_FALSE = enif_make_atom(env, "false");
  226. ATOM_NO_MORE = enif_make_atom(env, "no_more");
  227. ErlNifResourceFlags flags = (ErlNifResourceFlags)(ERL_NIF_RT_CREATE |
  228. ERL_NIF_RT_TAKEOVER);
  229. bsn_type = enif_open_resource_type(env, NULL, "bsn_type",
  230. bsn_type_dtor, flags, NULL);
  231. if (bsn_type == NULL) return 1;
  232. return 0;
  233. }
  234. int
  235. on_upgrade(ErlNifEnv* env, void** priv, void** old_priv, ERL_NIF_TERM info)
  236. {
  237. return 0;
  238. }
  239. static ErlNifFunc nif_functions[] = {
  240. {"new", 1, bsn_new},
  241. {"add", 2, bsn_add},
  242. {"all", 1, bsn_all},
  243. {"in", 2, bsn_search},
  244. {"clear", 2, bsn_clear},
  245. {"count", 1, bsn_count},
  246. };
  247. ERL_NIF_INIT(bsn_int, nif_functions, &on_load, &on_load, &on_upgrade, NULL);