Skip to content

Instantly share code, notes, and snippets.

@Bad-ptr

Bad-ptr/build.sh Secret

Last active July 25, 2016 11:32
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Bad-ptr/3ea0d6d65ae18b5b68c6cb15a96fef8e to your computer and use it in GitHub Desktop.
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.
#!/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"
#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);
-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".
#!/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