erlang各种有用的函数包括一些有用nif封装,还有一些性能测试case。
Nevar pievienot vairāk kā 25 tēmas Tēmai ir jāsākas ar burtu vai ciparu, tā var saturēt domu zīmes ('-') un var būt līdz 35 simboliem gara.
 
 
 
 
 
 

364 rindas
9.4 KiB

//
// Created by fox on 2017/8/10.
//
#ifndef USENIF
#define USENIF 1
#endif
#include <string.h>
#include "erl_nif.h"
#include "skiplist.h"
// all pointer to skiplist would be stored here
static skiplist **p_array;
static size_t p_array_size = 0;
#define enif_get_value enif_get_int
#define enif_make_value enif_make_int
// store a new pointer
int store_new_pointer(skiplist *p)
{
if (p_array_size == 0) {
// init it
p_array_size = 2;
p_array = (skiplist **)icalloc(p_array_size * sizeof(skiplist *));
p_array[0] = p;
return 0;
}
// find the empty pos
for (int i = 0; i < p_array_size; ++i) {
if (p_array[i] == NULL) {
p_array[i] = p;
return i;
}
}
// reallocate array
size_t old_size = p_array_size;
p_array_size *= 2;
p_array = (skiplist **)realloc(p_array, sizeof(skiplist *) * p_array_size);
memset(p_array+old_size, 0, sizeof(skiplist *) * old_size);
p_array[old_size] = p;
return (int)old_size;
}
inline skiplist *get_pointer(ErlNifEnv* env, ERL_NIF_TERM arg);
skiplist *get_pointer(ErlNifEnv* env, ERL_NIF_TERM arg)
{
int index;
if (!enif_get_int(env, arg, &index))
return NULL;
if (0 <= index && index < p_array_size)
return p_array[index];
return NULL;
}
static ERL_NIF_TERM new(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
skiplist *list = skiplist_init();
int pointer_pos = store_new_pointer(list);
ERL_NIF_TERM res = enif_make_int(env, pointer_pos);
return res;
}
static ERL_NIF_TERM free1(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
int index;
if (!enif_get_int(env, argv[0], &index))
return enif_make_badarg(env);
if (index < 0 || index >= p_array_size)
return enif_make_badarg(env);
skiplist_free(p_array[index]);
p_array[index] = NULL;
ERL_NIF_TERM res;
enif_make_existing_atom(env, "ok", &res, ERL_NIF_LATIN1);
return res;
}
static ERL_NIF_TERM insert(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
skiplist *list = get_pointer(env, argv[0]);
if (!list)
return enif_make_badarg(env);
int score;
vtype value;
if (!enif_get_int(env, argv[1], &score))
return enif_make_badarg(env);
if (!enif_get_value(env, argv[2], &value))
return enif_make_badarg(env);
int res0 = skiplist_insert(list, score, value);
ERL_NIF_TERM res = enif_make_int(env, res0);
return res;
}
static ERL_NIF_TERM update(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
skiplist *list = get_pointer(env, argv[0]);
if (!list)
return enif_make_badarg(env);
int score, old_score;
vtype value;
if (!enif_get_int(env, argv[1], &score))
return enif_make_badarg(env);
if (!enif_get_value(env, argv[2], &value))
return enif_make_badarg(env);
if (!enif_get_int(env, argv[3], &old_score))
return enif_make_badarg(env);
int res0 = skiplist_update(list, score, value, old_score);
ERL_NIF_TERM res = enif_make_int(env, res0);
return res;
}
static ERL_NIF_TERM delete(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
skiplist *list = get_pointer(env, argv[0]);
if (!list)
return enif_make_badarg(env);
int socre;
vtype value;
if (!enif_get_int(env, argv[1], &socre))
return enif_make_badarg(env);
if (!enif_get_value(env, argv[2], &value))
return enif_make_badarg(env);
int res0 = skiplist_delete(list, socre, value);
ERL_NIF_TERM res = enif_make_int(env, res0);
return res;
}
static ERL_NIF_TERM to_list(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
skiplist *list = get_pointer(env, argv[0]);
if (!list)
return enif_make_badarg(env);
snode *x = list->header->level[0].forward;
snode **nodes = (snode **)malloc(sizeof(snode *) * (list->size + 1));
while (x) {
*nodes = x;
++nodes;
x = x->level[0].forward;
}
ERL_NIF_TERM res = enif_make_list(env, 0);
for (int i = list->size-1; i >= 0; --i) {
--nodes;
ERL_NIF_TERM item = enif_make_tuple(
env,
2,
enif_make_int(env, (*nodes)->score),
enif_make_value(env, (*nodes)->value));
res = enif_make_list_cell(env, item, res);
}
free(nodes);
return res;
}
static ERL_NIF_TERM size1(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
skiplist *list = get_pointer(env, argv[0]);
if (!list)
return enif_make_badarg(env);
ERL_NIF_TERM res = enif_make_int(env, list->size);
return res;
}
// first index of the score
static ERL_NIF_TERM index_of_score(ErlNifEnv *env, int argc, const ERL_NIF_TERM *argv)
{
skiplist *list = get_pointer(env, argv[0]);
if (!list)
return enif_make_badarg(env);
int socre;
if (!enif_get_int(env, argv[1], &socre))
return enif_make_badarg(env);
int res0 = skiplist_index_of_score(list, socre);
ERL_NIF_TERM res = enif_make_int(env, res0);
return res;
}
static ERL_NIF_TERM at(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
skiplist *list = get_pointer(env, argv[0]);
if (!list)
return enif_make_badarg(env);
int index;
if (!enif_get_int(env, argv[1], &index))
return enif_make_badarg(env);
snode *x = skiplist_at(list, index);
ERL_NIF_TERM res;
if (x) {
res = enif_make_tuple(
env,
2,
enif_make_int(env, x->score),
enif_make_value(env, x->value));
} else {
enif_make_existing_atom(env, "error", &res, ERL_NIF_LATIN1);
}
return res;
}
static ERL_NIF_TERM range_by_score(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
skiplist *list = get_pointer(env, argv[0]);
if (!list)
return enif_make_badarg(env);
int score1, score2;
if (!enif_get_int(env, argv[1], &score1))
return enif_make_badarg(env);
if (!enif_get_int(env, argv[2], &score2))
return enif_make_badarg(env);
skiplist_search_ret res0;
skiplist_search(list, score1, &res0);
ERL_NIF_TERM ret_list = enif_make_list(env, 0);
for (snode *node = res0.node; node && node->score <= score2; node = node->level[0].forward) {
ret_list = enif_make_list_cell(env,
enif_make_tuple(env,
2,
enif_make_int(env, node->score),
enif_make_value(env, node->value)),
ret_list);
}
ERL_NIF_TERM ret_list1;
enif_make_reverse_list(env, ret_list, &ret_list1);
return enif_make_tuple(
env,
2,
enif_make_int(env, res0.index),
ret_list1);
}
static ERL_NIF_TERM range_1(
ErlNifEnv* env,
const ERL_NIF_TERM argv[],
ERL_NIF_TERM (*func_make_item)(ErlNifEnv *, snode *))
{
skiplist *list = get_pointer(env, argv[0]);
if (!list)
return enif_make_badarg(env);
int start, len;
if (!enif_get_int(env, argv[1], &start))
return enif_make_badarg(env);
if (!enif_get_int(env, argv[2], &len))
return enif_make_badarg(env);
int n = list->size - start + 1;
int alloc_size = n < len ? n : len;
ERL_NIF_TERM res = enif_make_list(env, 0);
if (alloc_size <= 0) {
return res;
}
snode **nodes = (snode **)malloc(sizeof(snode *) * (alloc_size + 1));
// get the nodes
snode *x = skiplist_at(list, start);
for (n = 0; n < alloc_size; n++) {
*nodes = x;
++nodes;
x = x->level[0].forward;
}
for (n = 0; n < alloc_size; n++) {
--nodes;
res = enif_make_list_cell(env, func_make_item(env, *nodes), res);
}
free(nodes);
return res;
}
inline static ERL_NIF_TERM range_make_item(ErlNifEnv* env, snode *node);
static ERL_NIF_TERM range_make_item(ErlNifEnv* env, snode *node)
{
return enif_make_value(env, node->value);
}
/* int p_list: identification of skiplist
* int start: >= 1, start index of skiplist
* int len: >= 1, max items to return
* return: [node]
*/
static ERL_NIF_TERM range(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
return range_1(env, argv, range_make_item);
}
inline static ERL_NIF_TERM range_with_score_make_item(ErlNifEnv* env, snode *node);
static ERL_NIF_TERM range_with_score_make_item(ErlNifEnv* env, snode *node)
{
return enif_make_tuple(
env,
2,
enif_make_int(env, node->score),
enif_make_value(env, node->value));
}
/* int p_list: identification of skiplist
* int start: >= 1, start index of skiplist
* int len: >= 1, max items to return
* return: [{score, node}]
*/
static ERL_NIF_TERM range_with_score(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
return range_1(env, argv, range_with_score_make_item);
}
static ErlNifFunc nif_funcs[] = {
{"new", 0, new},
{"free", 1, free1},
{"insert", 3, insert},
{"update", 4, update},
{"delete", 3, delete},
{"to_list", 1, to_list},
{"size", 1, size1},
{"index_of_score", 2, index_of_score},
{"at", 2, at},
{"range", 3, range},
{"range_with_score", 3, range_with_score},
{"range_by_score", 3, range_by_score},
};
ERL_NIF_INIT(skiplist, nif_funcs, NULL, NULL, NULL, NULL)