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

#include "erl_nif.h"
ErlNifResourceType* bsn_type;
ERL_NIF_TERM ATOM_TRUE, ATOM_FALSE, ATOM_NO_MORE;
struct bsn_elem_struct {
ErlNifBinary bin;
unsigned int hash;
};
typedef struct bsn_elem_struct bsn_elem;
typedef struct {
unsigned int count; /* count of elements */
unsigned int max; /* count of slots */
ErlNifMutex *mutex;
bsn_elem* list;
unsigned int (*next_pos)
(void*, unsigned int, unsigned int);
} bsn_res;
inline static ERL_NIF_TERM bool_to_term(int value) {
return value ? ATOM_TRUE : ATOM_FALSE;
}
unsigned int next_pos_linear(bsn_res* r, unsigned int hash, unsigned int step) {
return (hash + step) % (r->max);
}
unsigned int next_pos_quadric(bsn_res* r, unsigned int hash, unsigned int step) {
return (hash + (step*step)) % (r->max);
}
/* Calculate the sum of chars. */
unsigned int
private_hash(const ErlNifBinary* b, unsigned int max)
{
unsigned char* ptr;
unsigned int i, sum = 0;
ptr = b->data;
i = b->size;
for (; i; i--, ptr++)
sum += *ptr;
return sum % max;
}
inline int
private_compare(ErlNifBinary* b1, ErlNifBinary* b2)
{
unsigned char* p1;
unsigned char* p2;
unsigned len;
if (b1->size != b2->size)
return 0;
p1 = b1->data;
p2 = b2->data;
len = b1->size;
while (len) {
if ((*p1) != (*p2))
return 0;
len--; p1++; p2++;
}
return 1;
}
static ERL_NIF_TERM
bsn_new(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
int max; /* This value will be set by a client:
if (max<0) -> use quadric algorithm */
bsn_elem* ptr;
bsn_res* r;
if (!enif_get_int(env, argv[0], &max) || (max == 0))
return enif_make_badarg(env);
r = (bsn_res*) enif_alloc_resource(bsn_type, sizeof(bsn_res));
r->mutex = enif_mutex_create("Mutex for the BSN writer");
r->count = 0;
/* Select an algorithm */
if (max>0) {
r->next_pos = &next_pos_linear;
} else if (max<0) {
r->next_pos = &next_pos_quadric;
max *= -1;
}
/* Now max is cells' count in the array. */
r->max = (unsigned int) max;
ptr = enif_alloc(sizeof(bsn_elem) * max);
if (ptr == NULL)
return enif_make_badarg(env);
r->list = ptr;
for (; max; max--, ptr++)
ptr->hash = r->max;
return enif_make_resource(env, r);
}
static ERL_NIF_TERM
bsn_add(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
ErlNifBinary bin;
bsn_res* r;
unsigned int pos, hash, max;
int num = 0;
bsn_elem* elem_ptr;
if (!(enif_get_resource(env, argv[0], bsn_type, (void**) &r)
&& enif_inspect_binary(env, argv[1], &bin)))
return enif_make_badarg(env);
enif_realloc_binary(&bin, bin.size);
hash = pos = private_hash(&bin, r->max);
enif_mutex_lock(r->mutex);
max = r->max;
while (num < max) {
elem_ptr = &(r->list[pos]);
/* Found free space */
if (elem_ptr->hash == max) {
elem_ptr->bin = bin;
elem_ptr->hash = hash;
break;
}
/* Found elem */
if ((elem_ptr->hash == hash)
&& private_compare(&bin, &(elem_ptr->bin))) {
num *= -1;
break;
}
pos = (r->next_pos)(r, hash, num);
num++;
}
if ((num >= 0) && (num < max))
(r->count)++;
enif_mutex_unlock(r->mutex);
/* Error: already added or owerflow */
if (!((num >= 0) && (num < max)))
enif_release_binary(&bin);
if (num >= max)
return ATOM_NO_MORE;
return enif_make_int(env, num);
}
static ERL_NIF_TERM
bsn_search(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
ErlNifBinary bin;
bsn_res* r;
unsigned int pos, max, hash;
int num = 1;
bsn_elem* elem_ptr;
if (!(enif_get_resource(env, argv[0], bsn_type, (void**) &r)
&& enif_inspect_binary(env, argv[1], &bin)))
return enif_make_badarg(env);
hash = pos = private_hash(&bin, r->max);
enif_mutex_lock(r->mutex);
max = r->max;
while (num < max) {
elem_ptr = &(r->list[pos]);
/* Found free space */
if (elem_ptr->hash == max) {
break;
}
/* Found elem */
if ((elem_ptr->hash == hash)
&& private_compare(&bin, &(elem_ptr->bin))) {
num *= -1;
break;
}
pos = (r->next_pos)(r, hash, num);
num++;
}
enif_mutex_unlock(r->mutex);
return enif_make_int(env, num);
}
static ERL_NIF_TERM
bsn_clear(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
return enif_make_badarg(env);
}
static ERL_NIF_TERM
bsn_all(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
bsn_res* r;
unsigned int max, pos = 0;
ERL_NIF_TERM head, tail;
ErlNifBinary bin;
bsn_elem* elem_ptr;
if (!enif_get_resource(env, argv[0], bsn_type, (void**) &r))
return enif_make_badarg(env);
tail = enif_make_list(env, 0);
enif_mutex_lock(r->mutex);
max = r->max;
elem_ptr = r->list;
do {
if (elem_ptr->hash != max) {
bin = elem_ptr->bin;
enif_realloc_binary(&bin, bin.size);
head = enif_make_binary(env, &bin);
tail = enif_make_list_cell(env, head, tail);
}
elem_ptr++;
pos++;
} while (pos < max);
enif_mutex_unlock(r->mutex);
return tail;
}
static ERL_NIF_TERM
bsn_count(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
bsn_res* r;
if (!enif_get_resource(env, argv[0], bsn_type, (void**) &r))
return enif_make_badarg(env);
return enif_make_int(env, r->count);
}
void private_clear_all(bsn_res* r)
{
unsigned int max, num;
bsn_elem* ptr;
num = max = r->max;
ptr = r->list;
while (num) {
if (ptr->hash != max) {
enif_release_binary(&(ptr->bin));
}
ptr++;
num--;
}
}
void
bsn_type_dtor(ErlNifEnv* env, void* obj)
{
bsn_res* r = (bsn_res*) obj;
private_clear_all(r);
enif_mutex_destroy(r->mutex);
enif_free(r->list);
}
int
on_load(ErlNifEnv* env, void** priv, ERL_NIF_TERM info)
{
ATOM_TRUE = enif_make_atom(env, "true");
ATOM_FALSE = enif_make_atom(env, "false");
ATOM_NO_MORE = enif_make_atom(env, "no_more");
ErlNifResourceFlags flags = (ErlNifResourceFlags)(ERL_NIF_RT_CREATE |
ERL_NIF_RT_TAKEOVER);
bsn_type = enif_open_resource_type(env, NULL, "bsn_type",
bsn_type_dtor, flags, NULL);
if (bsn_type == NULL) return 1;
return 0;
}
int
on_upgrade(ErlNifEnv* env, void** priv, void** old_priv, ERL_NIF_TERM info)
{
return 0;
}
static ErlNifFunc nif_functions[] = {
{"new", 1, bsn_new},
{"add", 2, bsn_add},
{"all", 1, bsn_all},
{"in", 2, bsn_search},
{"clear", 2, bsn_clear},
{"count", 1, bsn_count},
};
ERL_NIF_INIT(bsn_int, nif_functions, &on_load, &on_load, &on_upgrade, NULL);