// // Created by fox on 2017/8/10. // #ifndef USENIF #define USENIF 1 #endif #include #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)