File 2201-Add-map-conversion-functions-to-proplists.patch of Package erlang
From 000eef428f7c239b3c4e76b23ea3c578d6bf5219 Mon Sep 17 00:00:00 2001
From: Maria-12648430 <maria-12648430@gmx.net>
Date: Fri, 11 Dec 2020 17:03:56 +0100
Subject: [PATCH 1/2] Add map conversion functions to proplists
---
lib/stdlib/doc/src/proplists.xml | 32 ++++++++++++++
lib/stdlib/src/proplists.erl | 57 ++++++++++++++++++++++++-
lib/stdlib/test/proplists_SUITE.erl | 65 ++++++++++++++++++++++++++++-
3 files changed, 151 insertions(+), 3 deletions(-)
diff --git a/lib/stdlib/doc/src/proplists.xml b/lib/stdlib/doc/src/proplists.xml
index f59b6eda17..05c02cc3be 100644
--- a/lib/stdlib/doc/src/proplists.xml
+++ b/lib/stdlib/doc/src/proplists.xml
@@ -137,6 +137,14 @@ expand([{{foo, true}, [bar, baz]}], [{foo, false}, fie, foo, fum])</code>
</desc>
</func>
+ <func>
+ <name name="from_map" arity="1" since=""/>
+ <fsummary></fsummary>
+ <desc>
+ <p>Converts the map <c><anno>Map</anno></c> to a property list.</p>
+ </desc>
+ </func>
+
<func>
<name name="get_all_values" arity="2" since=""/>
<fsummary></fsummary>
@@ -364,6 +372,30 @@ split([{c, 2}, {e, 1}, a, {c, 3, 4}, d, {b, 5}, b], [a, b, c])</code>
</desc>
</func>
+ <func>
+ <name name="to_map" arity="1" since=""/>
+ <fsummary></fsummary>
+ <desc>
+ <p>Converts the property list <c><anno>List</anno></c> to a map.</p>
+ <p>Shorthand atom values in <c><anno>List</anno></c> will be expanded
+ to an association of the form <c>Atom => true</c>. Tuples of the
+ form <c>{Key, Value}</c> in <c><anno>List</anno></c> will be
+ converted to an association of the form <c>Key => Value</c>.
+ Anything else will be silently ignored.</p>
+ <p>If the same key appears in <c><anno>List</anno></c> multiple
+ times, the value of the one appearing nearest to the head of
+ <c><anno>List</anno></c> will be in the result map, that is
+ the value that would be returned by a call to
+ <c>get_value(Key, List)</c>.</p>
+ <p><em>Example:</em></p>
+ <code type="none">
+to_map([a, {b, 1}, {c, 2}, {c, 3}])</code>
+ <p>returns:</p>
+ <code type="none">
+#{a => true, b => 1, c => 2}</code>
+ </desc>
+ </func>
+
<func>
<name name="unfold" arity="1" since=""/>
<fsummary></fsummary>
diff --git a/lib/stdlib/src/proplists.erl b/lib/stdlib/src/proplists.erl
index 9216c3bdb3..b92982dae0 100644
--- a/lib/stdlib/src/proplists.erl
+++ b/lib/stdlib/src/proplists.erl
@@ -35,7 +35,7 @@
lookup_all/2, is_defined/2, get_value/2, get_value/3,
get_all_values/2, append_values/2, get_bool/2, get_keys/1,
delete/2, substitute_aliases/2, substitute_negations/2,
- expand/2, normalize/2, split/2]).
+ expand/2, normalize/2, split/2, from_map/1, to_map/1]).
%% ---------------------------------------------------------------------
@@ -668,3 +668,58 @@ split([], Store, Rest) ->
maps_prepend(Key, Val, Dict) ->
Dict#{Key := [Val | map_get(Key, Dict)]}.
+
+%% ---------------------------------------------------------------------
+
+%% @doc Converts the property list <code>List</code> to a map.
+%%
+%% Shorthand atom values in <code>List</code> will be expanded to an
+%% association of the form <code>Atom => true</code>. Tuples of the
+%% form <code>{Key, Value}</code> in <code>List</code> will be
+%% converted to an association of the form <code>Key => Value</code>.
+%% Anything else will be silently ignored.
+%%
+%% If the same key appears in <code>List</code> multiple times, the
+%% value of the one appearing nearest to the head of <code>List</code>
+%% will be in the result map, that is the value that would be returned
+%% by a call to <code>get_value/2</code> with this key.
+%%
+%% <p>Example:<pre>
+%% to_map([a, {b, 1}, {c, 2}, {c, 3}])</pre>
+%% returns<pre>
+%% #{a => true, b => 1, c => 2}</pre>
+%% </p>
+
+-spec to_map(List) -> Map when
+ List :: [Shorthand | {Key, Value} | term()],
+ Map :: #{Shorthand => 'true', Key => Value},
+ Shorthand :: atom(),
+ Key :: term(),
+ Value :: term().
+
+to_map(List) ->
+ lists:foldr(
+ fun
+ ({K, V}, M) ->
+ M#{K => V};
+ (T, M) when 1 =< tuple_size(T) ->
+ maps:remove(element(1, T), M);
+ (K, M) when is_atom(K) ->
+ M#{K => true};
+ (_, M) ->
+ M
+ end,
+ #{},
+ List
+ ).
+
+%% @doc Converts the map <code>Map</code> to a property list.
+
+-spec from_map(Map) -> List when
+ Map :: #{Key => Value},
+ List :: [{Key, Value}],
+ Key :: term(),
+ Value :: term().
+
+from_map(Map) ->
+ maps:to_list(Map).
diff --git a/lib/stdlib/test/proplists_SUITE.erl b/lib/stdlib/test/proplists_SUITE.erl
index 600fb8845e..64c5e60125 100644
--- a/lib/stdlib/test/proplists_SUITE.erl
+++ b/lib/stdlib/test/proplists_SUITE.erl
@@ -23,7 +23,7 @@
-export([all/0, suite/0,groups/0, init_per_suite/1, end_per_suite/1,
init_per_group/2, end_per_group/2,
init_per_testcase/2, end_per_testcase/2,
- examples/1]).
+ examples/1, map_conversion/1]).
init_per_testcase(_Case, Config) ->
Config.
@@ -36,7 +36,7 @@ suite() ->
{timetrap,{minutes,5}}].
all() ->
- [examples].
+ [examples, map_conversion].
groups() ->
[].
@@ -77,4 +77,65 @@ examples(_Config) ->
NegListRes = [{foo, false}, {foo, false}, foo, foo, foo],
NegListRes = proplists:substitute_negations([{no_foo, foo}], NegList),
+ true = #{a => true, b => 1, c => 2} =:= proplists:to_map([a, {b, 1}, {c, 2}, {c, 3}]),
+
+ ok.
+
+map_conversion(_Config) ->
+ %% Simple tests.
+ true = #{} =:= proplists:to_map([]),
+ true = #{a => true, b => true} =:= proplists:to_map([a, b]),
+ true = #{a => true, b => true} =:= proplists:to_map([b, a]),
+ true = #{a => 1, b => true} =:= proplists:to_map([{a, 1}, b]),
+ true = #{a => 1, b => true} =:= proplists:to_map([b, {a, 1}]),
+ true = #{a => 1, b => 2} =:= proplists:to_map([{a, 1}, {b, 2}]),
+ true = #{a => 1, b => 2} =:= proplists:to_map([{b, 2}, {a, 1}]),
+ true = #{b => true} =:= proplists:to_map(["a", b]),
+ true = #{b => true} =:= proplists:to_map([b, "a"]),
+ true = #{b => true} =:= proplists:to_map([{a}, b]),
+ true = #{b => true} =:= proplists:to_map([b, {a}]),
+ true = #{b => true} =:= proplists:to_map([{a, 1, 2}, b]),
+ true = #{b => true} =:= proplists:to_map([b, {a, 1, 2}]),
+
+ %% Ensure that maps:get/3 using the created map yields the same
+ %% results as proplists:get_value/3 on the original proplist does,
+ %% and that proplists:get_value/3 on a proplist created from the
+ %% map yields the same results as proplists:get_value/3 on the
+ %% original proplist, ie they either all return the same `Value',
+ %% or they all return the `Default' given as respective third argument.
+ Default1 = make_ref(),
+ Default2 = make_ref(),
+ Default3 = make_ref(),
+ InList=[a, b, {a, 1}, {}, {a}, {a, 1, 2}, "foo"],
+ lists:foreach(
+ fun (L1) ->
+ LKs = proplists:get_keys(L1),
+ M = proplists:to_map(L1),
+ L2 = proplists:from_map(M),
+ [] = maps:keys(M) -- LKs,
+ [] = proplists:get_keys(L2) -- LKs,
+ lists:foreach(
+ fun (K) ->
+ case
+ {
+ maps:get(K, M, Default1),
+ proplists:get_value(K, L1, Default2),
+ proplists:get_value(K, L2, Default3)
+ }
+ of
+ {V, V, V} -> true;
+ {Default1, Default2, Default3} -> true
+ end
+ end,
+ LKs
+ )
+ end,
+ [[A, B, C, D, E, F, G] || A <- InList,
+ B <- InList -- [A],
+ C <- InList -- [A, B],
+ D <- InList -- [A, B, C],
+ E <- InList -- [A, B, C, D],
+ F <- InList -- [A, B, C, D, E],
+ G <- InList -- [A, B, C, D, E, F]]
+ ),
ok.
--
2.26.2