erlang各种有用的函数包括一些有用nif封装,还有一些性能测试case。
Você não pode selecionar mais de 25 tópicos Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') e podem ter até 35 caracteres.
 
 
 
 
 
 

448 linhas
8.5 KiB

#include "erl_nif.h"
ErlNifResourceType* bsn_type;
ERL_NIF_TERM ATOM_TRUE, ATOM_FALSE;
/*
typedef struct {
unsigned size;
unsigned char* data;
} ErlNifBinary;
*/
struct bsn_elem_struct {
ErlNifBinary bin;
struct bsn_elem_struct* next;
};
typedef struct bsn_elem_struct bsn_elem;
typedef bsn_elem* bsn_list;
typedef struct {
unsigned int count; /* count of elements */
unsigned int max; /* count of slots */
ErlNifMutex *mutex;
bsn_list* list;
} bsn_res;
inline static ERL_NIF_TERM bool_to_term(int value) {
return value ? ATOM_TRUE : ATOM_FALSE;
}
/* 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 void
private_clear_elem(bsn_elem* el)
{
enif_release_binary(&(el->bin));
enif_free(el);
}
inline void
private_chain_clear_all(bsn_elem* ptr)
{
bsn_elem* next;
while (ptr != NULL) {
next = ptr->next;
private_clear_elem(ptr);
ptr = next;
}
}
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;
}
/* Skip existing elements. If the element bin is not found, return last element.
* If el.bin == bin, return el. */
bsn_elem*
private_chain_shift(bsn_elem* ptr, ErlNifBinary* bin, int* num_ptr)
{
(*num_ptr)++;
if ((ptr) == NULL)
return ptr;
while (1) {
if (private_compare(&(ptr->bin), bin)) {
/* found an equal binary. Invert num */
(*num_ptr) *= -1;
return ptr;
}
if ((ptr->next) == NULL)
return ptr;
ptr = ptr->next;
(*num_ptr)++;
}
}
/* Append the element `el' to the chain `chain' */
void
private_chain_append(bsn_elem** chain, bsn_elem* el, int* num_ptr)
{
bsn_elem* last;
if ((*chain) == NULL) {
/* The new element is last */
*chain = el;
} else {
last = private_chain_shift(*chain, &(el->bin), num_ptr);
if ((*num_ptr) < 0) {
/* Element was already added. */
private_clear_elem(el);
} else {
last->next = el;
}
}
}
bsn_elem*
private_chain_shift_clear(bsn_elem** ptr, ErlNifBinary* bin, int* num_ptr)
{
bsn_elem** prev = NULL;
bsn_elem* el;
while ((*ptr) != NULL) {
if (private_compare(&((*ptr)->bin), bin)) {
(*num_ptr) *= -1;
/* found an equal binary. Delete elem. Invert num */
if (prev == NULL) {
el = *ptr;
(*ptr) = (*ptr)->next;
return el;
}
*prev = (*ptr)->next;
return *ptr;
}
prev = ptr;
el = *ptr;
ptr = (bsn_elem**) &(el->next);
(*num_ptr)++;
}
return NULL;
}
static ERL_NIF_TERM
bsn_new(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
unsigned int max;
bsn_list* ptr;
bsn_res* r;
if (!(enif_get_uint(env, argv[0], &max) && (max>0)))
return enif_make_badarg(env);
ptr = enif_alloc(sizeof(bsn_list) * max);
if (ptr == NULL)
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;
r->max = max;
r->list = ptr;
for (; max; max--, ptr++)
*ptr = NULL;
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;
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);
pos = private_hash(&bin, r->max);
elem_ptr = enif_alloc(sizeof(bsn_elem));
if (elem_ptr == NULL)
return enif_make_badarg(env);
elem_ptr->next = NULL;
elem_ptr->bin = bin;
enif_mutex_lock(r->mutex);
private_chain_append(&(r->list[pos]), elem_ptr, &num);
if (num >= 0)
(r->count)++;
enif_mutex_unlock(r->mutex);
/* Already added */
if (num < 0)
enif_release_binary(&(bin));
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;
int num = 0;
if (!(enif_get_resource(env, argv[0], bsn_type, (void**) &r)
&& enif_inspect_binary(env, argv[1], &bin)))
return enif_make_badarg(env);
pos = private_hash(&bin, r->max);
enif_mutex_lock(r->mutex);
private_chain_shift(r->list[pos], &bin, &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[])
{
ErlNifBinary bin;
bsn_res* r;
unsigned int pos;
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);
pos = private_hash(&bin, r->max);
enif_mutex_lock(r->mutex);
elem_ptr = private_chain_shift_clear(&(r->list[pos]), &bin, &num);
if (elem_ptr != NULL) {
private_clear_elem(elem_ptr);
(r->count)--;
}
enif_mutex_unlock(r->mutex);
return enif_make_int(env, num);
}
static ERL_NIF_TERM
bsn_all_chain(ErlNifEnv* env, bsn_elem* e, ERL_NIF_TERM tail)
{
ERL_NIF_TERM head;
ErlNifBinary bin;
while (e != NULL) {
bin = e->bin;
enif_realloc_binary(&bin, bin.size);
head = enif_make_binary(env, &bin);
tail = enif_make_list_cell(env, head, tail);
e = e->next;
}
return tail;
}
static ERL_NIF_TERM
bsn_chains(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
bsn_res* r;
unsigned int max;
bsn_list* ptr;
ERL_NIF_TERM tail, head;
if (!enif_get_resource(env, argv[0], bsn_type, (void**) &r))
return enif_make_badarg(env);
tail = enif_make_list(env, 0);
ptr = r->list;
enif_mutex_lock(r->mutex);
max = r->max;
while (max) {
head = enif_make_list(env, 0);
head = bsn_all_chain(env, *ptr, head);
tail = enif_make_list_cell(env, head, tail);
ptr++;
max--;
}
enif_mutex_unlock(r->mutex);
return tail;
}
static ERL_NIF_TERM
bsn_all(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
bsn_res* r;
unsigned int max;
bsn_list* ptr;
ERL_NIF_TERM list;
if (!enif_get_resource(env, argv[0], bsn_type, (void**) &r))
return enif_make_badarg(env);
list = enif_make_list(env, 0);
ptr = r->list;
enif_mutex_lock(r->mutex);
max = r->max;
while (max) {
list = bsn_all_chain(env, *ptr, list);
ptr++;
max--;
}
enif_mutex_unlock(r->mutex);
return list;
}
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);
}
static ERL_NIF_TERM
bsn_hash(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
ErlNifBinary bin;
unsigned int max;
if (!(enif_inspect_binary(env, argv[0], &bin)
&& enif_get_uint(env, argv[1], &max) && (max>0)))
return enif_make_badarg(env);
return enif_make_uint(env,
private_hash(&bin, max));
}
static ERL_NIF_TERM
bsn_compare(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
ErlNifBinary b1, b2;
if (!(enif_inspect_binary(env, argv[0], &b1)
&& enif_inspect_binary(env, argv[1], &b2)))
return enif_make_badarg(env);
return bool_to_term(private_compare(&b1, &b2));
}
void private_clear_all(bsn_res* r)
{
unsigned int max;
bsn_list* ptr;
max = r->max;
ptr = r->list;
while (max) {
private_chain_clear_all(*ptr);
ptr++;
max--;
}
}
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");
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},
{"chains", 1, bsn_chains},
{"in", 2, bsn_search},
{"clear", 2, bsn_clear},
{"count", 1, bsn_count},
{"hash", 2, bsn_hash},
{"compare", 2, bsn_compare},
};
ERL_NIF_INIT(bsn_ext, nif_functions, &on_load, &on_load, &on_upgrade, NULL);