You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@couchdb.apache.org by kx...@apache.org on 2015/07/13 20:45:10 UTC
[11/43] jiffy commit: updated refs/heads/upstream to 446e284
Initial support for the new map type
This patch adds initial support for decoding/encoding to/from the new
maps data type.
I'd like to thank Jihyun Yu (yjh0502) for the initial versions of this
work.
Project: http://git-wip-us.apache.org/repos/asf/couchdb-jiffy/repo
Commit: http://git-wip-us.apache.org/repos/asf/couchdb-jiffy/commit/b96de951
Tree: http://git-wip-us.apache.org/repos/asf/couchdb-jiffy/tree/b96de951
Diff: http://git-wip-us.apache.org/repos/asf/couchdb-jiffy/diff/b96de951
Branch: refs/heads/upstream
Commit: b96de951a2a9fabda48b4e3ed4958bf898cde913
Parents: 577d7e0
Author: Paul J. Davis <pa...@gmail.com>
Authored: Mon Jun 16 16:17:51 2014 -0500
Committer: Paul J. Davis <pa...@gmail.com>
Committed: Mon Jun 16 16:17:51 2014 -0500
----------------------------------------------------------------------
c_src/decoder.c | 54 +++++++++++++++++++++++++++++++++++++++++------
c_src/encoder.c | 51 ++++++++++++++++++++++++++++++++++++++++++++
c_src/jiffy.c | 1 +
c_src/jiffy.h | 5 +++++
rebar.config | 3 +++
rebar.config.script | 14 +++++++-----
src/jiffy.erl | 13 ++++++++++++
src/jiffy_utf8.erl | 12 +++++++++++
test/jiffy_tests.erl | 18 ++++++++++++++++
9 files changed, 160 insertions(+), 11 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/couchdb-jiffy/blob/b96de951/c_src/decoder.c
----------------------------------------------------------------------
diff --git a/c_src/decoder.c b/c_src/decoder.c
index c02b18d..7cc74bd 100644
--- a/c_src/decoder.c
+++ b/c_src/decoder.c
@@ -51,6 +51,7 @@ typedef struct {
size_t bytes_per_iter;
int is_partial;
+ int return_maps;
char* p;
unsigned char* u;
@@ -77,6 +78,7 @@ dec_new(ErlNifEnv* env)
d->bytes_per_iter = DEFAULT_BYTES_PER_ITER;
d->is_partial = 0;
+ d->return_maps = 0;
d->p = NULL;
d->u = NULL;
@@ -606,11 +608,41 @@ parse:
}
ERL_NIF_TERM
-make_object(ErlNifEnv* env, ERL_NIF_TERM pairs)
+make_empty_object(ErlNifEnv* env, int ret_map)
{
- ERL_NIF_TERM ret = enif_make_list(env, 0);
- ERL_NIF_TERM key, val;
+#if MAP_TYPE_PRESENT
+ if(ret_map) {
+ return enif_make_new_map(env);
+ }
+#endif
+
+ return enif_make_tuple1(env, enif_make_list(env, 0));
+}
+
+int
+make_object(ErlNifEnv* env, ERL_NIF_TERM pairs, ERL_NIF_TERM* out, int ret_map)
+{
+ ERL_NIF_TERM ret;
+ ERL_NIF_TERM key;
+ ERL_NIF_TERM val;
+#if MAP_TYPE_PRESENT
+ if(ret_map) {
+ ret = enif_make_new_map(env);
+ while(enif_get_list_cell(env, pairs, &val, &pairs)) {
+ if(!enif_get_list_cell(env, pairs, &key, &pairs)) {
+ assert(0 == 1 && "Unbalanced object pairs.");
+ }
+ if(!enif_make_map_put(env, ret, key, val, &ret)) {
+ return 0;
+ }
+ }
+ *out = ret;
+ return 1;
+ }
+#endif
+
+ ret = enif_make_list(env, 0);
while(enif_get_list_cell(env, pairs, &val, &pairs)) {
if(!enif_get_list_cell(env, pairs, &key, &pairs)) {
assert(0 == 1 && "Unbalanced object pairs.");
@@ -618,8 +650,9 @@ make_object(ErlNifEnv* env, ERL_NIF_TERM pairs)
val = enif_make_tuple2(env, key, val);
ret = enif_make_list_cell(env, val, ret);
}
+ *out = enif_make_tuple1(env, ret);
- return enif_make_tuple1(env, ret);
+ return 1;
}
ERL_NIF_TERM
@@ -668,6 +701,12 @@ decode_init(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
while(enif_get_list_cell(env, opts, &val, &opts)) {
if(get_bytes_per_iter(env, val, &(d->bytes_per_iter))) {
continue;
+ } else if(enif_compare(val, d->atoms->atom_return_maps) == 0) {
+#if MAP_TYPE_PRESENT
+ d->return_maps = 1;
+#else
+ return enif_make_badarg(env);
+#endif
} else {
return enif_make_badarg(env);
}
@@ -862,7 +901,7 @@ decode_iter(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
dec_pop(d, st_key);
dec_pop(d, st_object);
dec_pop(d, st_value);
- val = enif_make_tuple1(env, curr);
+ val = make_empty_object(env, d->return_maps);
if(!enif_get_list_cell(env, objs, &curr, &objs)) {
ret = dec_error(d, "internal_error");
goto done;
@@ -931,7 +970,10 @@ decode_iter(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
}
dec_pop(d, st_object);
dec_pop(d, st_value);
- val = make_object(env, curr);
+ if(!make_object(env, curr, &val, d->return_maps)) {
+ ret = dec_error(d, "internal_object_error");
+ goto done;
+ }
if(!enif_get_list_cell(env, objs, &curr, &objs)) {
ret = dec_error(d, "internal_error");
goto done;
http://git-wip-us.apache.org/repos/asf/couchdb-jiffy/blob/b96de951/c_src/encoder.c
----------------------------------------------------------------------
diff --git a/c_src/encoder.c b/c_src/encoder.c
index 86813e0..fff9752 100644
--- a/c_src/encoder.c
+++ b/c_src/encoder.c
@@ -500,6 +500,49 @@ enc_comma(Encoder* e)
return 1;
}
+#if MAP_TYPE_PRESENT
+int
+enc_map_to_ejson(ErlNifEnv* env, ERL_NIF_TERM map, ERL_NIF_TERM* out)
+{
+ ErlNifMapIterator iter;
+ size_t size;
+
+ ERL_NIF_TERM list;
+ ERL_NIF_TERM tuple;
+ ERL_NIF_TERM key;
+ ERL_NIF_TERM val;
+
+ if(!enif_get_map_size(env, map, &size)) {
+ fprintf(stderr, "bad map size\r\n");
+ return 0;
+ }
+
+ list = enif_make_list(env, 0);
+
+ if(size == 0) {
+ *out = enif_make_tuple1(env, list);
+ return 1;
+ }
+
+ if(!enif_map_iterator_create(env, map, &iter, ERL_NIF_MAP_ITERATOR_HEAD)) {
+ fprintf(stderr, "bad iterator create\r\n");
+ return 0;
+ }
+
+ do {
+ if(!enif_map_iterator_get_pair(env, &iter, &key, &val)) {
+ fprintf(stderr, "bad get pair\r\n");
+ return 0;
+ }
+ tuple = enif_make_tuple2(env, key, val);
+ list = enif_make_list_cell(env, tuple, list);
+ } while(enif_map_iterator_next(env, &iter));
+
+ *out = enif_make_tuple1(env, list);
+ return 1;
+}
+#endif
+
ERL_NIF_TERM
encode_init(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
@@ -743,6 +786,14 @@ encode_iter(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
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);
+#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);
+#endif
} else if(enif_is_list(env, curr)) {
if(!enc_start_array(e)) {
ret = enc_error(e, "internal_error");
http://git-wip-us.apache.org/repos/asf/couchdb-jiffy/blob/b96de951/c_src/jiffy.c
----------------------------------------------------------------------
diff --git a/c_src/jiffy.c b/c_src/jiffy.c
index d8b11c3..b3b4ba4 100644
--- a/c_src/jiffy.c
+++ b/c_src/jiffy.c
@@ -25,6 +25,7 @@ load(ErlNifEnv* env, void** priv, ERL_NIF_TERM info)
st->atom_force_utf8 = make_atom(env, "force_utf8");
st->atom_iter = make_atom(env, "iter");
st->atom_bytes_per_iter = make_atom(env, "bytes_per_iter");
+ st->atom_return_maps = make_atom(env, "return_maps");
// Markers used in encoding
st->ref_object = make_atom(env, "$object_ref$");
http://git-wip-us.apache.org/repos/asf/couchdb-jiffy/blob/b96de951/c_src/jiffy.h
----------------------------------------------------------------------
diff --git a/c_src/jiffy.h b/c_src/jiffy.h
index b0cc75d..90f364c 100644
--- a/c_src/jiffy.h
+++ b/c_src/jiffy.h
@@ -8,6 +8,10 @@
#define DEFAULT_BYTES_PER_ITER 2048
+#define MAP_TYPE_PRESENT \
+ ((ERL_NIF_MAJOR_VERSION == 2 && ERL_NIF_MINOR_VERSION >= 6) \
+ || (ERL_NIF_MAJOR_VERSION > 2))
+
typedef struct {
ERL_NIF_TERM atom_ok;
ERL_NIF_TERM atom_error;
@@ -23,6 +27,7 @@ typedef struct {
ERL_NIF_TERM atom_force_utf8;
ERL_NIF_TERM atom_iter;
ERL_NIF_TERM atom_bytes_per_iter;
+ ERL_NIF_TERM atom_return_maps;
ERL_NIF_TERM ref_object;
ERL_NIF_TERM ref_array;
http://git-wip-us.apache.org/repos/asf/couchdb-jiffy/blob/b96de951/rebar.config
----------------------------------------------------------------------
diff --git a/rebar.config b/rebar.config
index 67625e9..831ca38 100644
--- a/rebar.config
+++ b/rebar.config
@@ -25,6 +25,9 @@
{"win32", "CXXFLAGS", "-g -Wall -O3"}
]}.
+{erl_opts, [
+ {platform_define, "R1(1|2|3|4|5|6)", 'JIFFY_NO_MAPS'}
+]}.
{eunit_opts, [
verbose,
http://git-wip-us.apache.org/repos/asf/couchdb-jiffy/blob/b96de951/rebar.config.script
----------------------------------------------------------------------
diff --git a/rebar.config.script b/rebar.config.script
index 58d4ff7..8a0049d 100644
--- a/rebar.config.script
+++ b/rebar.config.script
@@ -7,9 +7,7 @@
%
% This script is based on the example provided with Rebar.
-ErlOpts = {erl_opts, [
- {d, 'JIFFY_DEV'}
-]},
+ErlOpts = [{d, 'JIFFY_DEV'}],
Proper = [
{proper, ".*", {git, "git://github.com/manopapad/proper.git", "master"}}
@@ -21,13 +19,19 @@ DevMarker = filename:join([ConfigPath, ".jiffy.dev"]),
case filelib:is_file(DevMarker) of
true ->
% Don't override existing dependencies
- NewConfig = case lists:keyfind(deps, 1, CONFIG) of
+ Config0 = case lists:keyfind(deps, 1, CONFIG) of
false ->
CONFIG ++ [{deps, Proper}];
{deps, DepsList} ->
lists:keyreplace(deps, 1, CONFIG, {deps, DepsList ++ Proper})
end,
- NewConfig ++ [ErlOpts];
+ Config1 = case lists:keyfind(erl_opts, 1, Config0) of
+ false ->
+ Config0 ++ [{erl_opts, ErlOpts}];
+ {erl_opts, Opts} ->
+ NewOpts = {erl_opts, Opts ++ ErlOpts},
+ lists:keyreplace(erl_opts, 1, Config0, NewOpts)
+ end;
false ->
CONFIG
end.
http://git-wip-us.apache.org/repos/asf/couchdb-jiffy/blob/b96de951/src/jiffy.erl
----------------------------------------------------------------------
diff --git a/src/jiffy.erl b/src/jiffy.erl
index 26e03d1..8903831 100644
--- a/src/jiffy.erl
+++ b/src/jiffy.erl
@@ -67,7 +67,20 @@ finish_decode({Pairs}) when is_list(Pairs) ->
finish_decode(Vals) when is_list(Vals) ->
finish_decode_arr(Vals, []);
finish_decode(Val) ->
+ maybe_map(Val).
+
+-ifndef(JIFFY_NO_MAPS).
+maybe_map(Obj) when is_map(Obj) ->
+ maps:map(fun finish_decode_map/2, Obj);
+maybe_map(Val) ->
+ Val.
+
+finish_decode_map(_, V) ->
+ finish_decode(V).
+-else.
+maybe_map(Val) ->
Val.
+-endif.
finish_decode_obj([], Acc) ->
{lists:reverse(Acc)};
http://git-wip-us.apache.org/repos/asf/couchdb-jiffy/blob/b96de951/src/jiffy_utf8.erl
----------------------------------------------------------------------
diff --git a/src/jiffy_utf8.erl b/src/jiffy_utf8.erl
index ee937fe..f36cbc7 100644
--- a/src/jiffy_utf8.erl
+++ b/src/jiffy_utf8.erl
@@ -12,8 +12,20 @@ fix(Values) when is_list(Values) ->
fix(Bin) when is_binary(Bin) ->
fix_bin(Bin);
fix(Val) ->
+ maybe_map(Val).
+
+-ifndef(JIFFY_NO_MAPS).
+maybe_map(Obj) when is_map(Obj) ->
+ maps:fold(fun fix_map/3, maps:new(), Obj);
+maybe_map(Val) ->
Val.
+fix_map(K, V, Acc) ->
+ maps:put(fix(K), fix(V), Acc).
+-else.
+maybe_map(Val) ->
+ Val.
+-endif.
fix_props([], Acc) ->
{lists:reverse(Acc)};
http://git-wip-us.apache.org/repos/asf/couchdb-jiffy/blob/b96de951/test/jiffy_tests.erl
----------------------------------------------------------------------
diff --git a/test/jiffy_tests.erl b/test/jiffy_tests.erl
index 0655b0d..9ecea32 100644
--- a/test/jiffy_tests.erl
+++ b/test/jiffy_tests.erl
@@ -26,6 +26,24 @@ prop_encode_decode() ->
end
).
+-ifndef(JIFFY_NO_MAPS).
+to_map_ejson({Props}) ->
+ NewProps = [{K, to_map_ejson(V)} || {K, V} <- Props],
+ maps:from_list(NewProps);
+to_map_ejson(Vals) when is_list(Vals) ->
+ [to_map_ejson(V) || V <- Vals];
+to_map_ejson(Val) ->
+ Val.
+
+prop_map_encode_decode() ->
+ ?FORALL(Data, json(),
+ begin
+ MapData = to_map_ejson(Data),
+ MapData == jiffy:decode(jiffy:encode(MapData), [return_maps])
+ end
+ ).
+-endif.
+
prop_encode_decode_pretty() ->
?FORALL(Data, json(),
begin