Skip to content

Commit

Permalink
Added couch_ejson_compare NIF
Browse files Browse the repository at this point in the history
It's functionally equivalent to couch_view:json_less/2
  • Loading branch information
fdmanana committed Jun 3, 2011
1 parent 99a4982 commit 3935a4a
Show file tree
Hide file tree
Showing 6 changed files with 615 additions and 57 deletions.
2 changes: 2 additions & 0 deletions src/couchdb/Makefile.am
Expand Up @@ -42,6 +42,7 @@ source_files = \
couch_db_update_notifier_sup.erl \
couch_doc.erl \
couch_drv.erl \
couch_ejson_compare.erl \
couch_event_sup.erl \
couch_external_manager.erl \
couch_external_server.erl \
Expand Down Expand Up @@ -111,6 +112,7 @@ compiled_files = \
couch_db_update_notifier_sup.beam \
couch_doc.beam \
couch_drv.beam \
couch_ejson_compare.beam \
couch_event_sup.beam \
couch_external_manager.beam \
couch_external_server.beam \
Expand Down
100 changes: 100 additions & 0 deletions src/couchdb/couch_ejson_compare.erl
@@ -0,0 +1,100 @@
% 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.

-module(couch_ejson_compare).

-export([less/2]).

-on_load(init/0).


init() ->
LibDir = case couch_config:get("couchdb", "util_driver_dir") of
undefined ->
filename:join(couch_util:priv_dir(), "lib");
LibDir0 ->
LibDir0
end,
(catch erlang:load_nif(filename:join([LibDir, ?MODULE]), 0)),
case erlang:system_info(otp_release) of
"R13B03" -> true;
_ -> ok
end.


less(A, B) ->
try
less_nif(A, B)
catch
exit:{not_loaded, ?MODULE} ->
less_erl(A, B)
end.


less_nif(_, _) ->
exit({not_loaded, ?MODULE}).


less_erl(A,A) -> 0;

less_erl(A,B) when is_atom(A), is_atom(B) -> atom_sort(A) - atom_sort(B);
less_erl(A,_) when is_atom(A) -> -1;
less_erl(_,B) when is_atom(B) -> 1;

less_erl(A,B) when is_number(A), is_number(B) -> A - B;
less_erl(A,_) when is_number(A) -> -1;
less_erl(_,B) when is_number(B) -> 1;

less_erl(A,B) when is_binary(A), is_binary(B) -> couch_util:collate(A,B);
less_erl(A,_) when is_binary(A) -> -1;
less_erl(_,B) when is_binary(B) -> 1;

less_erl(A,B) when is_list(A), is_list(B) -> less_list(A,B);
less_erl(A,_) when is_list(A) -> -1;
less_erl(_,B) when is_list(B) -> 1;

less_erl({A},{B}) when is_list(A), is_list(B) -> less_props(A,B);
less_erl({A},_) when is_list(A) -> -1;
less_erl(_,{B}) when is_list(B) -> 1.

atom_sort(null) -> 1;
atom_sort(false) -> 2;
atom_sort(true) -> 3.

less_props([], [_|_]) ->
-1;
less_props(_, []) ->
1;
less_props([{AKey, AValue}|RestA], [{BKey, BValue}|RestB]) ->
case couch_util:collate(AKey, BKey) of
0 ->
case less_erl(AValue, BValue) of
0 ->
less_props(RestA, RestB);
Result ->
Result
end;
Result ->
Result
end.

less_list([], [_|_]) ->
-1;
less_list(_, []) ->
1;
less_list([A|RestA], [B|RestB]) ->
case less_erl(A,B) of
0 ->
less_list(RestA, RestB);
Result ->
Result
end.
59 changes: 2 additions & 57 deletions src/couchdb/couch_view.erl
Expand Up @@ -394,67 +394,12 @@ nuke_dir(RootDelDir, Dir) ->

% keys come back in the language of btree - tuples.
less_json_ids({JsonA, IdA}, {JsonB, IdB}) ->
case less_json0(JsonA, JsonB) of
case couch_ejson_compare:less(JsonA, JsonB) of
0 ->
IdA < IdB;
Result ->
Result < 0
end.

