コミットを比較

...

17 コミット

作成者 SHA1 メッセージ 日付
  John Högberg a1fb83fe04 Remove -fno-strict-aliasing 6年前
  John Högberg ef0da5723e Get rid of separate unsigned/signed buffers 6年前
  John Högberg d5e848c5c1 Never expand the encode buffer; emit and restart 6年前
  John Högberg 031d7526f0 Fix erroneous state check in the decoder 6年前
  John Högberg 11b0c9da0b Enable link-time optimization on *nix platforms 6年前
  John Högberg 509fee7ff4 Move all atom checks under enif_is_atom 6年前
  John Högberg 7edbb36db4 Use the result map for key dedupe 6年前
  John Högberg 03f6af3af5 Refactor trapping and trap more often during decode 6年前
  John Högberg 35cf937328 Skip erroneous UTF-8 validation for atoms 6年前
  John Högberg 8265831643 Use enif_is_identical for equality checks 6年前
  John Högberg 081969ed48 Replace sprintf with a dedicated integer print routine 6年前
  John Högberg 4cbe781b8e Skip redundant enif_is_empty_list checks during encode 6年前
  John Högberg 6e7e1c7ae1 Use realloc instead of doing it manually 6年前
  John Högberg f02c656f6a Walk through strings once when encoding 6年前
  John Högberg 90a11a2c51 Use an array for the position stack rather than an Erlang list 6年前
  John Högberg 009618ae39 sizeof(char) == 1 by definition 6年前
  Paul J. Davis fb005f9810 0.15.2 7年前
19個のファイルの変更746行の追加489行の削除
分割表示
  1. +100
    -81
      c_src/decoder.c
  2. +2
    -2
      c_src/doubles.cc
  3. +424
    -344
      c_src/encoder.c
  4. +11
    -4
      c_src/jiffy.h
  5. +3
    -8
      c_src/objects.cc
  6. +87
    -0
      c_src/termstack.c
  7. +28
    -0
      c_src/termstack.h
  8. +13
    -13
      c_src/utf8.c
  9. +21
    -10
      c_src/util.c
  10. +3
    -3
      rebar.config
  11. +1
    -1
      src/jiffy.app.src
  12. +8
    -8
      src/jiffy.erl
  13. +10
    -9
      test/jiffy_02_literal_tests.erl
  14. +1
    -0
      test/jiffy_03_number_tests.erl
  15. +11
    -5
      test/jiffy_04_string_tests.erl
  16. +10
    -0
      test/jiffy_05_array_tests.erl
  17. +10
    -0
      test/jiffy_06_object_tests.erl
  18. +1
    -1
      test/jiffy_10_short_double_tests.erl
  19. +2
    -0
      test/jiffy_util.hrl

+ 100
- 81
c_src/decoder.c ファイルの表示

