Compare commits

...

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

Loading…
取消
儲存