aboutsummaryrefslogtreecommitdiffstats
path: root/erts/emulator/test
diff options
context:
space:
mode:
authorGuilherme Andrade <[email protected]>2017-04-19 00:43:37 +0100
committerGuilherme Andrade <[email protected]>2017-04-19 01:25:35 +0100
commit0835f40ae25f97360dc393928796387d3cd6b16e (patch)
tree22b56cc3a6cb90d79efb394ecd1fab58e1182f8c /erts/emulator/test
parent6124bfc9b61227a5e82f1d7273d0895e909aac6e (diff)
downloadotp-0835f40ae25f97360dc393928796387d3cd6b16e.tar.gz
otp-0835f40ae25f97360dc393928796387d3cd6b16e.tar.bz2
otp-0835f40ae25f97360dc393928796387d3cd6b16e.zip
erts: Add enif_phash2 and enif_phash2_ranged
These allow one to hash VM terms from NIF code.
Diffstat (limited to 'erts/emulator/test')
-rw-r--r--erts/emulator/test/nif_SUITE.erl85
-rw-r--r--erts/emulator/test/nif_SUITE_data/nif_SUITE.c19
2 files changed, 102 insertions, 2 deletions
diff --git a/erts/emulator/test/nif_SUITE.erl b/erts/emulator/test/nif_SUITE.erl
index 693db42e58..780fe0a5ee 100644
--- a/erts/emulator/test/nif_SUITE.erl
+++ b/erts/emulator/test/nif_SUITE.erl
@@ -56,7 +56,9 @@
nif_is_process_alive/1, nif_is_port_alive/1,
nif_term_to_binary/1, nif_binary_to_term/1,
nif_port_command/1,
- nif_snprintf/1
+ nif_snprintf/1,
+ nif_phash2/1,
+ nif_phash2_ranged/1
]).
-export([many_args_100/100]).
@@ -90,7 +92,9 @@ all() ->
nif_is_process_alive, nif_is_port_alive,
nif_term_to_binary, nif_binary_to_term,
nif_port_command,
- nif_snprintf].
+ nif_snprintf,
+ nif_phash2,
+ nif_phash2_ranged].
groups() ->
[{G, [], api_repeaters()} || G <- api_groups()]
@@ -2610,6 +2614,81 @@ nif_snprintf(Config) ->
<<"{{hello,world,-33},",0>> = format_term_nif(20,{{hello,world, -33}, 3.14, self()}),
ok.
+nif_phash2(Config) ->
+ ensure_lib_loaded(Config),
+ Terms =
+ [random_term() || _ <- lists:seq(1, 1000)],
+
+ lists:foreach(
+ fun (Term) ->
+ HashValue = erlang:phash2(Term),
+ NifHashValue = phash2_nif(Term),
+ (HashValue =:= NifHashValue
+ orelse ct:fail("Expected: ~p\nActual: ~p",
+ [HashValue, NifHashValue]))
+ end,
+ Terms).
+
+nif_phash2_ranged(Config) ->
+ ensure_lib_loaded(Config),
+ RandomRangedTerms =
+ [{random_term(), rand:uniform((1 bsl 32) - 1)}
+ || _ <- lists:seq(1, 1000)],
+
+ lists:foreach(
+ fun ({Term, Range}) ->
+ HashValue = erlang:phash2(Term, Range),
+ NifHashValue = phash2_ranged_nif(Term, Range),
+ (HashValue =:= NifHashValue
+ orelse ct:fail("Expected: ~p\nActual: ~p",
+ [HashValue, NifHashValue]))
+ end,
+ RandomRangedTerms),
+
+ EdgeCaseTerm = random_term(),
+ EdgeCaseHashValue = erlang:phash2(EdgeCaseTerm, 1 bsl 32),
+ EdgeCaseNifHashValue = phash2_ranged_nif(EdgeCaseTerm, 0),
+ (EdgeCaseHashValue =:= EdgeCaseNifHashValue
+ orelse ct:fail("Expected: ~p\nActual: ~p",
+ [EdgeCaseHashValue, EdgeCaseNifHashValue])).
+
+-define(HALF_DBL_EPSILON, 1.1102230246251565e-16). % math:pow(2, -53)
+
+random_term() ->
+ case rand:uniform(6) of
+ 1 -> rand:uniform(1 bsl 27) - 1; % small
+ 2 -> (1 bsl 27) + rand:uniform(1 bsl 128); % big
+ 3 -> random_sign() * (rand:uniform() * ?HALF_DBL_EPSILON); % float
+ 4 -> random_binary();
+ 5 -> random_pid();
+ 6 ->
+ Length = rand:uniform(10),
+ List = [random_term() || _ <- lists:seq(1, Length)],
+ case rand:uniform(2) of
+ 1 ->
+ List;
+ 2 ->
+ list_to_tuple(List)
+ end
+ end.
+
+random_sign() ->
+ case rand:uniform(2) of
+ 1 -> -1.0;
+ 2 -> 1.0
+ end.
+
+random_binary() ->
+ list_to_binary(random_bytes(rand:uniform(32) - 1)).
+
+random_bytes(0) ->
+ [];
+random_bytes(N) when N > 0 ->
+ [rand:uniform(256) - 1 | random_bytes(N - 1)].
+
+random_pid() ->
+ Processes = erlang:processes(),
+ lists:nth(rand:uniform(length(Processes)), Processes).
%% The NIFs:
lib_version() -> undefined.
@@ -2621,6 +2700,8 @@ type_test() -> ?nif_stub.
tuple_2_list(_) -> ?nif_stub.
is_identical(_,_) -> ?nif_stub.
compare(_,_) -> ?nif_stub.
+phash2_nif(_) -> ?nif_stub.
+phash2_ranged_nif(_, _) -> ?nif_stub.
many_args_100(_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_) -> ?nif_stub.
clone_bin(_) -> ?nif_stub.
make_sub_bin(_,_,_) -> ?nif_stub.
diff --git a/erts/emulator/test/nif_SUITE_data/nif_SUITE.c b/erts/emulator/test/nif_SUITE_data/nif_SUITE.c
index 8fe5ee809a..3bdd4d93c7 100644
--- a/erts/emulator/test/nif_SUITE_data/nif_SUITE.c
+++ b/erts/emulator/test/nif_SUITE_data/nif_SUITE.c
@@ -687,6 +687,23 @@ static ERL_NIF_TERM compare(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
return enif_make_int(env, enif_compare(argv[0],argv[1]));
}
+static ERL_NIF_TERM phash2_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{
+ if (argc != 1) {
+ return enif_make_badarg(env);
+ }
+ return enif_make_ulong(env, enif_phash2(argv[0]));
+}
+
+static ERL_NIF_TERM phash2_ranged_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{
+ unsigned long range;
+ if (argc != 2 || !enif_get_ulong(env, argv[1], &range)) {
+ return enif_make_badarg(env);
+ }
+ return enif_make_ulong(env, enif_phash2_ranged(argv[0], range));
+}
+
static ERL_NIF_TERM many_args_100(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
int i, k;
@@ -2864,6 +2881,8 @@ static ErlNifFunc nif_funcs[] =
{"tuple_2_list", 1, tuple_2_list},
{"is_identical",2,is_identical},
{"compare",2,compare},
+ {"phash2_nif",1,phash2_nif},
+ {"phash2_ranged_nif",2,phash2_ranged_nif},
{"many_args_100", 100, many_args_100},
{"clone_bin", 1, clone_bin},
{"make_sub_bin", 3, make_sub_bin},