Parcourir la source

Use an array for the position stack rather than an Erlang list

pull/184/head
John Högberg il y a 6 ans
committed by Paul J. Davis
Parent
révision
4ab9a68313
5 fichiers modifiés avec 174 ajouts et 35 suppressions
  1. +39
    -35
      c_src/encoder.c
  2. +87
    -0
      c_src/termstack.c
  3. +28
    -0
      c_src/termstack.h
  4. +10
    -0
      test/jiffy_05_array_tests.erl
  5. +10
    -0
      test/jiffy_06_object_tests.erl

+ 39
- 35
c_src/encoder.c Voir le fichier

@ -5,8 +5,8 @@
#include <stdio.h>
#include <string.h>
#include "erl_nif.h"
#include "jiffy.h"
#include "termstack.h"
#define BIN_INC_SIZE 2048
@ -588,7 +588,7 @@ encode_init(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
}
tmp_argv[0] = enif_make_resource(env, e);
tmp_argv[1] = enif_make_list(env, 1, argv[0]);
tmp_argv[1] = enif_make_tuple1(env, argv[0]);
tmp_argv[2] = enif_make_list(env, 0);
enif_release_resource(e);
@ -624,14 +624,15 @@ encode_init(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
ERL_NIF_TERM
encode_iter(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
Encoder* e;
jiffy_st* st = (jiffy_st*) enif_priv_data(env);
Encoder* e;
TermStack stack;
ERL_NIF_TERM ret = 0;
ERL_NIF_TERM stack;
ERL_NIF_TERM curr;
ERL_NIF_TERM item;
ERL_NIF_TERM saved_stack;
const ERL_NIF_TERM* tuple;
int arity;
ErlNifSInt64 lval;
@ -644,8 +645,6 @@ encode_iter(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
return enif_make_badarg(env);
} else if(!enif_get_resource(env, argv[0], st->res_enc, (void**) &e)) {
return enif_make_badarg(env);
} else if(!enif_is_list(env, argv[1])) {
return enif_make_badarg(env);
} else if(!enif_is_list(env, argv[2])) {
return enif_make_badarg(env);
}
@ -654,34 +653,35 @@ encode_iter(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
return enif_make_badarg(env);
}
stack = argv[1];
if(!termstack_restore(env, argv[1], &stack)) {
return enif_make_badarg(env);
}
e->iolist = argv[2];
start = e->iosize + e->i;
while(!enif_is_empty_list(env, stack)) {
while(!termstack_is_empty(&stack)) {
bytes_written += (e->iosize + e->i) - start;
if(should_yield(env, &bytes_written, e->bytes_per_red)) {
saved_stack = termstack_save(env, &stack);
termstack_destroy(&stack);
return enif_make_tuple4(
env,
st->atom_iter,
argv[0],
stack,
saved_stack,
e->iolist
);
}
if(!enif_get_list_cell(env, stack, &curr, &stack)) {
ret = enc_error(e, "internal_error");
goto done;
}
curr = termstack_pop(&stack);
if(enif_is_identical(curr, e->atoms->ref_object)) {
if(!enif_get_list_cell(env, stack, &curr, &stack)) {
ret = enc_error(e, "internal_error");
goto done;
}
curr = termstack_pop(&stack);
if(enif_is_empty_list(env, curr)) {
if(!enc_end_object(e)) {
ret = enc_error(e, "internal_error");
@ -713,14 +713,13 @@ encode_iter(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
ret = enc_error(e, "internal_error");
goto done;
}
stack = enif_make_list_cell(env, curr, stack);
stack = enif_make_list_cell(env, e->atoms->ref_object, stack);
stack = enif_make_list_cell(env, tuple[1], stack);
termstack_push(&stack, curr);
termstack_push(&stack, e->atoms->ref_object);
termstack_push(&stack, tuple[1]);
} else if(enif_is_identical(curr, e->atoms->ref_array)) {
if(!enif_get_list_cell(env, stack, &curr, &stack)) {
ret = enc_error(e, "internal_error");
goto done;
}
curr = termstack_pop(&stack);
if(enif_is_empty_list(env, curr)) {
if(!enc_end_array(e)) {
ret = enc_error(e, "internal_error");
@ -736,9 +735,10 @@ encode_iter(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
ret = enc_error(e, "internal_error");
goto done;
}
stack = enif_make_list_cell(env, curr, stack);
stack = enif_make_list_cell(env, e->atoms->ref_array, stack);
stack = enif_make_list_cell(env, item, stack);
termstack_push(&stack, curr);
termstack_push(&stack, e->atoms->ref_array);
termstack_push(&stack, item);
} else if(enif_compare(curr, e->atoms->atom_null) == 0) {
if(!enc_literal(e, "null", 4)) {
ret = enc_error(e, "null");
@ -819,16 +819,18 @@ encode_iter(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
ret = enc_error(e, "internal_error");
goto done;
}
stack = enif_make_list_cell(env, curr, stack);
stack = enif_make_list_cell(env, e->atoms->ref_object, stack);
stack = enif_make_list_cell(env, tuple[1], stack);
termstack_push(&stack, curr);
termstack_push(&stack, e->atoms->ref_object);
termstack_push(&stack, tuple[1]);
#if MAP_TYPE_PRESENT
} else if(enif_is_map(env, curr)) {
if(!enc_map_to_ejson(env, curr, &curr)) {
ret = enc_error(e, "internal_error");
goto done;
}
stack = enif_make_list_cell(env, curr, stack);
termstack_push(&stack, curr);
#endif
} else if(enif_is_list(env, curr)) {
if(!enc_start_array(e)) {
@ -846,9 +848,10 @@ encode_iter(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
ret = enc_error(e, "internal_error");
goto done;
}
stack = enif_make_list_cell(env, curr, stack);
stack = enif_make_list_cell(env, e->atoms->ref_array, stack);
stack = enif_make_list_cell(env, item, stack);
termstack_push(&stack, curr);
termstack_push(&stack, e->atoms->ref_array);
termstack_push(&stack, item);
} else {
if(!enc_unknown(e, curr)) {
ret = enc_error(e, "internal_error");
@ -869,6 +872,7 @@ encode_iter(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
}
done:
termstack_destroy(&stack);
return ret;
}

+ 87
- 0
c_src/termstack.c Voir le fichier

@ -0,0 +1,87 @@
// This file is part of Jiffy released under the MIT license.
// See the LICENSE file for more information.
#include <assert.h>
#include <stdio.h>
#include <string.h>
#include "jiffy.h"
#include "termstack.h"
ERL_NIF_TERM
termstack_save(ErlNifEnv* env, TermStack* stack)
{
return enif_make_tuple_from_array(env, stack->elements, stack->top);
}
int
termstack_restore(ErlNifEnv* env, ERL_NIF_TERM from, TermStack* stack)
{
const ERL_NIF_TERM* elements;
int arity;
if(enif_get_tuple(env, from, &arity, &elements)) {
stack->top = arity;
if(arity <= SMALL_TERMSTACK_SIZE) {
stack->elements = &stack->__default_elements[0];
stack->size = SMALL_TERMSTACK_SIZE;
} else {
stack->size = arity * 2;
stack->elements = enif_alloc(stack->size * sizeof(ERL_NIF_TERM));
if(!stack->elements) {
return 0;
}
}
memcpy(stack->elements, elements, arity * sizeof(ERL_NIF_TERM));
return 1;
}
return 0;
}
void
termstack_destroy(TermStack* stack)
{
if(stack->elements != &stack->__default_elements[0]) {
enif_free(stack->elements);
}
}
inline void
termstack_push(TermStack* stack, ERL_NIF_TERM term)
{
if(stack->top == stack->size) {
size_t new_size = stack->size * 2;
size_t num_bytes = new_size * sizeof(ERL_NIF_TERM);
if (stack->elements == &stack->__default_elements[0]) {
ERL_NIF_TERM* elems = enif_alloc(num_bytes);
memcpy(elems, stack->elements, num_bytes);
stack->elements = elems;
} else {
stack->elements = enif_realloc(stack->elements, num_bytes);
}
stack->size = new_size;
}
assert(stack->top < stack->size);
stack->elements[stack->top++] = term;
}
inline ERL_NIF_TERM
termstack_pop(TermStack* stack)
{
assert(stack->top > 0 && stack->top <= stack->size);
return stack->elements[--stack->top];
}
inline int
termstack_is_empty(TermStack* stack)
{
return stack->top == 0;
}

+ 28
- 0
c_src/termstack.h Voir le fichier

@ -0,0 +1,28 @@
// This file is part of Jiffy released under the MIT license.
// See the LICENSE file for more information.
#ifndef TERMSTACK_H
#define TERMSTACK_H
#include "erl_nif.h"
#define SMALL_TERMSTACK_SIZE 16
typedef struct {
ERL_NIF_TERM* elements;
size_t size;
size_t top;
ERL_NIF_TERM __default_elements[SMALL_TERMSTACK_SIZE];
} TermStack;
ERL_NIF_TERM termstack_save(ErlNifEnv* env, TermStack* stack);
int termstack_restore(ErlNifEnv* env, ERL_NIF_TERM from, TermStack* stack);
void termstack_destroy(TermStack* stack);
void termstack_push(TermStack* stack, ERL_NIF_TERM term);
ERL_NIF_TERM termstack_pop(TermStack* stack);
int termstack_is_empty(TermStack* stack);
#endif

+ 10
- 0
test/jiffy_05_array_tests.erl Voir le fichier

@ -16,6 +16,16 @@ array_failure_test_() ->
[gen(error, Case) || Case <- cases(error)].
nested_array_test_() ->
Obj = nested(256),
Enc = enc(Obj),
?_assertEqual(Obj, dec(Enc)).
nested(0) -> <<"bottom">>;
nested(N) -> [nested(N - 1)].
gen(ok, {J, E}) ->
gen(ok, {J, E, J});
gen(ok, {J1, E, J2}) ->

+ 10
- 0
test/jiffy_06_object_tests.erl Voir le fichier

@ -16,6 +16,16 @@ object_failure_test_() ->
[gen(error, Case) || Case <- cases(error)].
nested_object_test_() ->
Obj = nested(256),
Enc = enc(Obj),
?_assertEqual(Obj, dec(Enc)).
nested(0) -> <<"bottom">>;
nested(N) -> {[{integer_to_binary(N), nested(N - 1)}]}.
gen(ok, {J, E}) ->
gen(ok, {J, E, J});
gen(ok, {J1, E, J2}) ->

Chargement…
Annuler
Enregistrer