Add genlib_map:search/2 (#36)

* feat: Add genlib_map:search/2

* deps: Update tools deps and fix formatting

* fix: Change return type
This commit is contained in:
Yaroslav Rogov 2021-09-14 11:09:50 +03:00 committed by GitHub
parent 2bbc54d4ab
commit b08ef4d61e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 70 additions and 11 deletions

View File

@ -39,9 +39,9 @@
]}.
{plugins, [
{erlfmt, "0.8.0"},
{rebar3_proper, "0.12.0"},
{rebar3_lint, "0.4.0"}
{erlfmt, "1.0.0"},
{rebar3_proper, "0.12.1"},
{rebar3_lint, "0.5.0"}
]}.
{erlfmt, [

View File

@ -240,10 +240,12 @@ binary_to_hex(V, false) ->
binary_to_hex_(V, A) ->
<<
<<(if
<<
(if
C >= 10 -> C + A - 10;
true -> C + $0
end)>>
end)
>>
|| <<C:4>> <= V
>>.

View File

@ -18,6 +18,7 @@
-export([binarize/2]).
-export([diff/2]).
-export([fold_while/3]).
-export([search/2]).
%%
@ -161,3 +162,17 @@ do_fold_while(Fun, Acc, Iter) ->
{cont, NextAcc} -> do_fold_while(Fun, NextAcc, NextIter)
end
end.
%% @doc Like lists:search, but for maps to reduce memory pressure
%% (comparing to naive implementation with conversion to list)
-spec search(fun((K, V) -> boolean()), #{K => V}) -> false | {K, V}.
search(Fun, Map) when is_function(Fun, 2), is_map(Map) ->
do_search(Fun, maps:next(maps:iterator(Map))).
do_search(_Fun, none) ->
false;
do_search(Fun, {Key, Value, Iter}) ->
case Fun(Key, Value) of
true -> {Key, Value};
false -> do_search(Fun, maps:next(Iter))
end.

View File

@ -6,11 +6,9 @@
prop_fold_while() ->
?FORALL(
Map,
?LET(KVList, non_empty(list({term(), term()})), maps:from_list(KVList)),
non_empty_map(),
begin
RandomId = rand:uniform(map_size(Map)),
{RandomKey, RandomValue} = lists:nth(RandomId, maps:to_list(Map)),
{RandomKey, RandomValue} = random_map_pair(Map),
Result =
genlib_map:fold_while(
fun
@ -24,3 +22,47 @@ prop_fold_while() ->
Result =:= RandomValue
end
).
-spec prop_search_found() -> proper:test().
prop_search_found() ->
?FORALL(
Map,
non_empty_map(),
begin
{RandomKey, RandomValue} = random_map_pair(Map),
Result =
genlib_map:search(
fun(K, _V) -> K =:= RandomKey end,
Map
),
{RandomKey, RandomValue} =:= Result
end
).
-spec prop_search_not_found() -> proper:test().
prop_search_not_found() ->
?FORALL(
Map,
map(),
begin
NonExistentKey = make_ref(),
Result =
genlib_map:search(
fun(K, _V) -> K =:= NonExistentKey end,
Map
),
false =:= Result
end
).
map() ->
?LET(KVList, list({term(), term()}), maps:from_list(KVList)).
non_empty_map() ->
?LET(KVList, non_empty(list({term(), term()})), maps:from_list(KVList)).
random_map_pair(Map) ->
RandomId = rand:uniform(map_size(Map)),
lists:nth(RandomId, maps:to_list(Map)).