@ -57,8 +57,7 @@ typedef struct {
int copy_strings;
ERL_NIF_TERM null_term;
char* p;
unsigned char* u;
unsigned char* p;
int i;
int len;
@ -89,11 +88,10 @@ dec_new(ErlNifEnv* env)
d->null_term = d->atoms->atom_null;
d->p = NULL;
d->u = NULL;
d->len = -1;
d->i = -1;
d->i = 0;
d->st_data = (char*) enif_alloc(STACK_SIZE_INC * sizeof(char));
d->st_data = (char*) enif_alloc(STACK_SIZE_INC);
d->st_size = STACK_SIZE_INC;
d->st_top = 0;
@ -113,19 +111,8 @@ 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->p = 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
@ -150,7 +137,8 @@ dec_error(Decoder* d, const char* atom)
char
dec_curr(Decoder* d)
{
return d->st_data[d->st_top-1];
assert(d->st_top > 0);
return d->st_data[d->st_top - 1];
}
int
@ -162,31 +150,41 @@ dec_top(Decoder* d)
void
dec_push(Decoder* d, char val)
{
char* tmp;
int new_sz;
int i;
if(d->st_top >= d->st_size) {
if(d->st_top == d->st_size) {
new_sz = d->st_size + STACK_SIZE_INC;
tmp = (char*) enif_alloc(new_sz * sizeof(char));
memcpy(tmp, d->st_data, d->st_size * sizeof(char));
enif_free(d->st_data);
d->st_data = tmp;
d->st_data = (char*) enif_realloc(d->st_data, new_sz);
d->st_size = new_sz;
for(i = d->st_top; i < d->st_size; i++) {
d->st_data[i] = st_invalid;
}
}
assert(d->st_top < d->st_size);
d->st_data[d->st_top++] = val;
}
char
dec_pop(Decoder* d) {
char current = st_invalid;
if (d->st_top > 0) {
current = d->st_data[d->st_top - 1];
d->st_data[d->st_top - 1] = st_invalid;
d->st_top--;
}
return current;
}
void
dec_pop(Decoder* d, char val)
dec_pop_assert(Decoder* d, char val)
{
assert(d->st_data[d->st_top-1] == val && "popped invalid state.");
d->st_data[d->st_top-1] = st_invalid;
d->st_top--;
char current = dec_pop(d);
assert(current == val && "popped invalid state.");
(void)current;
}
int
@ -210,7 +208,7 @@ dec_string(Decoder* d, ERL_NIF_TERM* value)
st = d->i;
while(d->i < d->len) {
if(d->u[d->i] < 0x20) {
if(d->p[d->i] < 0x20) {
return 0;
} else if(d->p[d->i] == '\"') {
d->i++;
@ -240,7 +238,7 @@ dec_string(Decoder* d, ERL_NIF_TERM* value)
if(d->i + 4 >= d->len) {
return 0;
}
hi = int_from_hex(&(d->u[d->i]));
hi = int_from_hex(&(d->p[d->i]));
if(hi < 0) {
return 0;
}
@ -254,7 +252,7 @@ dec_string(Decoder* d, ERL_NIF_TERM* value)
} else if(d->p[d->i++] != 'u') {
return 0;
}
lo = int_from_hex(&(d->u[d->i]));
lo = int_from_hex(&(d->p[d->i]));
if(lo < 0) {
return 0;
}
@ -276,10 +274,10 @@ dec_string(Decoder* d, ERL_NIF_TERM* value)
default:
return 0;
}
} else if(d->u[d->i] < 0x80) {
} else if(d->p[d->i] < 0x80) {
d->i++;
} else {
ulen = utf8_validate(&(d->u[d->i]), d->len - d->i);
ulen = utf8_validate(&(d->p[d->i]), d->len - d->i);
if(ulen < 0) {
return 0;
}
@ -345,12 +343,12 @@ parse:
break;
case 'u':
ui++;
hi = int_from_hex(&(d->u[ui]));
hi = int_from_hex(&(d->p[ui]));
if(hi < 0) {
return 0;
}
if(hi >= 0xD800 && hi < 0xDC00) {
lo = int_from_hex(&(d->u[ui+6]));
lo = int_from_hex(&(d->p[ui+6]));
if(lo < 0) {
return 0;
}
@ -681,19 +679,19 @@ decode_init(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
continue;
} else if(get_bytes_per_red(env, val, &(d->bytes_per_red))) {
continue;
} else if(enif_compare(val, d->atoms->atom_return_maps) == 0) {
} else if(enif_is_identical(val, d->atoms->atom_return_maps)) {
#if MAP_TYPE_PRESENT
d->return_maps = 1;
#else
return enif_make_badarg(env);
#endif
} else if(enif_compare(val, d->atoms->atom_return_trailer) == 0) {
} else if(enif_is_identical(val, d->atoms->atom_return_trailer)) {
d->return_trailer = 1;
} else if(enif_compare(val, d->atoms->atom_dedupe_keys) == 0) {
} else if(enif_is_identical(val, d->atoms->atom_dedupe_keys)) {
d->dedupe_keys = 1;
} else if(enif_compare(val, d->atoms->atom_copy_strings) == 0) {
} else if(enif_is_identical(val, d->atoms->atom_copy_strings)) {
d->copy_strings = 1;
} else if(enif_compare(val, d->atoms->atom_use_nil) == 0) {
} else if(enif_is_identical(val, d->atoms->atom_use_nil)) {
d->null_term = d->atoms->atom_nil;
} else if(get_null_term(env, val, &(d->null_term))) {
continue;
@ -718,38 +716,60 @@ decode_iter(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
ERL_NIF_TERM val = argv[2];
ERL_NIF_TERM trailer;
ERL_NIF_TERM ret;
size_t bytes_read = 0;
ERL_NIF_TERM tmp_argv[5];
if(argc != 5) {
return enif_make_badarg(env);
} else if(!enif_inspect_binary(env, argv[0], &bin)) {
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[3])) {
void* res;
size_t start;
size_t bytes_processed = 0;
if(!enif_inspect_binary(env, argv[0], &bin)) {
return enif_make_badarg(env);
} else if(!enif_is_list(env, argv[4])) {
} else if(!enif_get_resource(env, argv[1], st->res_dec, &res)) {
return enif_make_badarg(env);
}
d = (Decoder*) res;
dec_init(d, env, argv[0], &bin);
objs = argv[3];
curr = argv[4];
start = d->i;
while(d->i < bin.size) {
if(should_yield(env, &bytes_read, d->bytes_per_red)) {
return enif_make_tuple5(
bytes_processed = d->i - start;
if(should_yield(bytes_processed, d->bytes_per_red)) {
assert(enif_is_list(env, objs));
assert(enif_is_list(env, curr));
tmp_argv[0] = argv[0];
tmp_argv[1] = argv[1];
tmp_argv[2] = val;
tmp_argv[3] = objs;
tmp_argv[4] = curr;
bump_used_reds(env, bytes_processed, d->bytes_per_red);
#if SCHEDULE_NIF_PRESENT
return enif_schedule_nif(
env,
"nif_decode_iter",
0,
decode_iter,
5,
tmp_argv
);
#else
return enif_make_tuple2(
env,
st->atom_iter,
argv[1],
val,
objs,
curr
enif_make_tuple(env, 5, tmp_argv)
);
#endif
}
bytes_read += 1;
switch(dec_curr(d)) {
case st_value:
switch(d->p[d->i]) {
@ -769,7 +789,7 @@ decode_iter(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
goto done;
}
val = d->null_term;
dec_pop(d, st_value);
dec_pop_assert(d, st_value);
d->i += 4;
break;
case 't':
@ -782,7 +802,7 @@ decode_iter(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
goto done;
}
val = d->atoms->atom_true;
dec_pop(d, st_value);
dec_pop_assert(d, st_value);
d->i += 4;
break;
case 'f':
@ -795,7 +815,7 @@ decode_iter(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
goto done;
}
val = d->atoms->atom_false;
dec_pop(d, st_value);
dec_pop_assert(d, st_value);
d->i += 5;
break;
case '\"':
@ -803,7 +823,7 @@ decode_iter(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
ret = dec_error(d, "invalid_string");
goto done;
}
dec_pop(d, st_value);
dec_pop_assert(d, st_value);
break;
case '-':
case '0':
@ -820,7 +840,7 @@ decode_iter(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
ret = dec_error(d, "invalid_number");
goto done;
}
dec_pop(d, st_value);
dec_pop_assert(d, st_value);
break;
case '{':
dec_push(d, st_object);
@ -841,13 +861,12 @@ decode_iter(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
ret = dec_error(d, "invalid_json");
goto done;
}
dec_pop(d, st_value);
if(dec_curr(d) != st_array) {
dec_pop_assert(d, st_value);
if(dec_pop(d) != st_array) {
ret = dec_error(d, "invalid_json");
goto done;
}
dec_pop(d, st_array);
dec_pop(d, st_value);
dec_pop_assert(d, st_value);
val = curr; // curr is []
if(!enif_get_list_cell(env, objs, &curr, &objs)) {
ret = dec_error(d, "internal_error");
@ -880,7 +899,7 @@ decode_iter(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
ret = dec_error(d, "invalid_string");
goto done;
}
dec_pop(d, st_key);
dec_pop_assert(d, st_key);
dec_push(d, st_colon);
curr = enif_make_list_cell(env, val, curr);
break;
@ -889,9 +908,9 @@ decode_iter(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
ret = dec_error(d, "invalid_json");
goto done;
}
dec_pop(d, st_key);
dec_pop(d, st_object);
dec_pop(d, st_value);
dec_pop_assert(d, st_key);
dec_pop_assert(d, st_object);
dec_pop_assert(d, st_value);
val = make_empty_object(env, d->return_maps);
if(!enif_get_list_cell(env, objs, &curr, &objs)) {
ret = dec_error(d, "internal_error");
@ -920,7 +939,7 @@ decode_iter(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
d->i++;
break;
case ':':
dec_pop(d, st_colon);
dec_pop_assert(d, st_colon);
dec_push(d, st_value);
d->i++;
break;
@ -939,7 +958,7 @@ decode_iter(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
d->i++;
break;
case ',':
dec_pop(d, st_comma);
dec_pop_assert(d, st_comma);
switch(dec_curr(d)) {
case st_object:
dec_push(d, st_key);
@ -954,13 +973,12 @@ decode_iter(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
d->i++;
break;
case '}':
dec_pop(d, st_comma);
if(dec_curr(d) != st_object) {
dec_pop_assert(d, st_comma);
if(dec_pop(d) != st_object) {
ret = dec_error(d, "invalid_json");
goto done;
}
dec_pop(d, st_object);
dec_pop(d, st_value);
dec_pop_assert(d, st_value);
if(!make_object(env, curr, &val,
d->return_maps, d->dedupe_keys)) {
ret = dec_error(d, "internal_object_error");
@ -979,13 +997,12 @@ decode_iter(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
d->i++;
break;
case ']':
dec_pop(d, st_comma);
if(dec_curr(d) != st_array) {
dec_pop_assert(d, st_comma);
if(dec_pop(d) != st_array) {
ret = dec_error(d, "invalid_json");
goto done;
}
dec_pop(d, st_array);
dec_pop(d, st_value);
dec_pop_assert(d, st_value);
val = make_array(env, curr);
if(!enif_get_list_cell(env, objs, &curr, &objs)) {
ret = dec_error(d, "internal_error");
@ -1034,7 +1051,7 @@ decode_done:
goto done;
}
if(dec_curr(d) != st_done) {
if(dec_pop(d) != st_done) {
ret = dec_error(d, "truncated_json");
} else if(d->is_partial) {
ret = enif_make_tuple2(env, d->atoms->atom_partial, val);
@ -1043,5 +1060,7 @@ decode_done:
}
done:
bump_used_reds(env, bytes_processed, d->bytes_per_red);
return ret;
}

+ 2
- 2
c_src/doubles.cc ファイルの表示

@ -10,14 +10,14 @@ namespace dc = double_conversion;
BEGIN_C
int
double_to_shortest(char* buf, size_t size, size_t* len, double val)
double_to_shortest(unsigned char* buf, size_t size, size_t* len, double val)
{
int flags = dc::DoubleToStringConverter::UNIQUE_ZERO |
dc::DoubleToStringConverter::EMIT_POSITIVE_EXPONENT_SIGN |
dc::DoubleToStringConverter::EMIT_TRAILING_DECIMAL_POINT |
dc::DoubleToStringConverter::EMIT_TRAILING_ZERO_AFTER_POINT;
dc::StringBuilder builder(buf, size);
dc::StringBuilder builder(reinterpret_cast<char*>(buf), size);
dc::DoubleToStringConverter conv(flags, NULL, NULL, 'e', -6, 21, 6, 0);
if(!conv.ToShortest(val, &builder)) {

+ 424
- 344
c_src/encoder.c
ファイル差分が大きすぎるため省略します
ファイルの表示


+ 11
- 4
c_src/jiffy.h ファイルの表示

@ -13,6 +13,12 @@
((ERL_NIF_MAJOR_VERSION == 2 && ERL_NIF_MINOR_VERSION >= 6) \
|| (ERL_NIF_MAJOR_VERSION > 2))
#define CONSUME_TIMESLICE_PRESENT \
((ERL_NIF_MAJOR_VERSION >= 2 && ERL_NIF_MINOR_VERSION >= 4))
#define SCHEDULE_NIF_PRESENT \
((ERL_NIF_MAJOR_VERSION >= 2 && ERL_NIF_MINOR_VERSION >= 7))
typedef struct {
ERL_NIF_TERM atom_ok;
ERL_NIF_TERM atom_error;
@ -53,7 +59,8 @@ ERL_NIF_TERM make_obj_error(jiffy_st* st, ErlNifEnv* env, const char* error,
int get_bytes_per_iter(ErlNifEnv* env, ERL_NIF_TERM val, size_t* bpi);
int get_bytes_per_red(ErlNifEnv* env, ERL_NIF_TERM val, size_t* bpr);
int get_null_term(ErlNifEnv* env, ERL_NIF_TERM val, ERL_NIF_TERM *null_term);
int should_yield(ErlNifEnv* env, size_t* used, size_t bytes_per_red);
int should_yield(size_t used, size_t bytes_per_red);
void bump_used_reds(ErlNifEnv* env, size_t used, size_t bytes_per_red);
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[]);
@ -67,14 +74,14 @@ int make_object(ErlNifEnv* env, ERL_NIF_TERM pairs, ERL_NIF_TERM* out,
int ret_map, int dedupe_keys);
int int_from_hex(const unsigned char* p);
int int_to_hex(int val, char* p);
int int_to_hex(int val, unsigned char* p);
int utf8_len(int c);
int utf8_esc_len(int c);
int utf8_validate(unsigned char* data, size_t size);
int utf8_to_unicode(unsigned char* buf, size_t size);
int unicode_to_utf8(int c, unsigned char* buf);
int unicode_from_pair(int hi, int lo);
int unicode_uescape(int c, char* buf);
int double_to_shortest(char *buf, size_t size, size_t* len, double val);
int unicode_uescape(int c, unsigned char* buf);
int double_to_shortest(unsigned char *buf, size_t size, size_t* len, double val);
#endif // Included JIFFY_H

+ 3
- 8
c_src/objects.cc ファイルの表示

@ -19,11 +19,12 @@ BEGIN_C
int
make_object(ErlNifEnv* env, ERL_NIF_TERM pairs, ERL_NIF_TERM* out,
int ret_map, int dedupe_keys)
int ret_map, int dedupe_keys)
{
ERL_NIF_TERM ret;
ERL_NIF_TERM key;
ERL_NIF_TERM val;
ERL_NIF_TERM old_val;
std::set<std::string> seen;
@ -34,13 +35,7 @@ make_object(ErlNifEnv* env, ERL_NIF_TERM pairs, ERL_NIF_TERM* out,
if(!enif_get_list_cell(env, pairs, &key, &pairs)) {
assert(0 == 1 && "Unbalanced object pairs.");
}
ErlNifBinary bin;
if(!enif_inspect_binary(env, key, &bin)) {
return 0;
}
std::string skey((char*) bin.data, bin.size);
if(seen.count(skey) == 0) {
seen.insert(skey);
if(!enif_get_map_value(env, ret, key, &old_val)) {
if(!enif_make_map_put(env, ret, key, val, &ret)) {
return 0;
}

+ 87
- 0
c_src/termstack.c ファイルの表示

@ -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 ファイルの表示

@ -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

+ 13
- 13
c_src/utf8.c ファイルの表示

@ -49,7 +49,7 @@ int_from_hex(const unsigned char* p)
}
int
int_to_hex(int val, char* p)
int_to_hex(int val, unsigned char* p)
{
if(val < 0 || val > 65535)
return -1;
@ -163,7 +163,7 @@ utf8_to_unicode(unsigned char* buf, size_t size)
int ret;
if((buf[0] & 0x80) == 0x00) {
// 0xxxxxxx
ret = (int) buf[0];
ret = buf[0];
} else if((buf[0] & 0xE0) == 0xC0 && size >= 2) {
// 110xxxxy 10yyyyyy
ret = ((buf[0] & 0x1F) << 6)
@ -192,26 +192,26 @@ int
unicode_to_utf8(int c, unsigned char* buf)
{
if(c < 0x80) {
buf[0] = (unsigned char) c;
buf[0] = c;
return 1;
} else if(c < 0x800) {
buf[0] = (unsigned char) 0xC0 + (c >> 6);
buf[1] = (unsigned char) 0x80 + (c & 0x3F);
buf[0] = 0xC0 + (c >> 6);
buf[1] = 0x80 + (c & 0x3F);
return 2;
} else if(c < 0x10000) {
if(c < 0xD800 || (c > 0xDFFF)) {
buf[0] = (unsigned char) 0xE0 + (c >> 12);
buf[1] = (unsigned char) 0x80 + ((c >> 6) & 0x3F);
buf[2] = (unsigned char) 0x80 + (c & 0x3F);
buf[0] = 0xE0 + (c >> 12);
buf[1] = 0x80 + ((c >> 6) & 0x3F);
buf[2] = 0x80 + (c & 0x3F);
return 3;
} else {
return -1;
}
} else if(c <= 0x10FFFF) {
buf[0] = (unsigned char) 0xF0 + (c >> 18);
buf[1] = (unsigned char) 0x80 + ((c >> 12) & 0x3F);
buf[2] = (unsigned char) 0x80 + ((c >> 6) & 0x3F);
buf[3] = (unsigned char) 0x80 + (c & 0x3F);
buf[0] = 0xF0 + (c >> 18);
buf[1] = 0x80 + ((c >> 12) & 0x3F);
buf[2] = 0x80 + ((c >> 6) & 0x3F);
buf[3] = 0x80 + (c & 0x3F);
return 4;
}
return -1;
@ -226,7 +226,7 @@ unicode_from_pair(int hi, int lo)
}
int
unicode_uescape(int val, char* p)
unicode_uescape(int val, unsigned char* p)
{
int n;
if(val < 0x10000) {

+ 21
- 10
c_src/util.c ファイルの表示

@ -122,20 +122,31 @@ get_null_term(ErlNifEnv* env, ERL_NIF_TERM val, ERL_NIF_TERM *null_term)
}
int
should_yield(ErlNifEnv* env, size_t* used, size_t bytes_per_red)
should_yield(size_t used, size_t bytes_per_red)
{
#if(ERL_NIF_MAJOR_VERSION >= 2 && ERL_NIF_MINOR_VERSION >= 4)
if(((*used) / bytes_per_red) >= 20) {
*used = 0;
return enif_consume_timeslice(env, 1);
}
return (used / bytes_per_red) >= DEFAULT_ERLANG_REDUCTION_COUNT;
}
return 0;
void
bump_used_reds(ErlNifEnv* env, size_t used, size_t bytes_per_red)
{
#if CONSUME_TIMESLICE_PRESENT
size_t reds_used;
size_t pct_used;
#else
reds_used = used / bytes_per_red;
pct_used = 100 * reds_used / DEFAULT_ERLANG_REDUCTION_COUNT;
return ((*used) / bytes_per_red) >= DEFAULT_ERLANG_REDUCTION_COUNT;
if(pct_used > 0) {
if(pct_used > 100) {
pct_used = 100;
}
enif_consume_timeslice(env, pct_used);
}
#endif
(void) env;
(void) used;
(void) bytes_per_red;
}

+ 3
- 3
rebar.config ファイルの表示

@ -8,12 +8,12 @@
{port_env, [
{"(linux|solaris|freebsd|netbsd|openbsd|dragonfly|darwin|gnu)",
"CFLAGS", "$CFLAGS -Ic_src/ -g -Wall -Werror -O3 -fno-strict-aliasing"},
"CFLAGS", "$CFLAGS -Ic_src/ -g -Wall -flto -Werror -O3"},
{"(linux|solaris|freebsd|netbsd|openbsd|dragonfly|darwin|gnu)",
"CXXFLAGS", "$CXXFLAGS -Ic_src/ -g -Wall -Werror -O3"},
"CXXFLAGS", "$CXXFLAGS -Ic_src/ -g -Wall -flto -Werror -O3"},
{"(linux|solaris|freebsd|netbsd|openbsd|dragonfly|darwin|gnu)",
"LDFLAGS", "$LDFLAGS -lstdc++"},
"LDFLAGS", "$LDFLAGS -flto -lstdc++"},
%% OS X Leopard flags for 64-bit
{"darwin9.*-64$", "CXXFLAGS", "-m64"},

+ 1
- 1
src/jiffy.app.src ファイルの表示

@ -1,6 +1,6 @@
{application, jiffy, [
{description, "JSON Decoder/Encoder."},
{vsn, "0.15.1"},
{vsn, "0.15.2"},
{registered, []},
{applications, [kernel, stdlib, xmerl]},
{maintainers, ["Paul J. Davis"]},

+ 8
- 8
src/jiffy.erl ファイルの表示

@ -71,7 +71,7 @@ decode(Data, Opts) when is_binary(Data), is_list(Opts) ->
throw(Error);
{partial, EJson} ->
finish_decode(EJson);
{iter, Decoder, Val, Objs, Curr} ->
{iter, {_, Decoder, Val, Objs, Curr}} ->
decode_loop(Data, Decoder, Val, Objs, Curr);
EJson ->
EJson
@ -99,10 +99,10 @@ encode(Data, Options) ->
throw(Error);
{partial, IOData} ->
finish_encode(IOData, []);
{iter, Encoder, Stack, IOBuf} ->
{iter, {Encoder, Stack, IOBuf}} ->
encode_loop(Data, Options, Encoder, Stack, IOBuf);
IOData ->
IOData
RevIOData when is_list(RevIOData) ->
lists:reverse(RevIOData)
end.
@ -184,7 +184,7 @@ decode_loop(Data, Decoder, Val, Objs, Curr) ->
throw(Error);
{partial, EJson} ->
finish_decode(EJson);
{iter, NewDecoder, NewVal, NewObjs, NewCurr} ->
{iter, {_, NewDecoder, NewVal, NewObjs, NewCurr}} ->
decode_loop(Data, NewDecoder, NewVal, NewObjs, NewCurr);
EJson ->
EJson
@ -204,10 +204,10 @@ encode_loop(Data, Options, Encoder, Stack, IOBuf) ->
throw(Error);
{partial, IOData} ->
finish_encode(IOData, []);
{iter, NewEncoder, NewStack, NewIOBuf} ->
{iter, {NewEncoder, NewStack, NewIOBuf}} ->
encode_loop(Data, Options, NewEncoder, NewStack, NewIOBuf);
IOData ->
IOData
RevIOData when is_list(RevIOData) ->
lists:reverse(RevIOData)
end.

+ 10
- 9
test/jiffy_02_literal_tests.erl ファイルの表示

@ -4,32 +4,33 @@
-module(jiffy_02_literal_tests).
-include_lib("eunit/include/eunit.hrl").
-include("jiffy_util.hrl").
true_test_() ->
{"true", [
{"Decode", ?_assertEqual(true, jiffy:decode(<<"true">>))},
{"Encode", ?_assertEqual(<<"true">>, jiffy:encode(true))}
{"Decode", ?_assertEqual(true, dec(<<"true">>))},
{"Encode", ?_assertEqual(<<"true">>, enc(true))}
]}.
false_test_() ->
{"false", [
{"Decode", ?_assertEqual(false, jiffy:decode(<<"false">>))},
{"Encode", ?_assertEqual(<<"false">>, jiffy:encode(false))}
{"Decode", ?_assertEqual(false, dec(<<"false">>))},
{"Encode", ?_assertEqual(<<"false">>, enc(false))}
]}.
null_test_() ->
{"null", [
{"Decode", ?_assertEqual(null, jiffy:decode(<<"null">>))},
{"Encode", ?_assertEqual(<<"null">>, jiffy:encode(null))}
{"Decode", ?_assertEqual(null, dec(<<"null">>))},
{"Encode", ?_assertEqual(<<"null">>, enc(null))}
]}.
nil_test_() ->
{"null", [
{"Decode", ?_assertEqual(nil, jiffy:decode(<<"null">>, [use_nil]))},
{"Encode", ?_assertEqual(<<"null">>, jiffy:encode(nil, [use_nil]))}
{"Decode", ?_assertEqual(nil, dec(<<"null">>, [use_nil]))},
{"Encode", ?_assertEqual(<<"null">>, enc(nil, [use_nil]))}
]}.
null_term_test_() ->
@ -41,4 +42,4 @@ null_term_test_() ->
{whatever, [{null_term, undefined}, {null_term, whatever}]}
],
{"null_term",
[?_assertEqual(R, jiffy:decode(<<"null">>, O)) || {R, O} <- T]}.
[?_assertEqual(R, dec(<<"null">>, O)) || {R, O} <- T]}.

+ 1
- 0
test/jiffy_03_number_tests.erl ファイルの表示

@ -48,6 +48,7 @@ cases(ok) ->
{<<"1">>, 1},
{<<"12">>, 12},
{<<"-3">>, -3},
{<<"{\"key\":9223372036854775808}">>,{[{<<"key">>,1 bsl 63}]}},
{<<"1234567890123456789012345">>, 1234567890123456789012345},
{<<"1310050760199">>, 1310050760199},
{

+ 11
- 5
test/jiffy_04_string_tests.erl ファイルの表示

@ -8,6 +8,12 @@
-include("jiffy_util.hrl").
latin1_atom_test_() ->
Key = binary_to_atom(<<228>>, latin1), %% `ä`
Expected = <<"{\"", 195, 164, "\":\"bar\"}">>,
?_assertEqual(Expected, enc(#{ Key => <<"bar">> })).
string_success_test_() ->
[gen(ok, Case) || Case <- cases(ok)].
@ -59,15 +65,15 @@ gen(utf8, {Case, Fixed}) ->
Case2 = <<34, Case/binary, 34>>,
Fixed2 = <<34, Fixed/binary, 34>>,
{msg("UTF-8: ~s", [hex(Case)]), [
?_assertThrow({error, {invalid_string, _}}, jiffy:encode(Case)),
?_assertEqual(Fixed2, jiffy:encode(Case, [force_utf8])),
?_assertThrow({error, {_, invalid_string}}, jiffy:decode(Case2))
?_assertThrow({error, {invalid_string, _}}, enc(Case)),
?_assertEqual(Fixed2, enc(Case, [force_utf8])),
?_assertThrow({error, {_, invalid_string}}, dec(Case2))
]};
gen(bad_utf8_key, {J, E}) ->
{msg("Bad UTF-8 key: - ~p", [size(term_to_binary(J))]), [
?_assertThrow({error, {invalid_object_member_key, _}}, jiffy:encode(J)),
?_assertEqual(E, jiffy:decode(jiffy:encode(J, [force_utf8])))
?_assertThrow({error, {invalid_object_member_key, _}}, enc(J)),
?_assertEqual(E, dec(enc(J, [force_utf8])))
]};
gen(escaped_slashes, {J, E}) ->

+ 10
- 0
test/jiffy_05_array_tests.erl ファイルの表示

@ -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 ファイルの表示

@ -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}) ->

+ 1
- 1
test/jiffy_10_short_double_tests.erl ファイルの表示

@ -23,7 +23,7 @@ run(Fd, Acc) ->
V1 = re:replace(iolist_to_binary(Data), <<"\.\n">>, <<"">>),
V2 = iolist_to_binary(V1),
V3 = <<34, V2/binary, 34>>,
R = jiffy:encode(jiffy:decode(V3)),
R = enc(dec(V3)),
case R == V3 of
true -> run(Fd, Acc);
false -> run(Fd, Acc + 1)

+ 2
- 0
test/jiffy_util.hrl ファイルの表示

@ -17,6 +17,8 @@ hex(Bin) when is_binary(Bin) ->
dec(V) ->
jiffy:decode(V).
dec(V, Opts) ->
jiffy:decode(V, Opts).
enc(V) ->

読み込み中…
キャンセル
保存