-
-
Save Bad-ptr/3ea0d6d65ae18b5b68c6cb15a96fef8e to your computer and use it in GitHub Desktop.
[This will not work] Doubly linked list for erlang as a NIF module.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/bash | |
ERLANG_INCLUDE_PATH="$(erl -eval 'io:format("~s", [lists:concat([code:root_dir(), "/erts-", erlang:system_info(version), "/include"])])' -s init stop -noshell)" | |
cc -fPIC -shared -o dllist.so dllist.c -I"$ERLANG_INCLUDE_PATH" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <erl_nif.h> | |
static ErlNifResourceType *DLLIST_RESOURCE; | |
typedef struct dllist_cell_s { | |
struct dllist_cell_s *prev, *next; | |
ERL_NIF_TERM data; //XXX: how to properly store erlang objects here? | |
} dllist_cell_t; | |
typedef struct DLList_s { | |
dllist_cell_t *head, *tail; | |
unsigned int length; | |
} DLList_t; | |
static ERL_NIF_TERM new(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) { | |
DLList_t *ret = (DLList_t*)enif_alloc_resource(DLLIST_RESOURCE, sizeof(DLList_t)); | |
ret->head = ret->tail = NULL; | |
ret->length = 0; | |
ERL_NIF_TERM ret_term = enif_make_resource(env, (void*)ret); | |
enif_release_resource((void*)ret); | |
return ret_term; | |
} | |
static ERL_NIF_TERM push(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) { | |
DLList_t *list = NULL; | |
if (!enif_get_resource(env, argv[0], DLLIST_RESOURCE, (void**)&list)) | |
return enif_make_badarg(env); | |
ERL_NIF_TERM item = argv[1]; | |
dllist_cell_t *new_tail = enif_alloc(sizeof(dllist_cell_t)); | |
new_tail->prev = list->tail; | |
new_tail->next = NULL; | |
new_tail->data = item; //XXX: is it safe to store ERL_NIF_TERM here? I guess it is not. | |
if (1 > list->length) list->head = new_tail; | |
list->tail = new_tail; | |
list->length += 1; | |
return item; | |
} | |
int DLList_pop(DLList_t *list, ERL_NIF_TERM *out) { | |
if (NULL == list || 1 > list->length) return 0; | |
dllist_cell_t *old_tail = list->tail; | |
if (NULL != out) *out = old_tail->data; | |
list->tail = old_tail->prev; | |
if (NULL != list->tail) list->tail->next = NULL; | |
list->length -= 1; | |
if (1 > list->length) list->head = NULL; | |
enif_free(old_tail); | |
return 1; | |
} | |
static ERL_NIF_TERM pop(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) { | |
DLList_t *list; | |
if (!enif_get_resource(env, argv[0], DLLIST_RESOURCE, (void**)&list)) | |
return enif_make_badarg(env); | |
ERL_NIF_TERM ret; | |
if (0 == DLList_pop(list, &ret)) return enif_make_badarg(env); | |
return ret; | |
} | |
int DLList_clear(DLList_t *list) { | |
if (NULL == list) return 0; | |
while (0 < list->length) DLList_pop(list, NULL); | |
return 1; | |
} | |
static ERL_NIF_TERM kill(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) { | |
DLList_t *list; | |
if (!enif_get_resource(env, argv[0], DLLIST_RESOURCE, (void**)&list)) | |
return enif_make_badarg(env); | |
if (0 == DLList_clear(list)) return enif_make_badarg(env); | |
return enif_make_atom(env, "ok"); | |
} | |
static void cleanup(ErlNifEnv *env, void *obj){ | |
DLList_t *list = obj; | |
DLList_clear(list, NULL); | |
enif_free(list); | |
}; | |
static int load(ErlNifEnv *env, void **priv_data, ERL_NIF_TERM load_info) { | |
*priv_data = NULL; | |
DLLIST_RESOURCE = enif_open_resource_type(env, NULL, "dllist_resource", cleanup, ERL_NIF_RT_CREATE|ERL_NIF_RT_TAKEOVER, NULL); | |
if (DLLIST_RESOURCE == NULL) | |
return -1; | |
return 0; | |
} | |
static ErlNifFunc funcs[] = { | |
{"new", 0, new}, | |
{"kill", 1, kill}, | |
{"push", 2, push}, | |
{"pop", 1, pop} | |
}; | |
ERL_NIF_INIT(dllist, funcs, load, NULL, NULL, NULL); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
-module(dllist). | |
-export([new/0, kill/1, push/2, pop/1]). | |
-on_load(init/0). | |
init() -> | |
erlang:load_nif("./dllist", 0). | |
new() -> | |
"dllist NIF module is not loaded". | |
kill(dllist) -> | |
"dllist NIF module is not loaded". | |
push(dllist,item) -> | |
"dllist NIF module is not loaded". | |
pop(dllist) -> | |
"dllist NIF module is not loaded". |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env escript | |
%% -*- erlang -*- | |
%%! -smp enable -sname dllisttest | |
test(_) -> | |
%% Testobject0 = 1, | |
%% Testobject1 = 123124125125, | |
%% Testobject2 = 1.0, | |
%% Testobject3 = [1123,2], | |
%% Testobject4 = {123, {1,{3,4,[6,7]}}}, | |
%% c(dllist), | |
Testobject0 = "test", | |
Testobject1 = "long long test long", | |
Testobject2 = 1 , | |
Testobject3 = [1,2], | |
Testobject4 = {"test"}, | |
Dlist = dllist:new(), | |
dllist:push(Dlist, Testobject0), | |
dllist:push(Dlist, Testobject1), | |
dllist:push(Dlist, Testobject2), | |
dllist:push(Dlist, Testobject3), | |
dllist:push(Dlist, Testobject4), | |
TestRet0 = dllist:pop(Dlist), | |
TestRet1 = dllist:pop(Dlist), | |
TestRet2 = dllist:pop(Dlist), | |
TestRet3 = dllist:pop(Dlist), | |
TestRet4 = dllist:pop(Dlist), | |
dllist:push(Dlist, Testobject0), | |
dllist:push(Dlist, Testobject1), | |
dllist:push(Dlist, Testobject2), | |
dllist:push(Dlist, Testobject3), | |
TestRet5 = dllist:pop(Dlist), | |
io:format("~p~n",[[TestRet0, TestRet1, TestRet2, TestRet3, TestRet4, TestRet5]]). | |
main(Args) -> | |
test(Args). |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment