Current section
Files
Jump to
Current section
Files
src/median.c
#include <erl_nif.h>
#include "median_int.h"
#include "median_float.h"
static ERL_NIF_TERM median(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) {
ERL_NIF_TERM list = argv[0];
ERL_NIF_TERM head;
ERL_NIF_TERM tail;
ErlNifTermType t;
unsigned int len; // can we use size_t instead of unsigned int?
double *arr_float = NULL;
int *arr_int = NULL;
ERL_NIF_TERM res;
if (!enif_get_list_length(env, list, &len)) {
return enif_make_badarg(env); // not a proper list
}
if (len == 0) {
return enif_make_atom(env, "nil");
}
enif_get_list_cell(env, list, &head, &tail);
t = enif_term_type(env, head);
switch (t) {
case ERL_NIF_TERM_TYPE_FLOAT:
arr_float = enif_alloc(len * sizeof(double));
break;
case ERL_NIF_TERM_TYPE_INTEGER:
arr_int = enif_alloc(len * sizeof(int));
break;
default:
return enif_make_badarg(env);
}
if (!arr_float && !arr_int) {
return enif_raise_exception(env, enif_make_atom(env, "alloc"));
}
for (unsigned int i=0; i<len; i++) {
enif_get_list_cell(env, list, &head, &tail);
list = tail;
if (t == ERL_NIF_TERM_TYPE_FLOAT) {
if (!enif_get_double(env, head, &arr_float[i])) {
enif_free(arr_float);
return enif_make_badarg(env);
}
} else {
if (!enif_get_int(env, head, &arr_int[i])) {
enif_free(arr_int);
return enif_make_badarg(env);
}
}
}
if (t == ERL_NIF_TERM_TYPE_FLOAT) {
res = enif_make_double(env, median_double(arr_float, len));
enif_free(arr_float);
} else {
res = enif_make_int(env, median_int(arr_int, len));
enif_free(arr_int);
}
return res;
}
static ErlNifFunc nif_funcs[] = {
{"select", 1, median},
};
ERL_NIF_INIT(Elixir.Median, nif_funcs, NULL, NULL, NULL, NULL)