Current section

Files

Jump to
mmath c_src bin_nif.c
Raw

c_src/bin_nif.c

#include "erl_nif.h"
#include "mmath.h"
#include <math.h>
static int
load(ErlNifEnv* env, void** priv, ERL_NIF_TERM load_info)
{
return 0;
}
static int
upgrade(ErlNifEnv* env, void** priv, void** old_priv, ERL_NIF_TERM load_info)
{
return 0;
}
static ERL_NIF_TERM
to_list(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
ErlNifBinary a;
ERL_NIF_TERM *acc;
ERL_NIF_TERM r;
ErlNifSInt64* vs;
ERL_NIF_TERM last = enif_make_int(env, 0);
ffloat f;
unsigned count;
int64_t v;
int64_t v_overlay;
if (argc != 1)
return enif_make_badarg(env);
GET_BIN(0, a, count, vs);
acc = malloc(count * sizeof(ERL_NIF_TERM));
for (unsigned i = 0 ; i < count; i++) {
switch (TYPE(vs[i])) {
case EMPTY_TYPE:
// do nothing
break;
case INTEGER_TYPE:
v = ntohll(vs[i]);
v_overlay = v & VALUE_MASK;
if (v & VALUE_SIGN_MASK) {
v_overlay |= ((int64_t) -1) & ~ VALUE_MASK;
}
last = enif_make_int64(env, v_overlay);
break;
default:
f = float_deserialize(vs[i]);
last = enif_make_double(env, f.value);
}
acc[i] = last;
}
r = enif_make_list_from_array(env, acc, count);
free(acc);
return r;
}
static ERL_NIF_TERM
from_list(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
ERL_NIF_TERM list;
ERL_NIF_TERM cell;
ErlNifSInt64 int_v;
double float_v;
ErlNifSInt64* target;
ERL_NIF_TERM r;
unsigned count;
ffloat d;
if (argc != 1)
return enif_make_badarg(env);
list = argv[0];
if (!enif_get_list_length(env, list, &count))
return enif_make_badarg(env);
if (!(target = (ErlNifSInt64*) enif_make_new_binary(env, count * sizeof(ErlNifSInt64), &r)))
return enif_make_badarg(env); // TODO return propper error
for (int i = 0; i < count; i++) {
if (! enif_get_list_cell(env, list, &cell, &list))
return enif_make_badarg(env); // TODO return propper error
if (enif_get_int64(env, cell, &int_v)) {
target[i] = TO_DDB_INT(int_v);
} else if (enif_get_double(env, cell, &float_v)){
d = float_from_double(float_v);
target[i] = float_serialize(d);
} else {
return enif_make_badarg(env);}
}
return r;
}
static ERL_NIF_TERM
rdatasize(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
if (argc != 0)
return enif_make_badarg(env);
return enif_make_int(env, sizeof(ffloat));
}
static ERL_NIF_TERM
realize(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
ErlNifBinary a;
ERL_NIF_TERM r;
ErlNifSInt64* vs;
ffloat* target;
ffloat last = {.value = 0, .confidence = 0};
int has_last = 0;
int count;
if (argc != 1)
return enif_make_badarg(env);
GET_BIN(0, a, count, vs);
if (! (target = (ffloat*) enif_make_new_binary(env, count * sizeof(ffloat), &r)))
return enif_make_badarg(env); // TODO return propper error
for (int i = 0; i < count; i++) {
last.confidence = 0;
if (IS_SET(vs[i])) {
last = FROM_DDB(vs[i]);
if (! has_last) {
for (int j = 0; j < i; j++) {
target[j] = last;
target[j].confidence = 0;
}
has_last = 1;
}
};
target[i] = last;
}
return r;
}
static ERL_NIF_TERM
derealize(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
ErlNifBinary a;
ERL_NIF_TERM r;
ffloat* vs;
ErlNifSInt64* target;
int count;
if (argc != 1)
return enif_make_badarg(env);
GET_BIN(0, a, count, vs);
if (! (target = (ErlNifSInt64*) enif_make_new_binary(env, count * sizeof(ErlNifSInt64), &r)))
return enif_make_badarg(env); // TODO return propper error
for (int i = 0; i < count; i++) {
target[i] = TO_DDB(vs[i]);
}
return r;
}
static ERL_NIF_TERM
replicate(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
ErlNifBinary bin;
ERL_NIF_TERM r;
ffloat* vs;
ffloat* target;
ErlNifSInt64 rep_size; // replication factor
uint32_t count;
uint32_t pos;
uint32_t target_size;
if (argc != 2)
return enif_make_badarg(env);
GET_CHUNK(rep_size);
GET_BIN(0, bin, count, vs);
target_size = ceil(count * rep_size * sizeof(ffloat));
if (! (target = (ffloat*) enif_make_new_binary(env, target_size, &r)))
return enif_make_badarg(env); // TODO return propper error
// If we don't have any input data we can return right away.
if (count == 0)
return r;
// We iterate over the input i..count elements, making rep_size copies of each
for (uint32_t i = 0; i < count; i++) {
for (uint32_t j = 0; j < rep_size; j++) {
pos = (i * rep_size) + j;
target[pos] = vs[i];
}
}
return r;
}
static ERL_NIF_TERM
clean(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
ErlNifBinary a;
ERL_NIF_TERM r;
ErlNifSInt64* vs;
ErlNifSInt64* target;
unsigned count;
unsigned j = 0;
if (argc != 1)
return enif_make_badarg(env);
GET_BIN(0, a, count, vs);
if (count % 2)
return enif_make_badarg(env); // TODO return propper error
if (!(target = (ErlNifSInt64*) enif_make_new_binary(env, (count / 2) * sizeof(ErlNifSInt64), &r)))
return enif_make_badarg(env); // TODO return propper error
for (unsigned i = 1 ; i < count; i = i + 2) {
target[j] = vs[i];
j++;
}
return r;
}
char get_type(ErlNifSInt64 ev) {
int64_t v = ntohll(ev);
return (uint8_t)((v & TYPE_MASK) >> 56);
}
static ErlNifFunc nif_funcs[] = {
{"from_list", 1, from_list},
{"to_list", 1, to_list},
{"rdatasize", 0, rdatasize},
{"realize", 1, realize},
{"derealize", 1, derealize},
{"replicate", 2, replicate},
{"clean", 1, clean}
};
// Initialize this NIF library.
//
// Args: (MODULE, ErlNifFunc funcs[], load, reload, upgrade, unload)
// Docs: http://erlang.org/doc/man/erl_nif.html#ERL_NIF_INIT
ERL_NIF_INIT(mmath_bin, nif_funcs, &load, NULL, &upgrade, NULL);