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.

435 regels
14 KiB

5 jaren geleden
  1. #include <stdint.h>
  2. #include <string.h>
  3. #include "erl_nif.h"
  4. typedef struct {
  5. size_t keySize;
  6. size_t bblSize_1;
  7. size_t bblSize_2;
  8. struct _bbl **arrayPtr;
  9. } hashb;
  10. typedef struct _bbl {
  11. struct _node *head;
  12. } bbl;
  13. typedef struct _node {
  14. struct _node *next;
  15. ErlNifBinary Key;
  16. ErlNifBinary Value;
  17. } node;
  18. #define BBLSIZE_1 128
  19. #define BBLSIZE_2 128
  20. static ErlNifResourceType *ResType = NULL;
  21. static ERL_NIF_TERM undefined;
  22. static ERL_NIF_TERM ok;
  23. ///////////////////////////////hash 函数 /////////////////////////////
  24. static uint32_t fnv_hash(const unsigned char *data, size_t size, uint32_t salt) {
  25. uint32_t i;
  26. uint64_t hashv;
  27. const unsigned char *_hf_key = (const unsigned char *) (data);
  28. hashv = 2166136261;
  29. for (i = 0; i < size; i++) {
  30. hashv = hashv ^ _hf_key[i];
  31. hashv = hashv * 16777619;
  32. }
  33. //enif_fprintf(stdout, "IMY************get %T \n", argv[1]);
  34. return hashv;
  35. }
  36. static uint32_t murmurhash(const unsigned char *key, uint32_t len, uint32_t seed) {
  37. //uint32_t c1 = 0xcc9e2d51;
  38. //uint32_t c2 = 0x1b873593;
  39. //uint32_t r1 = 15;
  40. //uint32_t r2 = 13;
  41. //uint32_t m = 5;
  42. //uint32_t n = 0xe6546b64;
  43. uint32_t h = 0;
  44. uint32_t k = 0;
  45. uint8_t *d = (uint8_t *) key; // 32 bit extract from `key'
  46. const uint32_t *chunks = NULL;
  47. const uint8_t *tail = NULL; // tail - last 8 bytes
  48. int i = 0;
  49. int l = len / 4; // chunk length
  50. h = seed;
  51. chunks = (const uint32_t *) (d + l * 4); // body
  52. tail = (const uint8_t *) (d + l * 4); // last 8 byte chunk of `key'
  53. // for each 4 byte chunk of `key'
  54. for (i = -l; i != 0; ++i) {
  55. // next 4 byte chunk of `key'
  56. k = chunks[i];
  57. // encode next 4 byte chunk of `key'
  58. k *= 0xcc9e2d51;
  59. k = (k << 15) | (k >> (32 - 15));
  60. k *= 0x1b873593;
  61. // append to hash
  62. h ^= k;
  63. h = (h << 13) | (h >> (32 - 13));
  64. h = h * 5 + 0xe6546b64;
  65. }
  66. k = 0;
  67. // remainder
  68. switch (len & 3) { // `len % 4'
  69. case 3:
  70. k ^= (tail[2] << 16);
  71. case 2:
  72. k ^= (tail[1] << 8);
  73. case 1:
  74. k ^= tail[0];
  75. k *= 0xcc9e2d51;
  76. k = (k << 15) | (k >> (32 - 15));
  77. k *= 0x1b873593;
  78. h ^= k;
  79. }
  80. h ^= len;
  81. h ^= (h >> 16);
  82. h *= 0x85ebca6b;
  83. h ^= (h >> 13);
  84. h *= 0xc2b2ae35;
  85. h ^= (h >> 16);
  86. return h;
  87. }
  88. //////////////////////////////////hash 函数测试///////////////////////////
  89. static ERL_NIF_TERM hash1(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) {
  90. ErlNifBinary Value;
  91. if (!enif_term_to_binary(env, argv[0], &Value))
  92. return enif_make_badarg(env);
  93. uint32_t Salt;
  94. if (!enif_get_uint(env, argv[1], &Salt)) {
  95. return enif_make_badarg(env);
  96. }
  97. Salt = fnv_hash(Value.data, Value.size, Salt);
  98. enif_release_binary(&Value);
  99. return ok;
  100. };
  101. static ERL_NIF_TERM hash2(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) {
  102. ErlNifUInt64 Salt;
  103. if (!enif_get_uint64(env, argv[1], &Salt))
  104. return enif_make_badarg(env);
  105. ErlNifBinary Value;
  106. if (!enif_term_to_binary(env, argv[0], &Value))
  107. return enif_make_badarg(env);
  108. enif_release_binary(&Value);
  109. Salt = enif_hash(ERL_NIF_INTERNAL_HASH, argv[1], 2423432432);
  110. return ok;
  111. };
  112. static ERL_NIF_TERM hash3(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) {
  113. ErlNifUInt64 Salt;
  114. if (!enif_get_uint64(env, argv[1], &Salt))
  115. return enif_make_badarg(env);
  116. ErlNifBinary Value;
  117. if (!enif_term_to_binary(env, argv[0], &Value))
  118. return enif_make_badarg(env);
  119. Salt = murmurhash(Value.data, Value.size, 0);
  120. enif_release_binary(&Value);
  121. return ok;
  122. };
  123. static uint8_t compareChar1(const unsigned char *src, const unsigned char *dst, size_t Size) {
  124. // int j = 0;
  125. // unsigned char *tsrc, *tdst;
  126. // tsrc = src;
  127. // tdst = dst;
  128. // for(j = 0; j <= Size; j++)
  129. // {
  130. // enif_fprintf(stdout, "IMY************get9999111 src %d dst %d \n", *tsrc, *tdst);
  131. // tsrc++;
  132. // tdst++;
  133. // }
  134. uint8_t i = 0;
  135. while (i < Size-1 && (*src == *dst)) {
  136. // enif_fprintf(stdout, "IMY************get99992222 %d %d \n", *src, *dst);
  137. src++;
  138. dst++;
  139. i++;
  140. }
  141. //enif_fprintf(stdout, "IMY************get9999while end %d %d \n", *src, *dst);
  142. if (*src != *dst) {
  143. //enif_fprintf(stdout, "IMY************get99993333 %d %d \n", *src, *dst);
  144. return 1;
  145. } else {
  146. //enif_fprintf(stdout, "IMY************get99995555 %d %d \n", *src, *dst);
  147. return 0;
  148. }
  149. }
  150. static uint8_t compareChar2(const unsigned char *src, const unsigned char *dst, size_t Size) {
  151. const uint32_t *intSrc = NULL;
  152. const uint32_t *intDst = NULL;
  153. const uint8_t *tailSrc = NULL; // tail - last 8 bytes
  154. const uint8_t *tailDst = NULL; // tail - last 8 bytes
  155. int l = Size / 4; // chunk length
  156. intSrc = (const uint32_t *) src; // body
  157. intDst = (const uint32_t *) dst; // body
  158. tailSrc = (const uint8_t *) (src + l * 4); // last 8 byte chunk of `key'
  159. tailDst = (const uint8_t *) (dst + l * 4); // last 8 byte chunk of `key'
  160. // for each 4 byte chunk of `key'
  161. int i = 0;
  162. for (i = 0; i < l; i++) {
  163. if (intSrc[i] != intDst[i])
  164. return 1;
  165. }
  166. // remainder
  167. switch (Size & 3) {
  168. case 3:
  169. if (tailSrc[0] != tailDst[0] || tailSrc[1] != tailDst[1] || tailSrc[2] != tailDst[2]) {
  170. return 1;
  171. }
  172. break;
  173. case 2:
  174. if (tailSrc[0] != tailDst[0] || tailSrc[1] != tailDst[1]) {
  175. return 1;
  176. }
  177. break;
  178. case 1:
  179. if (tailSrc[0] != tailDst[0]) {
  180. return 1;
  181. }
  182. break;
  183. }
  184. return 0;
  185. }
  186. static ERL_NIF_TERM compareBin1(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) {
  187. ErlNifBinary src, dst;
  188. if (!(enif_inspect_binary(env, argv[0], &src) && enif_inspect_binary(env, argv[1], &dst)))
  189. return enif_make_badarg(env);
  190. if (src.size != dst.size) {
  191. return enif_make_int(env, 1);
  192. }
  193. int Ret = compareChar1(src.data, dst.data, src.size);
  194. return enif_make_int(env, Ret);
  195. }
  196. static ERL_NIF_TERM compareBin2(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) {
  197. ErlNifBinary src, dst;
  198. if (!(enif_inspect_binary(env, argv[0], &src) && enif_inspect_binary(env, argv[1], &dst)))
  199. return enif_make_badarg(env);
  200. if (src.size != dst.size) {
  201. return enif_make_int(env, 1);
  202. }
  203. int Ret = compareChar2(src.data, dst.data, src.size);
  204. return enif_make_int(env, Ret);
  205. }
  206. /////////////////////////////////////////////////////////////////////
  207. static int load(ErlNifEnv *env, void **priv, ERL_NIF_TERM load_info) {
  208. ErlNifResourceFlags flags = ERL_NIF_RT_CREATE | ERL_NIF_RT_TAKEOVER;
  209. ResType = enif_open_resource_type(env, NULL, "_nifHashb_", NULL, flags, NULL);
  210. if (NULL == ResType)
  211. return -1;
  212. undefined = enif_make_atom(env, "undefined");
  213. ok = enif_make_atom(env, "ok");
  214. return 0;
  215. }
  216. static ERL_NIF_TERM new(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) {
  217. hashb *ResPtr = (hashb *) enif_alloc_resource(ResType, sizeof(hashb));
  218. ResPtr->keySize = 0;
  219. ResPtr->bblSize_1 = BBLSIZE_1;
  220. ResPtr->bblSize_2 = BBLSIZE_2;
  221. ResPtr->arrayPtr = enif_alloc(sizeof(bbl *) * BBLSIZE_1);
  222. int i, j;
  223. bbl NullBbl;
  224. NullBbl.head = NULL;
  225. for (i = 0; i < BBLSIZE_1; i++) {
  226. ResPtr->arrayPtr[i] = enif_alloc(sizeof(bbl) * BBLSIZE_2);
  227. for (j = 0; j < BBLSIZE_2; j++) {
  228. ResPtr->arrayPtr[i][j] = NullBbl;
  229. }
  230. }
  231. ERL_NIF_TERM Res = enif_make_resource(env, ResPtr);
  232. enif_release_resource(ResPtr);
  233. return Res;
  234. }
  235. static uint8_t compareChar(const unsigned char *src, const unsigned char *dst, size_t Size) {
  236. const uint32_t *intSrc = NULL;
  237. const uint32_t *intDst = NULL;
  238. const uint8_t *tailSrc = NULL; // tail - last 8 bytes
  239. const uint8_t *tailDst = NULL; // tail - last 8 bytes
  240. int l = Size / 4; // chunk length
  241. intSrc = (const uint32_t *) src; // body
  242. intDst = (const uint32_t *) dst; // body
  243. tailSrc = (const uint8_t *) (src + l * 4); // last 8 byte chunk of `key'
  244. tailDst = (const uint8_t *) (dst + l * 4); // last 8 byte chunk of `key'
  245. // for each 4 byte chunk of `key'
  246. int i = 0;
  247. for (i = 0; i < l; i++) {
  248. if (intSrc[i] != intDst[i])
  249. return 1;
  250. }
  251. // remainder
  252. switch (Size & 3) {
  253. case 3:
  254. if (tailSrc[0] != tailDst[0] || tailSrc[1] != tailDst[1] || tailSrc[2] != tailDst[2]) {
  255. return 1;
  256. }
  257. break;
  258. case 2:
  259. if (tailSrc[0] != tailDst[0] || tailSrc[1] != tailDst[1]) {
  260. return 1;
  261. }
  262. break;
  263. case 1:
  264. if (tailSrc[0] != tailDst[0]) {
  265. return 1;
  266. }
  267. break;
  268. }
  269. return 0;
  270. }
  271. static uint8_t compareBin(ErlNifBinary src, ErlNifBinary dst) {
  272. if (src.size != dst.size) {
  273. //enif_fprintf(stdout, "IMY************get8888\n");
  274. return 1;
  275. }
  276. //enif_fprintf(stdout, "IMY************get8888111 %d \n", src.size);
  277. return compareChar(src.data, dst.data, src.size);
  278. }
  279. static ERL_NIF_TERM get(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) {
  280. hashb *ResPtr;
  281. if (!enif_get_resource(env, argv[0], ResType, (void **) &ResPtr)) {
  282. return enif_make_badarg(env);
  283. }
  284. //enif_fprintf(stdout, "IMY************get1111\n");
  285. ErlNifBinary getKey;
  286. if (!enif_term_to_binary(env, argv[1], &getKey))
  287. return enif_make_badarg(env);
  288. //enif_fprintf(stdout, "IMY************get2222\n");
  289. uint32_t BblIndex_1, BblIndex_2;
  290. BblIndex_1 = murmurhash(getKey.data, getKey.size, 131) % ResPtr->bblSize_1;
  291. BblIndex_2 = murmurhash(getKey.data, getKey.size, 16777619) % ResPtr->bblSize_2;
  292. //enif_fprintf(stdout, "IMY************get3333\n");
  293. if (NULL == ResPtr->arrayPtr[BblIndex_1][BblIndex_2].head) {
  294. //enif_fprintf(stdout, "IMY************get4444\n");
  295. enif_release_binary(&getKey);
  296. return undefined;
  297. } else {
  298. // enif_fprintf(stdout, "IMY************get55555\n");
  299. node *Head = ResPtr->arrayPtr[BblIndex_1][BblIndex_2].head;
  300. while (Head) {
  301. // enif_fprintf(stdout, "IMY************get7777\n");
  302. if (compareBin(getKey, Head->Key) == 0) {
  303. ERL_NIF_TERM Ret;
  304. enif_binary_to_term(env, Head->Value.data, Head->Value.size, &Ret, 0);
  305. //enif_fprintf(stdout, "IMY************get5555\n");
  306. enif_release_binary(&getKey);
  307. return Ret;
  308. }
  309. Head = Head->next;
  310. }
  311. //enif_fprintf(stdout, "IMY************get6666\n");
  312. enif_release_binary(&getKey);
  313. return undefined;
  314. }
  315. }
  316. static ERL_NIF_TERM put(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) {
  317. hashb *ResPtr;
  318. if (!enif_get_resource(env, argv[0], ResType, (void **) &ResPtr)) {
  319. return enif_make_badarg(env);
  320. }
  321. //enif_fprintf(stdout, "IMY************put111 \n");
  322. ErlNifBinary Key, Value;
  323. if (!enif_term_to_binary(env, argv[1], &Key))
  324. return enif_make_badarg(env);
  325. if (!enif_term_to_binary(env, argv[2], &Value))
  326. return enif_make_badarg(env);
  327. uint32_t BblIndex_1, BblIndex_2;
  328. BblIndex_1 = murmurhash(Key.data, Key.size, 131) % ResPtr->bblSize_1;
  329. BblIndex_2 = murmurhash(Key.data, Key.size, 16777619) % ResPtr->bblSize_2;
  330. //enif_fprintf(stdout, "IMY************put222 %d %d \n", BblIndex_1, BblIndex_2);
  331. //enif_fprintf(stdout, "IMY************put3333 \n");
  332. if (NULL == ResPtr->arrayPtr[BblIndex_1][BblIndex_2].head) {
  333. node *NewNode = enif_alloc(sizeof(node));
  334. NewNode->Key = Key;
  335. NewNode->Value = Value;
  336. NewNode->next = NULL;
  337. ResPtr->arrayPtr[BblIndex_1][BblIndex_2].head = NewNode;
  338. ResPtr->keySize = ResPtr->keySize + 1;
  339. //enif_fprintf(stdout, "IMY************put4444 \n");
  340. return ok;
  341. } else {
  342. node *Head = ResPtr->arrayPtr[BblIndex_1][BblIndex_2].head;
  343. while (Head) {
  344. if (compareBin(Key, Head->Key) == 0) {
  345. //ERL_NIF_TERM Ret;
  346. ErlNifBinary OldValue = Head->Value;
  347. //enif_binary_to_term(env, OldValue.data, OldValue.size, &Ret, 0);
  348. Head->Value = Value;
  349. enif_release_binary(&OldValue);
  350. enif_release_binary(&Key);
  351. //enif_fprintf(stdout, "IMY************put55555 \n");
  352. //return Ret;
  353. return ok;
  354. }
  355. Head = Head->next;
  356. }
  357. node *NewNode = enif_alloc(sizeof(node));
  358. NewNode->Key = Key;
  359. NewNode->Value = Value;
  360. NewNode->next = ResPtr->arrayPtr[BblIndex_1][BblIndex_2].head;
  361. ResPtr->arrayPtr[BblIndex_1][BblIndex_2].head = NewNode;
  362. ResPtr->keySize = ResPtr->keySize + 1;
  363. //enif_fprintf(stdout, "IMY************put6666\n");
  364. return ok;
  365. }
  366. }
  367. /////////////////////////////////////////////////////////////////////////
  368. static ErlNifFunc nifFuns[] = {
  369. {"new", 0, new},
  370. {"get", 2, get},
  371. {"put", 3, put},
  372. {"hash1", 2, hash1},
  373. {"hash2", 2, hash2},
  374. {"hash3", 2, hash3},
  375. {"compareBin1", 2, compareBin1},
  376. {"compareBin2", 2, compareBin2},
  377. };
  378. ERL_NIF_INIT(nifHashb, nifFuns,
  379. &load, NULL, NULL, NULL)