#include #include #include "erl_nif.h" typedef struct { size_t keySize; size_t bblSize_1; size_t bblSize_2; struct _bbl **arrayPtr; } hashb; typedef struct _bbl { struct _node *head; } bbl; typedef struct _node { struct _node *next; ErlNifBinary Key; ErlNifBinary Value; } node; #define BBLSIZE_1 128 #define BBLSIZE_2 128 static ErlNifResourceType *ResType = NULL; static ERL_NIF_TERM undefined; static ERL_NIF_TERM ok; ///////////////////////////////hash 函数 ///////////////////////////// static uint32_t fnv_hash(const unsigned char *data, size_t size, uint32_t salt) { uint32_t i; uint64_t hashv; const unsigned char *_hf_key = (const unsigned char *) (data); hashv = 2166136261; for (i = 0; i < size; i++) { hashv = hashv ^ _hf_key[i]; hashv = hashv * 16777619; } //enif_fprintf(stdout, "IMY************get %T \n", argv[1]); return hashv; } static uint32_t murmurhash(const unsigned char *key, uint32_t len, uint32_t seed) { //uint32_t c1 = 0xcc9e2d51; //uint32_t c2 = 0x1b873593; //uint32_t r1 = 15; //uint32_t r2 = 13; //uint32_t m = 5; //uint32_t n = 0xe6546b64; uint32_t h = 0; uint32_t k = 0; uint8_t *d = (uint8_t *) key; // 32 bit extract from `key' const uint32_t *chunks = NULL; const uint8_t *tail = NULL; // tail - last 8 bytes int i = 0; int l = len / 4; // chunk length h = seed; chunks = (const uint32_t *) (d + l * 4); // body tail = (const uint8_t *) (d + l * 4); // last 8 byte chunk of `key' // for each 4 byte chunk of `key' for (i = -l; i != 0; ++i) { // next 4 byte chunk of `key' k = chunks[i]; // encode next 4 byte chunk of `key' k *= 0xcc9e2d51; k = (k << 15) | (k >> (32 - 15)); k *= 0x1b873593; // append to hash h ^= k; h = (h << 13) | (h >> (32 - 13)); h = h * 5 + 0xe6546b64; } k = 0; // remainder switch (len & 3) { // `len % 4' case 3: k ^= (tail[2] << 16); case 2: k ^= (tail[1] << 8); case 1: k ^= tail[0]; k *= 0xcc9e2d51; k = (k << 15) | (k >> (32 - 15)); k *= 0x1b873593; h ^= k; } h ^= len; h ^= (h >> 16); h *= 0x85ebca6b; h ^= (h >> 13); h *= 0xc2b2ae35; h ^= (h >> 16); return h; } //////////////////////////////////hash 函数测试/////////////////////////// static ERL_NIF_TERM hash1(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) { ErlNifBinary Value; if (!enif_term_to_binary(env, argv[0], &Value)) return enif_make_badarg(env); uint32_t Salt; if (!enif_get_uint(env, argv[1], &Salt)) { return enif_make_badarg(env); } Salt = fnv_hash(Value.data, Value.size, Salt); enif_release_binary(&Value); return ok; }; static ERL_NIF_TERM hash2(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) { ErlNifUInt64 Salt; if (!enif_get_uint64(env, argv[1], &Salt)) return enif_make_badarg(env); ErlNifBinary Value; if (!enif_term_to_binary(env, argv[0], &Value)) return enif_make_badarg(env); enif_release_binary(&Value); Salt = enif_hash(ERL_NIF_INTERNAL_HASH, argv[1], 2423432432); return ok; }; static ERL_NIF_TERM hash3(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) { ErlNifUInt64 Salt; if (!enif_get_uint64(env, argv[1], &Salt)) return enif_make_badarg(env); ErlNifBinary Value; if (!enif_term_to_binary(env, argv[0], &Value)) return enif_make_badarg(env); Salt = murmurhash(Value.data, Value.size, 0); enif_release_binary(&Value); return ok; }; static uint8_t compareChar1(const unsigned char *src, const unsigned char *dst, size_t Size) { // int j = 0; // unsigned char *tsrc, *tdst; // tsrc = src; // tdst = dst; // for(j = 0; j <= Size; j++) // { // enif_fprintf(stdout, "IMY************get9999111 src %d dst %d \n", *tsrc, *tdst); // tsrc++; // tdst++; // } uint8_t i = 0; while (i < Size-1 && (*src == *dst)) { // enif_fprintf(stdout, "IMY************get99992222 %d %d \n", *src, *dst); src++; dst++; i++; } //enif_fprintf(stdout, "IMY************get9999while end %d %d \n", *src, *dst); if (*src != *dst) { //enif_fprintf(stdout, "IMY************get99993333 %d %d \n", *src, *dst); return 1; } else { //enif_fprintf(stdout, "IMY************get99995555 %d %d \n", *src, *dst); return 0; } } static uint8_t compareChar2(const unsigned char *src, const unsigned char *dst, size_t Size) { const uint32_t *intSrc = NULL; const uint32_t *intDst = NULL; const uint8_t *tailSrc = NULL; // tail - last 8 bytes const uint8_t *tailDst = NULL; // tail - last 8 bytes int l = Size / 4; // chunk length intSrc = (const uint32_t *) src; // body intDst = (const uint32_t *) dst; // body tailSrc = (const uint8_t *) (src + l * 4); // last 8 byte chunk of `key' tailDst = (const uint8_t *) (dst + l * 4); // last 8 byte chunk of `key' // for each 4 byte chunk of `key' int i = 0; for (i = 0; i < l; i++) { if (intSrc[i] != intDst[i]) return 1; } // remainder switch (Size & 3) { case 3: if (tailSrc[0] != tailDst[0] || tailSrc[1] != tailDst[1] || tailSrc[2] != tailDst[2]) { return 1; } break; case 2: if (tailSrc[0] != tailDst[0] || tailSrc[1] != tailDst[1]) { return 1; } break; case 1: if (tailSrc[0] != tailDst[0]) { return 1; } break; } return 0; } static ERL_NIF_TERM compareBin1(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) { ErlNifBinary src, dst; if (!(enif_inspect_binary(env, argv[0], &src) && enif_inspect_binary(env, argv[1], &dst))) return enif_make_badarg(env); if (src.size != dst.size) { return enif_make_int(env, 1); } int Ret = compareChar1(src.data, dst.data, src.size); return enif_make_int(env, Ret); } static ERL_NIF_TERM compareBin2(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) { ErlNifBinary src, dst; if (!(enif_inspect_binary(env, argv[0], &src) && enif_inspect_binary(env, argv[1], &dst))) return enif_make_badarg(env); if (src.size != dst.size) { return enif_make_int(env, 1); } int Ret = compareChar2(src.data, dst.data, src.size); return enif_make_int(env, Ret); } ///////////////////////////////////////////////////////////////////// static int load(ErlNifEnv *env, void **priv, ERL_NIF_TERM load_info) { ErlNifResourceFlags flags = ERL_NIF_RT_CREATE | ERL_NIF_RT_TAKEOVER; ResType = enif_open_resource_type(env, NULL, "_nifHashb_", NULL, flags, NULL); if (NULL == ResType) return -1; undefined = enif_make_atom(env, "undefined"); ok = enif_make_atom(env, "ok"); return 0; } static ERL_NIF_TERM new(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) { hashb *ResPtr = (hashb *) enif_alloc_resource(ResType, sizeof(hashb)); ResPtr->keySize = 0; ResPtr->bblSize_1 = BBLSIZE_1; ResPtr->bblSize_2 = BBLSIZE_2; ResPtr->arrayPtr = enif_alloc(sizeof(bbl *) * BBLSIZE_1); int i, j; bbl NullBbl; NullBbl.head = NULL; for (i = 0; i < BBLSIZE_1; i++) { ResPtr->arrayPtr[i] = enif_alloc(sizeof(bbl) * BBLSIZE_2); for (j = 0; j < BBLSIZE_2; j++) { ResPtr->arrayPtr[i][j] = NullBbl; } } ERL_NIF_TERM Res = enif_make_resource(env, ResPtr); enif_release_resource(ResPtr); return Res; } static uint8_t compareChar(const unsigned char *src, const unsigned char *dst, size_t Size) { const uint32_t *intSrc = NULL; const uint32_t *intDst = NULL; const uint8_t *tailSrc = NULL; // tail - last 8 bytes const uint8_t *tailDst = NULL; // tail - last 8 bytes int l = Size / 4; // chunk length intSrc = (const uint32_t *) src; // body intDst = (const uint32_t *) dst; // body tailSrc = (const uint8_t *) (src + l * 4); // last 8 byte chunk of `key' tailDst = (const uint8_t *) (dst + l * 4); // last 8 byte chunk of `key' // for each 4 byte chunk of `key' int i = 0; for (i = 0; i < l; i++) { if (intSrc[i] != intDst[i]) return 1; } // remainder switch (Size & 3) { case 3: if (tailSrc[0] != tailDst[0] || tailSrc[1] != tailDst[1] || tailSrc[2] != tailDst[2]) { return 1; } break; case 2: if (tailSrc[0] != tailDst[0] || tailSrc[1] != tailDst[1]) { return 1; } break; case 1: if (tailSrc[0] != tailDst[0]) { return 1; } break; } return 0; } static uint8_t compareBin(ErlNifBinary src, ErlNifBinary dst) { if (src.size != dst.size) { //enif_fprintf(stdout, "IMY************get8888\n"); return 1; } //enif_fprintf(stdout, "IMY************get8888111 %d \n", src.size); return compareChar(src.data, dst.data, src.size); } static ERL_NIF_TERM get(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) { hashb *ResPtr; if (!enif_get_resource(env, argv[0], ResType, (void **) &ResPtr)) { return enif_make_badarg(env); } //enif_fprintf(stdout, "IMY************get1111\n"); ErlNifBinary getKey; if (!enif_term_to_binary(env, argv[1], &getKey)) return enif_make_badarg(env); //enif_fprintf(stdout, "IMY************get2222\n"); uint32_t BblIndex_1, BblIndex_2; BblIndex_1 = murmurhash(getKey.data, getKey.size, 131) % ResPtr->bblSize_1; BblIndex_2 = murmurhash(getKey.data, getKey.size, 16777619) % ResPtr->bblSize_2; //enif_fprintf(stdout, "IMY************get3333\n"); if (NULL == ResPtr->arrayPtr[BblIndex_1][BblIndex_2].head) { //enif_fprintf(stdout, "IMY************get4444\n"); enif_release_binary(&getKey); return undefined; } else { // enif_fprintf(stdout, "IMY************get55555\n"); node *Head = ResPtr->arrayPtr[BblIndex_1][BblIndex_2].head; while (Head) { // enif_fprintf(stdout, "IMY************get7777\n"); if (compareBin(getKey, Head->Key) == 0) { ERL_NIF_TERM Ret; enif_binary_to_term(env, Head->Value.data, Head->Value.size, &Ret, 0); //enif_fprintf(stdout, "IMY************get5555\n"); enif_release_binary(&getKey); return Ret; } Head = Head->next; } //enif_fprintf(stdout, "IMY************get6666\n"); enif_release_binary(&getKey); return undefined; } } static ERL_NIF_TERM put(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) { hashb *ResPtr; if (!enif_get_resource(env, argv[0], ResType, (void **) &ResPtr)) { return enif_make_badarg(env); } //enif_fprintf(stdout, "IMY************put111 \n"); ErlNifBinary Key, Value; if (!enif_term_to_binary(env, argv[1], &Key)) return enif_make_badarg(env); if (!enif_term_to_binary(env, argv[2], &Value)) return enif_make_badarg(env); uint32_t BblIndex_1, BblIndex_2; BblIndex_1 = murmurhash(Key.data, Key.size, 131) % ResPtr->bblSize_1; BblIndex_2 = murmurhash(Key.data, Key.size, 16777619) % ResPtr->bblSize_2; //enif_fprintf(stdout, "IMY************put222 %d %d \n", BblIndex_1, BblIndex_2); //enif_fprintf(stdout, "IMY************put3333 \n"); if (NULL == ResPtr->arrayPtr[BblIndex_1][BblIndex_2].head) { node *NewNode = enif_alloc(sizeof(node)); NewNode->Key = Key; NewNode->Value = Value; NewNode->next = NULL; ResPtr->arrayPtr[BblIndex_1][BblIndex_2].head = NewNode; ResPtr->keySize = ResPtr->keySize + 1; //enif_fprintf(stdout, "IMY************put4444 \n"); return ok; } else { node *Head = ResPtr->arrayPtr[BblIndex_1][BblIndex_2].head; while (Head) { if (compareBin(Key, Head->Key) == 0) { //ERL_NIF_TERM Ret; ErlNifBinary OldValue = Head->Value; //enif_binary_to_term(env, OldValue.data, OldValue.size, &Ret, 0); Head->Value = Value; enif_release_binary(&OldValue); enif_release_binary(&Key); //enif_fprintf(stdout, "IMY************put55555 \n"); //return Ret; return ok; } Head = Head->next; } node *NewNode = enif_alloc(sizeof(node)); NewNode->Key = Key; NewNode->Value = Value; NewNode->next = ResPtr->arrayPtr[BblIndex_1][BblIndex_2].head; ResPtr->arrayPtr[BblIndex_1][BblIndex_2].head = NewNode; ResPtr->keySize = ResPtr->keySize + 1; //enif_fprintf(stdout, "IMY************put6666\n"); return ok; } } ///////////////////////////////////////////////////////////////////////// static ErlNifFunc nifFuns[] = { {"new", 0, new}, {"get", 2, get}, {"put", 3, put}, {"hash1", 2, hash1}, {"hash2", 2, hash2}, {"hash3", 2, hash3}, {"compareBin1", 2, compareBin1}, {"compareBin2", 2, compareBin2}, }; ERL_NIF_INIT(nifHashb, nifFuns, &load, NULL, NULL, NULL)