less_json(A,B) ->
less_json0(A,B) < 0.

less_json0(A,A) -> 0;

less_json0(A,B) when is_atom(A), is_atom(B) -> atom_sort(A) - atom_sort(B);
less_json0(A,_) when is_atom(A) -> -1;
less_json0(_,B) when is_atom(B) -> 1;

less_json0(A,B) when is_number(A), is_number(B) -> A - B;
less_json0(A,_) when is_number(A) -> -1;
less_json0(_,B) when is_number(B) -> 1;

less_json0(A,B) when is_binary(A), is_binary(B) -> couch_util:collate(A,B);
less_json0(A,_) when is_binary(A) -> -1;
less_json0(_,B) when is_binary(B) -> 1;

less_json0(A,B) when is_list(A), is_list(B) -> less_list(A,B);
less_json0(A,_) when is_list(A) -> -1;
less_json0(_,B) when is_list(B) -> 1;

less_json0({A},{B}) when is_list(A), is_list(B) -> less_props(A,B);
less_json0({A},_) when is_list(A) -> -1;
less_json0(_,{B}) when is_list(B) -> 1.

atom_sort(null) -> 1;
atom_sort(false) -> 2;
atom_sort(true) -> 3.

less_props([], [_|_]) ->
-1;
less_props(_, []) ->
1;
less_props([{AKey, AValue}|RestA], [{BKey, BValue}|RestB]) ->
case couch_util:collate(AKey, BKey) of
0 ->
case less_json0(AValue, BValue) of
0 ->
less_props(RestA, RestB);
Result ->
Result
end;
Result ->
Result
end.

less_list([], [_|_]) ->
-1;
less_list(_, []) ->
1;
less_list([A|RestA], [B|RestB]) ->
case less_json0(A,B) of
0 ->
less_list(RestA, RestB);
Result ->
Result
end.
couch_ejson_compare:less(A, B) < 0.
20 changes: 20 additions & 0 deletions src/couchdb/priv/Makefile.am
Expand Up @@ -28,6 +28,21 @@ ICU_LOCAL_LIBS=-licuuc -licudata -licui18n
endif

couchprivlib_LTLIBRARIES = couch_icu_driver.la
if USE_OTP_NIFS
couchprivlib_LTLIBRARIES += couch_ejson_compare.la
COUCH_EJSON_COMPARE_SRCS = \
couch_ejson_compare/erl_nif_compat.h \
couch_ejson_compare/couch_ejson_compare.c

couch_ejson_compare_la_SOURCES = $(COUCH_EJSON_COMPARE_SRCS)
couch_ejson_compare_la_CFLAGS = -D_BSD_SOURCE $(ICU_LOCAL_FLAGS)
couch_ejson_compare_la_LDFLAGS = -module -avoid-version $(ICU_LOCAL_FLAGS)
couch_ejson_compare_la_LIBADD = $(ICU_LOCAL_LIBS)

if WINDOWS
couch_ejson_compare_la_LDFLAGS += -no-undefined
endif
endif
couch_icu_driver_la_SOURCES = icu_driver/couch_icu_driver.c
couch_icu_driver_la_LDFLAGS = -module -avoid-version $(ICU_LOCAL_FLAGS)
couch_icu_driver_la_CFLAGS = $(ICU_LOCAL_FLAGS)
Expand Down Expand Up @@ -77,6 +92,11 @@ install-data-hook:
cd "$(DESTDIR)$(couchprivlibdir)" && \
$(LN_S) couch_icu_driver couch_icu_driver.so; \
fi
if test -f "$(DESTDIR)$(couchprivlibdir)/couch_ejson_compare_nif"; then \
rm -f "$(DESTDIR)$(couchprivlibdir)/couch_ejson_compare_nif.so"; \
cd "$(DESTDIR)$(couchprivlibdir)" && \
$(LN_S) couch_ejson_compare_nif couch_ejson_compare_nif.so; \
fi
if WINDOWS
$(INSTALL) $(ICU_LOCAL_BIN)/icuuc42.dll $(bindir)
$(INSTALL) $(ICU_LOCAL_BIN)/icudt42.dll $(bindir)
Expand Down

0 comments on commit 3935a4a

Please sign in to comment.