Browse Source

Use a resource for the decoder structure

This is ground work to allow Jiffy to yield back to the scheduler.
Creating a decoder resource will allow for the necessary state to be
carried across NIF function invocations.
pull/65/head
Paul J. Davis 11 years ago
parent
commit
79d24e9639
4 changed files with 102 additions and 22 deletions
  1. +79
    -18
      c_src/decoder.c
  2. +11
    -1
      c_src/jiffy.c
  3. +6
    -1
      c_src/jiffy.h
  4. +6
    -2
      src/jiffy.erl

+ 79
- 18
c_src/decoder.c View File

@ -61,21 +61,25 @@ typedef struct {
int st_top; int st_top;
} Decoder; } Decoder;
void
dec_init(Decoder* d, ErlNifEnv* env, ERL_NIF_TERM arg, ErlNifBinary* bin)
Decoder*
dec_new(ErlNifEnv* env)
{ {
jiffy_st* st = (jiffy_st*) enif_priv_data(env);
Decoder* d = enif_alloc_resource(st->res_dec, sizeof(Decoder));
int i; int i;
d->env = env;
d->atoms = enif_priv_data(env);
d->arg = arg;
if(d == NULL) {
return NULL;
}
d->atoms = st;
d->is_partial = 0; d->is_partial = 0;
d->p = (char*) bin->data;
d->u = bin->data;
d->len = bin->size;
d->i = 0;
d->p = NULL;
d->u = NULL;
d->len = -1;
d->i = -1;
d->st_data = (char*) enif_alloc(STACK_SIZE_INC * sizeof(char)); d->st_data = (char*) enif_alloc(STACK_SIZE_INC * sizeof(char));
d->st_size = STACK_SIZE_INC; d->st_size = STACK_SIZE_INC;
@ -87,11 +91,36 @@ dec_init(Decoder* d, ErlNifEnv* env, ERL_NIF_TERM arg, ErlNifBinary* bin)
d->st_data[0] = st_value; d->st_data[0] = st_value;
d->st_top++; d->st_top++;
return d;
} }
void void
dec_destroy(Decoder* d)
dec_init(Decoder* d, ErlNifEnv* env, ERL_NIF_TERM arg, ErlNifBinary* bin)
{ {
d->env = env;
d->arg = arg;
d->p = (char*) bin->data;
d->u = bin->data;
d->len = bin->size;
// I'd like to be more forceful on this check so that when
// we run a second iteration of the decoder we are sure
// that we're using the same binary. Unfortunately, I don't
// think there's a value to base this assertion on.
if(d->i < 0) {
d->i = 0;
} else {
assert(d->i <= d->len && "mismatched binary lengths");
}
}
void
dec_destroy(ErlNifEnv* env, void* obj)
{
Decoder* d = (Decoder*) obj;
if(d->st_data != NULL) { if(d->st_data != NULL) {
enif_free(d->st_data); enif_free(d->st_data);
} }
@ -605,25 +634,59 @@ make_array(ErlNifEnv* env, ERL_NIF_TERM list)
} }
ERL_NIF_TERM ERL_NIF_TERM
decode(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
decode_init(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{ {
Decoder dec;
Decoder* d = &dec;
Decoder* d;
jiffy_st* st = (jiffy_st*) enif_priv_data(env);
ERL_NIF_TERM tmp_argv[4];
if(argc != 1) {
return enif_make_badarg(env);
}
d = dec_new(env);
if(d == NULL) {
return make_error(st, env, "internal_error");
}
tmp_argv[0] = argv[0];
tmp_argv[1] = enif_make_resource(env, d);
tmp_argv[2] = enif_make_list(env, 0);
tmp_argv[3] = enif_make_list(env, 0);
enif_release_resource(d);
return decode_iter(env, 4, tmp_argv);
}
ERL_NIF_TERM
decode_iter(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
Decoder* d;
jiffy_st* st = (jiffy_st*) enif_priv_data(env);
ErlNifBinary bin; ErlNifBinary bin;
ERL_NIF_TERM objs = enif_make_list(env, 0);
ERL_NIF_TERM curr = enif_make_list(env, 0);
ERL_NIF_TERM objs;
ERL_NIF_TERM curr;
ERL_NIF_TERM val; ERL_NIF_TERM val;
ERL_NIF_TERM ret; ERL_NIF_TERM ret;
if(argc != 1) {
if(argc != 4) {
return enif_make_badarg(env); return enif_make_badarg(env);
} else if(!enif_inspect_binary(env, argv[0], &bin)) { } else if(!enif_inspect_binary(env, argv[0], &bin)) {
return enif_make_badarg(env); return enif_make_badarg(env);
} else if(!enif_get_resource(env, argv[1], st->res_dec, (void**) &d)) {
return enif_make_badarg(env);
} else if(!enif_is_list(env, argv[2])) {
return enif_make_badarg(env);
} else if(!enif_is_list(env, argv[3])) {
return enif_make_badarg(env);
} }
dec_init(d, env, argv[0], &bin); dec_init(d, env, argv[0], &bin);
objs = argv[2];
curr = argv[3];
//fprintf(stderr, "Parsing:\r\n"); //fprintf(stderr, "Parsing:\r\n");
while(d->i < bin.size) { while(d->i < bin.size) {
@ -908,7 +971,5 @@ decode(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
} }
done: done:
dec_destroy(d);
return ret; return ret;
} }

+ 11
- 1
c_src/jiffy.c View File

@ -28,6 +28,15 @@ load(ErlNifEnv* env, void** priv, ERL_NIF_TERM info)
st->ref_object = make_atom(env, "$object_ref$"); st->ref_object = make_atom(env, "$object_ref$");
st->ref_array = make_atom(env, "$array_ref$"); st->ref_array = make_atom(env, "$array_ref$");
st->res_dec = enif_open_resource_type(
env,
NULL,
"decoder",
dec_destroy,
ERL_NIF_RT_CREATE | ERL_NIF_RT_TAKEOVER,
NULL
);
*priv = (void*) st; *priv = (void*) st;
return 0; return 0;
@ -54,7 +63,8 @@ unload(ErlNifEnv* env, void* priv)
static ErlNifFunc funcs[] = static ErlNifFunc funcs[] =
{ {
{"nif_decode", 1, decode},
{"nif_decode_init", 1, decode_init},
{"nif_decode_iter", 4, decode_iter},
{"nif_encode", 2, encode} {"nif_encode", 2, encode}
}; };

+ 6
- 1
c_src/jiffy.h View File

@ -22,15 +22,20 @@ typedef struct {
ERL_NIF_TERM ref_object; ERL_NIF_TERM ref_object;
ERL_NIF_TERM ref_array; ERL_NIF_TERM ref_array;
ErlNifResourceType* res_dec;
} jiffy_st; } jiffy_st;
ERL_NIF_TERM make_atom(ErlNifEnv* env, const char* name); ERL_NIF_TERM make_atom(ErlNifEnv* env, const char* name);
ERL_NIF_TERM make_ok(jiffy_st* st, ErlNifEnv* env, ERL_NIF_TERM data); ERL_NIF_TERM make_ok(jiffy_st* st, ErlNifEnv* env, ERL_NIF_TERM data);
ERL_NIF_TERM make_error(jiffy_st* st, ErlNifEnv* env, const char* error); ERL_NIF_TERM make_error(jiffy_st* st, ErlNifEnv* env, const char* error);
ERL_NIF_TERM decode(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
ERL_NIF_TERM decode_init(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
ERL_NIF_TERM decode_iter(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
ERL_NIF_TERM encode(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); ERL_NIF_TERM encode(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
void dec_destroy(ErlNifEnv* env, void* obj);
int int_from_hex(const unsigned char* p); int int_from_hex(const unsigned char* p);
int int_to_hex(int val, char* p); int int_to_hex(int val, char* p);
int utf8_len(int c); int utf8_len(int c);

+ 6
- 2
src/jiffy.erl View File

@ -8,7 +8,7 @@
-on_load(init/0). -on_load(init/0).
decode(Data) when is_binary(Data) -> decode(Data) when is_binary(Data) ->
case nif_decode(Data) of
case nif_decode_init(Data) of
{error, _} = Error -> {error, _} = Error ->
throw(Error); throw(Error);
{partial, EJson} -> {partial, EJson} ->
@ -99,7 +99,11 @@ init() ->
not_loaded(Line) -> not_loaded(Line) ->
erlang:nif_error({not_loaded, [{module, ?MODULE}, {line, Line}]}). erlang:nif_error({not_loaded, [{module, ?MODULE}, {line, Line}]}).
nif_decode(_Data) ->
nif_decode_init(_Data) ->
?NOT_LOADED,
nif_decode_iter(w, x, y, z).
nif_decode_iter(_Data, _Decoder, _, _) ->
?NOT_LOADED. ?NOT_LOADED.
nif_encode(_Data, _Options) -> nif_encode(_Data, _Options) ->

Loading…
Cancel
Save