erlang各种有用的函数包括一些有用nif封装,还有一些性能测试case。
Nelze vybrat více než 25 témat Téma musí začínat písmenem nebo číslem, může obsahovat pomlčky („-“) a může být dlouhé až 35 znaků.
 
 
 
 
 
 

435 řádky
14 KiB

#include <stdint.h>
#include <string.h>
#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)