erlang各种有用的函数包括一些有用nif封装,还有一些性能测试case。
Non puoi selezionare più di 25 argomenti Gli argomenti devono iniziare con una lettera o un numero, possono includere trattini ('-') e possono essere lunghi fino a 35 caratteri.

448 righe
8.5 KiB

  1. #include "erl_nif.h"
  2. ErlNifResourceType* bsn_type;
  3. ERL_NIF_TERM ATOM_TRUE, ATOM_FALSE;
  4. /*
  5. typedef struct {
  6. unsigned size;
  7. unsigned char* data;
  8. } ErlNifBinary;
  9. */
  10. struct bsn_elem_struct {
  11. ErlNifBinary bin;
  12. struct bsn_elem_struct* next;
  13. };
  14. typedef struct bsn_elem_struct bsn_elem;
  15. typedef bsn_elem* bsn_list;
  16. typedef struct {
  17. unsigned int count; /* count of elements */
  18. unsigned int max; /* count of slots */
  19. ErlNifMutex *mutex;
  20. bsn_list* list;
  21. } bsn_res;
  22. inline static ERL_NIF_TERM bool_to_term(int value) {
  23. return value ? ATOM_TRUE : ATOM_FALSE;
  24. }
  25. /* Calculate the sum of chars. */
  26. unsigned int
  27. private_hash(const ErlNifBinary* b, unsigned int max)
  28. {
  29. unsigned char* ptr;
  30. unsigned int i, sum = 0;
  31. ptr = b->data;
  32. i = b->size;
  33. for (; i; i--, ptr++)
  34. sum += *ptr;
  35. return sum % max;
  36. }
  37. inline void
  38. private_clear_elem(bsn_elem* el)
  39. {
  40. enif_release_binary(&(el->bin));
  41. enif_free(el);
  42. }
  43. inline void
  44. private_chain_clear_all(bsn_elem* ptr)
  45. {
  46. bsn_elem* next;
  47. while (ptr != NULL) {
  48. next = ptr->next;
  49. private_clear_elem(ptr);
  50. ptr = next;
  51. }
  52. }
  53. inline int
  54. private_compare(ErlNifBinary* b1, ErlNifBinary* b2)
  55. {
  56. unsigned char* p1;
  57. unsigned char* p2;
  58. unsigned len;
  59. if (b1->size != b2->size)
  60. return 0;
  61. p1 = b1->data;
  62. p2 = b2->data;
  63. len = b1->size;
  64. while (len) {
  65. if ((*p1) != (*p2))
  66. return 0;
  67. len--; p1++; p2++;
  68. }
  69. return 1;
  70. }
  71. /* Skip existing elements. If the element bin is not found, return last element.
  72. * If el.bin == bin, return el. */
  73. bsn_elem*
  74. private_chain_shift(bsn_elem* ptr, ErlNifBinary* bin, int* num_ptr)
  75. {
  76. (*num_ptr)++;
  77. if ((ptr) == NULL)
  78. return ptr;
  79. while (1) {
  80. if (private_compare(&(ptr->bin), bin)) {
  81. /* found an equal binary. Invert num */
  82. (*num_ptr) *= -1;
  83. return ptr;
  84. }
  85. if ((ptr->next) == NULL)
  86. return ptr;
  87. ptr = ptr->next;
  88. (*num_ptr)++;
  89. }
  90. }
  91. /* Append the element `el' to the chain `chain' */
  92. void
  93. private_chain_append(bsn_elem** chain, bsn_elem* el, int* num_ptr)
  94. {
  95. bsn_elem* last;
  96. if ((*chain) == NULL) {
  97. /* The new element is last */
  98. *chain = el;
  99. } else {
  100. last = private_chain_shift(*chain, &(el->bin), num_ptr);
  101. if ((*num_ptr) < 0) {
  102. /* Element was already added. */
  103. private_clear_elem(el);
  104. } else {
  105. last->next = el;
  106. }
  107. }
  108. }
  109. bsn_elem*
  110. private_chain_shift_clear(bsn_elem** ptr, ErlNifBinary* bin, int* num_ptr)
  111. {
  112. bsn_elem** prev = NULL;
  113. bsn_elem* el;
  114. while ((*ptr) != NULL) {
  115. if (private_compare(&((*ptr)->bin), bin)) {
  116. (*num_ptr) *= -1;
  117. /* found an equal binary. Delete elem. Invert num */
  118. if (prev == NULL) {
  119. el = *ptr;
  120. (*ptr) = (*ptr)->next;
  121. return el;
  122. }
  123. *prev = (*ptr)->next;
  124. return *ptr;
  125. }
  126. prev = ptr;
  127. el = *ptr;
  128. ptr = (bsn_elem**) &(el->next);
  129. (*num_ptr)++;
  130. }
  131. return NULL;
  132. }
  133. static ERL_NIF_TERM
  134. bsn_new(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
  135. {
  136. unsigned int max;
  137. bsn_list* ptr;
  138. bsn_res* r;
  139. if (!(enif_get_uint(env, argv[0], &max) && (max>0)))
  140. return enif_make_badarg(env);
  141. ptr = enif_alloc(sizeof(bsn_list) * max);
  142. if (ptr == NULL)
  143. return enif_make_badarg(env);
  144. r = (bsn_res*) enif_alloc_resource(bsn_type, sizeof(bsn_res));
  145. r->mutex = enif_mutex_create("Mutex for the BSN writer");
  146. r->count = 0;
  147. r->max = max;
  148. r->list = ptr;
  149. for (; max; max--, ptr++)
  150. *ptr = NULL;
  151. return enif_make_resource(env, r);
  152. }
  153. static ERL_NIF_TERM
  154. bsn_add(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
  155. {
  156. ErlNifBinary bin;
  157. bsn_res* r;
  158. unsigned int pos;
  159. int num = 0;
  160. bsn_elem* elem_ptr;
  161. if (!(enif_get_resource(env, argv[0], bsn_type, (void**) &r)
  162. && enif_inspect_binary(env, argv[1], &bin)))
  163. return enif_make_badarg(env);
  164. enif_realloc_binary(&bin, bin.size);
  165. pos = private_hash(&bin, r->max);
  166. elem_ptr = enif_alloc(sizeof(bsn_elem));
  167. if (elem_ptr == NULL)
  168. return enif_make_badarg(env);
  169. elem_ptr->next = NULL;
  170. elem_ptr->bin = bin;
  171. enif_mutex_lock(r->mutex);
  172. private_chain_append(&(r->list[pos]), elem_ptr, &num);
  173. if (num >= 0)
  174. (r->count)++;
  175. enif_mutex_unlock(r->mutex);
  176. /* Already added */
  177. if (num < 0)
  178. enif_release_binary(&(bin));
  179. return enif_make_int(env, num);
  180. }
  181. static ERL_NIF_TERM
  182. bsn_search(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
  183. {
  184. ErlNifBinary bin;
  185. bsn_res* r;
  186. unsigned int pos;
  187. int num = 0;
  188. if (!(enif_get_resource(env, argv[0], bsn_type, (void**) &r)
  189. && enif_inspect_binary(env, argv[1], &bin)))
  190. return enif_make_badarg(env);
  191. pos = private_hash(&bin, r->max);
  192. enif_mutex_lock(r->mutex);
  193. private_chain_shift(r->list[pos], &bin, &num);
  194. enif_mutex_unlock(r->mutex);
  195. return enif_make_int(env, num);
  196. }
  197. static ERL_NIF_TERM
  198. bsn_clear(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
  199. {
  200. ErlNifBinary bin;
  201. bsn_res* r;
  202. unsigned int pos;
  203. int num = 0;
  204. bsn_elem* elem_ptr;
  205. if (!(enif_get_resource(env, argv[0], bsn_type, (void**) &r)
  206. && enif_inspect_binary(env, argv[1], &bin)))
  207. return enif_make_badarg(env);
  208. pos = private_hash(&bin, r->max);
  209. enif_mutex_lock(r->mutex);
  210. elem_ptr = private_chain_shift_clear(&(r->list[pos]), &bin, &num);
  211. if (elem_ptr != NULL) {
  212. private_clear_elem(elem_ptr);
  213. (r->count)--;
  214. }
  215. enif_mutex_unlock(r->mutex);
  216. return enif_make_int(env, num);
  217. }
  218. static ERL_NIF_TERM
  219. bsn_all_chain(ErlNifEnv* env, bsn_elem* e, ERL_NIF_TERM tail)
  220. {
  221. ERL_NIF_TERM head;
  222. ErlNifBinary bin;
  223. while (e != NULL) {
  224. bin = e->bin;
  225. enif_realloc_binary(&bin, bin.size);
  226. head = enif_make_binary(env, &bin);
  227. tail = enif_make_list_cell(env, head, tail);
  228. e = e->next;
  229. }
  230. return tail;
  231. }
  232. static ERL_NIF_TERM
  233. bsn_chains(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
  234. {
  235. bsn_res* r;
  236. unsigned int max;
  237. bsn_list* ptr;
  238. ERL_NIF_TERM tail, head;
  239. if (!enif_get_resource(env, argv[0], bsn_type, (void**) &r))
  240. return enif_make_badarg(env);
  241. tail = enif_make_list(env, 0);
  242. ptr = r->list;
  243. enif_mutex_lock(r->mutex);
  244. max = r->max;
  245. while (max) {
  246. head = enif_make_list(env, 0);
  247. head = bsn_all_chain(env, *ptr, head);
  248. tail = enif_make_list_cell(env, head, tail);
  249. ptr++;
  250. max--;
  251. }
  252. enif_mutex_unlock(r->mutex);
  253. return tail;
  254. }
  255. static ERL_NIF_TERM
  256. bsn_all(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
  257. {
  258. bsn_res* r;
  259. unsigned int max;
  260. bsn_list* ptr;
  261. ERL_NIF_TERM list;
  262. if (!enif_get_resource(env, argv[0], bsn_type, (void**) &r))
  263. return enif_make_badarg(env);
  264. list = enif_make_list(env, 0);
  265. ptr = r->list;
  266. enif_mutex_lock(r->mutex);
  267. max = r->max;
  268. while (max) {
  269. list = bsn_all_chain(env, *ptr, list);
  270. ptr++;
  271. max--;
  272. }
  273. enif_mutex_unlock(r->mutex);
  274. return list;
  275. }
  276. static ERL_NIF_TERM
  277. bsn_count(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
  278. {
  279. bsn_res* r;
  280. if (!enif_get_resource(env, argv[0], bsn_type, (void**) &r))
  281. return enif_make_badarg(env);
  282. return enif_make_int(env, r->count);
  283. }
  284. static ERL_NIF_TERM
  285. bsn_hash(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
  286. {
  287. ErlNifBinary bin;
  288. unsigned int max;
  289. if (!(enif_inspect_binary(env, argv[0], &bin)
  290. && enif_get_uint(env, argv[1], &max) && (max>0)))
  291. return enif_make_badarg(env);
  292. return enif_make_uint(env,
  293. private_hash(&bin, max));
  294. }
  295. static ERL_NIF_TERM
  296. bsn_compare(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
  297. {
  298. ErlNifBinary b1, b2;
  299. if (!(enif_inspect_binary(env, argv[0], &b1)
  300. && enif_inspect_binary(env, argv[1], &b2)))
  301. return enif_make_badarg(env);
  302. return bool_to_term(private_compare(&b1, &b2));
  303. }
  304. void private_clear_all(bsn_res* r)
  305. {
  306. unsigned int max;
  307. bsn_list* ptr;
  308. max = r->max;
  309. ptr = r->list;
  310. while (max) {
  311. private_chain_clear_all(*ptr);
  312. ptr++;
  313. max--;
  314. }
  315. }
  316. void
  317. bsn_type_dtor(ErlNifEnv* env, void* obj)
  318. {
  319. bsn_res* r = (bsn_res*) obj;
  320. private_clear_all(r);
  321. enif_mutex_destroy(r->mutex);
  322. enif_free(r->list);
  323. }
  324. int
  325. on_load(ErlNifEnv* env, void** priv, ERL_NIF_TERM info)
  326. {
  327. ATOM_TRUE = enif_make_atom(env, "true");
  328. ATOM_FALSE = enif_make_atom(env, "false");
  329. ErlNifResourceFlags flags = (ErlNifResourceFlags)(ERL_NIF_RT_CREATE |
  330. ERL_NIF_RT_TAKEOVER);
  331. bsn_type = enif_open_resource_type(env, NULL, "bsn_type",
  332. bsn_type_dtor, flags, NULL);
  333. if (bsn_type == NULL) return 1;
  334. return 0;
  335. }
  336. int
  337. on_upgrade(ErlNifEnv* env, void** priv, void** old_priv, ERL_NIF_TERM info)
  338. {
  339. return 0;
  340. }
  341. static ErlNifFunc nif_functions[] = {
  342. {"new", 1, bsn_new},
  343. {"add", 2, bsn_add},
  344. {"all", 1, bsn_all},
  345. {"chains", 1, bsn_chains},
  346. {"in", 2, bsn_search},
  347. {"clear", 2, bsn_clear},
  348. {"count", 1, bsn_count},
  349. {"hash", 2, bsn_hash},
  350. {"compare", 2, bsn_compare},
  351. };
  352. ERL_NIF_INIT(bsn_ext, nif_functions, &on_load, &on_load, &on_upgrade, NULL);