blob: 083ff42d09871385efed5f0abb530e9ebbe4ebd8 [file] [log] [blame]
% 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, less_json_ids/2, less_json/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,
NumScheds = erlang:system_info(schedulers),
(catch erlang:load_nif(filename:join([LibDir, ?MODULE]), NumScheds)),
case erlang:system_info(otp_release) of
"R13B03" -> true;
_ -> ok
end.
less(A, B) ->
try
less_nif(A, B)
catch
error:badarg ->
% Maybe the EJSON structure is too deep, fallback to Erlang land.
less_erl(A, B)
end.
less_json_ids({JsonA, IdA}, {JsonB, IdB}) ->
case less(JsonA, JsonB) of
0 ->
IdA < IdB;
Result ->
Result < 0
end.
less_json(A,B) ->
less(A, B) < 0.
less_nif(A, B) ->
less_erl(A, B).
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.