Permalink
Browse files

Added ejson application

This is a NIF based JSON decoder/encoder based on Paul Davis' eep0018
implementation (https://github.com/davisp/eep0018/), with some modifications
from Damien (big number support and optimizations) on top, plus a few fixes
from my side and Benoît on top of Damien's fork.
This module fallbacks to mochijson2 when the NIF is not loaded or compiled.
The NIF is only compiled and used if we're using an OTP release >= R13B04.

Thanks everyone. Closes COUCHDB-1118.



git-svn-id: https://svn.apache.org/repos/asf/couchdb/trunk@1088941 13f79535-47bb-0310-9956-ffa450edef68
  • Loading branch information...
1 parent 16aa3d8 commit 3925e856078717a4b3c1ed58918a11cf90a758b9 @fdmanana fdmanana committed Apr 5, 2011
Showing with 5,086 additions and 58 deletions.
  1. +4 −0 .gitignore
  2. +10 −0 NOTICE
  3. +5 −0 configure.ac
  4. +1 −1 src/Makefile.am
  5. +1 −1 src/couchdb/couch_api_wrap.erl
  6. +2 −2 src/couchdb/couch_db.hrl
  7. +3 −3 src/couchdb/couch_httpd_external.erl
  8. +1 −1 src/couchdb/couch_os_process.erl
  9. +0 −17 src/couchdb/couch_util.erl
  10. +86 −0 src/ejson/Makefile.am
  11. +296 −0 src/ejson/decode.c
  12. +9 −0 src/ejson/ejson.app.in
  13. +30 −0 src/ejson/ejson.c
  14. +151 −0 src/ejson/ejson.erl
  15. +164 −0 src/ejson/encode.c
  16. +102 −0 src/ejson/erl_nif_compat.h
  17. +849 −0 src/ejson/mochijson2.erl
  18. +354 −0 src/ejson/mochinum.erl
  19. +159 −0 src/ejson/yajl/yajl.c
  20. +65 −0 src/ejson/yajl/yajl_alloc.c
  21. +50 −0 src/ejson/yajl/yajl_alloc.h
  22. +119 −0 src/ejson/yajl/yajl_buf.c
  23. +73 −0 src/ejson/yajl/yajl_buf.h
  24. +85 −0 src/ejson/yajl/yajl_bytestack.h
  25. +85 −0 src/ejson/yajl/yajl_common.h
  26. +188 −0 src/ejson/yajl/yajl_encode.c
  27. +50 −0 src/ejson/yajl/yajl_encode.h
  28. +322 −0 src/ejson/yajl/yajl_gen.c
  29. +159 −0 src/ejson/yajl/yajl_gen.h
  30. +737 −0 src/ejson/yajl/yajl_lex.c
  31. +133 −0 src/ejson/yajl/yajl_lex.h
  32. +193 −0 src/ejson/yajl/yajl_parse.h
  33. +470 −0 src/ejson/yajl/yajl_parser.c
  34. +95 −0 src/ejson/yajl/yajl_parser.h
  35. +1 −1 test/etap/130-attachments-md5.t
  36. +12 −12 test/etap/140-attachment-comp.t
  37. +2 −2 test/etap/150-invalid-view-seq.t
  38. +13 −13 test/etap/160-vhosts.t
  39. +4 −2 test/etap/171-os-daemons-config.es
  40. +1 −2 test/etap/173-os-daemon-cfg-register.es
  41. +1 −1 test/etap/test_util.erl.in
  42. +1 −0 utils/Makefile.am
View
@@ -64,6 +64,10 @@ src/couchdb/priv/couchspawnkillable
src/couchdb/priv/stat_descriptions.cfg
src/erlang-oauth/oauth.app
src/ibrowse/ibrowse.app
+src/ejson/ejson.app
+src/ejson/.deps/
+src/ejson/.libs/
+src/ejson/priv
src/mochiweb/mochiweb.app
test/local.ini
test/etap/run
View
10 NOTICE
@@ -49,3 +49,13 @@ This product also includes the following third-party components:
* jspec.js (http://visionmedia.github.com/jspec/)
Copyright 2010 TJ Holowaychuk <tj@vision-media.ca>
+
+ * yajl (http://lloyd.github.com/yajl/)
+
+ Copyright 2010, Lloyd Hilaiel
+
+ * ejson
+
+ Based on Paul Davis' eep0018 implementation (https://github.com/davisp/eep0018/),
+ with some modifications from Damien Katz, Filipe Manana and Benoît Chesneau.
+ This application uses yajl.
View
@@ -262,6 +262,10 @@ if test `echo $version | ${AWK} "{print \\$2}"` -eq 6; then
fi
fi
+otp_release="`${ERL} -noshell -eval 'io:put_chars(erlang:system_info(otp_release)).' -s erlang halt`"
+AC_SUBST(otp_release)
+AM_CONDITIONAL([USE_OTP_NIFS], [test x$otp_release \> xR13B03])
+
has_crypto=`${ERL} -eval "case application:load(crypto) of ok -> ok; _ -> exit(no_crypto) end." -noshell -s init stop`
if test -n "$has_crypto"; then
@@ -419,6 +423,7 @@ AC_CONFIG_FILES([src/erlang-oauth/Makefile])
AC_CONFIG_FILES([src/etap/Makefile])
AC_CONFIG_FILES([src/ibrowse/Makefile])
AC_CONFIG_FILES([src/mochiweb/Makefile])
+AC_CONFIG_FILES([src/ejson/Makefile])
AC_CONFIG_FILES([test/Makefile])
AC_CONFIG_FILES([test/bench/Makefile])
AC_CONFIG_FILES([test/etap/Makefile])
View
@@ -10,4 +10,4 @@
## License for the specific language governing permissions and limitations under
## the License.
-SUBDIRS = couchdb erlang-oauth etap ibrowse mochiweb
+SUBDIRS = couchdb erlang-oauth etap ibrowse mochiweb ejson
@@ -427,7 +427,7 @@ options_to_query_args([revs | Rest], Acc) ->
options_to_query_args([{open_revs, all} | Rest], Acc) ->
options_to_query_args(Rest, [{"open_revs", "all"} | Acc]);
options_to_query_args([{open_revs, Revs} | Rest], Acc) ->
- JsonRevs = ?JSON_ENCODE(couch_doc:revs_to_strs(Revs)),
+ JsonRevs = ?b2l(?JSON_ENCODE(couch_doc:revs_to_strs(Revs))),
options_to_query_args(Rest, [{"open_revs", JsonRevs} | Acc]).
View
@@ -20,8 +20,8 @@
% the lowest possible database sequence number
-define(LOWEST_SEQ, 0).
--define(JSON_ENCODE(V), couch_util:json_encode(V)).
--define(JSON_DECODE(V), couch_util:json_decode(V)).
+-define(JSON_ENCODE(V), ejson:encode(V)).
+-define(JSON_DECODE(V), ejson:decode(V)).
-define(b2l(V), binary_to_list(V)).
-define(l2b(V), list_to_binary(V)).
@@ -105,11 +105,11 @@ json_query_keys({Json}) ->
json_query_keys([], Acc) ->
{lists:reverse(Acc)};
json_query_keys([{<<"startkey">>, Value} | Rest], Acc) ->
- json_query_keys(Rest, [{<<"startkey">>, couch_util:json_decode(Value)}|Acc]);
+ json_query_keys(Rest, [{<<"startkey">>, ?JSON_DECODE(Value)}|Acc]);
json_query_keys([{<<"endkey">>, Value} | Rest], Acc) ->
- json_query_keys(Rest, [{<<"endkey">>, couch_util:json_decode(Value)}|Acc]);
+ json_query_keys(Rest, [{<<"endkey">>, ?JSON_DECODE(Value)}|Acc]);
json_query_keys([{<<"key">>, Value} | Rest], Acc) ->
- json_query_keys(Rest, [{<<"key">>, couch_util:json_decode(Value)}|Acc]);
+ json_query_keys(Rest, [{<<"key">>, ?JSON_DECODE(Value)}|Acc]);
json_query_keys([Term | Rest], Acc) ->
json_query_keys(Rest, [Term|Acc]).
@@ -60,7 +60,7 @@ prompt(Pid, Data) ->
% Utility functions for reading and writing
% in custom functions
writeline(OsProc, Data) when is_record(OsProc, os_proc) ->
- port_command(OsProc#os_proc.port, Data ++ "\n").
+ port_command(OsProc#os_proc.port, [Data, $\n]).
readline(#os_proc{} = OsProc) ->
readline(OsProc, []).
View
@@ -21,7 +21,6 @@
-export([get_nested_json_value/2, json_user_ctx/1]).
-export([proplist_apply_field/2, json_apply_field/2]).
-export([to_binary/1, to_integer/1, to_list/1, url_encode/1]).
--export([json_encode/1, json_decode/1]).
-export([verify/2,simple_call/2,shutdown_sync/1]).
-export([get_value/2, get_value/3]).
-export([md5/1, md5_init/0, md5_update/2, md5_final/1]).
@@ -374,22 +373,6 @@ url_encode([H|T]) ->
url_encode([]) ->
[].
-json_encode(V) ->
- Handler =
- fun({L}) when is_list(L) ->
- {struct,L};
- (Bad) ->
- exit({json_encode, {bad_term, Bad}})
- end,
- (mochijson2:encoder([{handler, Handler}]))(V).
-
-json_decode(V) ->
- try (mochijson2:decoder([{object_hook, fun({struct,L}) -> {L} end}]))(V)
- catch
- _Type:_Error ->
- throw({invalid_json,V})
- end.
-
verify([X|RestX], [Y|RestY], Result) ->
verify(RestX, RestY, (X bxor Y) bor Result);
verify([], [], Result) ->
View
@@ -0,0 +1,86 @@
+## Licensed under the Apache License, Version 2.0 (the "License"); you may not
+## use this file except in compliance with the License. You may obtain a copy of
+## the License at
+##
+## http://www.apache.org/licenses/LICENSE-2.0
+##
+## Unless required by applicable law or agreed to in writing, software
+## distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+## WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+## License for the specific language governing permissions and limitations under
+## the License.
+
+ejsonebindir = $(localerlanglibdir)/ejson-0.1.0/ebin
+ejsonprivdir = $(localerlanglibdir)/ejson-0.1.0/priv
+
+CLEANFILES = \
+ $(ejsonebin_make_generated_file_list) \
+ $(ejsonpriv_make_generated_file_list)
+
+if USE_OTP_NIFS
+ejsonpriv_LTLIBRARIES = ejson.la
+endif
+
+EJSON_C_SRCS = \
+ ejson.c \
+ decode.c \
+ encode.c \
+ yajl/yajl_alloc.c \
+ yajl/yajl_buf.c \
+ yajl/yajl.c \
+ yajl/yajl_encode.c \
+ yajl/yajl_gen.c \
+ yajl/yajl_lex.c \
+ yajl/yajl_parser.c
+
+if USE_OTP_NIFS
+ejson_la_SOURCES = $(EJSON_C_SRCS)
+ejson_la_LDFLAGS = -module -avoid-version
+
+if WINDOWS
+ejson_la_LDFLAGS += -no-undefined
+endif
+endif
+
+ejson_file_collection = \
+ ejson.app.in \
+ ejson.erl \
+ mochijson2.erl \
+ mochinum.erl \
+ $(JSON_C_SRCS)
+
+ejsonebin_make_generated_file_list = \
+ ejson.app \
+ ejson.beam \
+ mochijson2.beam \
+ mochinum.beam
+
+ejsonebin_DATA = \
+ $(ejsonebin_make_generated_file_list)
+
+EXTRA_DIST = \
+ $(ejson_file_collection) \
+ erl_nif_compat.h \
+ yajl/yajl_alloc.h \
+ yajl/yajl_buf.h \
+ yajl/yajl_bytestack.h \
+ yajl/yajl_common.h \
+ yajl/yajl_encode.h \
+ yajl/yajl_gen.h \
+ yajl/yajl_lex.h \
+ yajl/yajl_parse.h \
+ yajl/yajl_parser.h \
+ priv
+
+if USE_OTP_NIFS
+priv/ejson.so: .libs/ejson.so
+ $(LN_S) .libs priv
+
+all: priv/ejson.so
+endif
+
+%.app: %.app.in
+ cp $< $@
+
+%.beam: %.erl
+ $(ERLC) $(ERLC_FLAGS) $<
Oops, something went wrong.

0 comments on commit 3925e85

Please sign in to comment.