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