File 2202-Add-proplists-to_map-2-including-normalization.patch of Package erlang

From 0dc222a1cdbff5386212f262a7d1117cabb28f71 Mon Sep 17 00:00:00 2001
From: Maria-12648430 <maria-12648430@gmx.net>
Date: Wed, 16 Dec 2020 17:47:58 +0100
Subject: [PATCH 2/2] Add proplists:to_map/2 including normalization

---
 lib/stdlib/doc/src/proplists.xml    |  12 +++
 lib/stdlib/src/proplists.erl        |  44 ++++++++---
 lib/stdlib/test/proplists_SUITE.erl | 112 +++++++++++++++++++---------
 3 files changed, 123 insertions(+), 45 deletions(-)

diff --git a/lib/stdlib/doc/src/proplists.xml b/lib/stdlib/doc/src/proplists.xml
index 05c02cc3be..6aed2d45e1 100644
--- a/lib/stdlib/doc/src/proplists.xml
+++ b/lib/stdlib/doc/src/proplists.xml
@@ -396,6 +396,18 @@ to_map([a, {b, 1}, {c, 2}, {c, 3}])</code>
       </desc>
     </func>
 
+    <func>
+      <name name="to_map" arity="2" since=""/>
+      <fsummary></fsummary>
+      <desc>
+        <p>Converts the property list <c><anno>List</anno></c> to a map after
+          applying the normalizations given in <c><anno>Stages</anno></c>.</p>
+        <p>See also
+          <seemfa marker="#normalize/2"><c>normalize/2</c></seemfa>,
+          <seemfa marker="#to_map/1"><c>to_map/1</c></seemfa>.</p>
+      </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 b92982dae0..8f25229cdd 100644
--- a/lib/stdlib/src/proplists.erl
+++ b/lib/stdlib/src/proplists.erl
@@ -35,7 +35,8 @@
 	 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, from_map/1, to_map/1]).
+	 expand/2, normalize/2, split/2, from_map/1, to_map/1,
+	 to_map/2]).
 
 %% ---------------------------------------------------------------------
 
@@ -607,14 +608,17 @@ flatten([]) ->
       Expansions :: [{Property :: property(), Expansion :: [term()]}],
       ListOut :: [term()].
 
-normalize(L, [{aliases, As} | Xs]) ->
-    normalize(substitute_aliases(As, L), Xs);
-normalize(L, [{expand, Es} | Xs]) ->
-    normalize(expand(Es, L), Xs);
-normalize(L, [{negations, Ns} | Xs]) ->
-    normalize(substitute_negations(Ns, L), Xs);
-normalize(L, []) ->
-    compact(L).
+normalize(L, Stages) ->
+    compact(apply_stages(L, Stages)).
+
+apply_stages(L, [{aliases, As} | Xs]) ->
+    apply_stages(substitute_aliases(As, L), Xs);
+apply_stages(L, [{expand, Es} | Xs]) ->
+    apply_stages(expand(Es, L), Xs);
+apply_stages(L, [{negations, Ns} | Xs]) ->
+    apply_stages(substitute_negations(Ns, L), Xs);
+apply_stages(L, []) ->
+    L.
 
 %% ---------------------------------------------------------------------
 
@@ -702,6 +706,8 @@ to_map(List) ->
         fun
             ({K, V}, M) ->
                 M#{K => V};
+            %% if tuples with arity /= 2 appear before atoms or
+            %% tuples with arity == 2, get_value/2,3 returns early
             (T, M) when 1 =< tuple_size(T) ->
                 maps:remove(element(1, T), M);
             (K, M) when is_atom(K) ->
@@ -713,6 +719,26 @@ to_map(List) ->
         List
     ).
 
+%% @doc Converts the property list <code>List</code> to a map
+%% after applying the normalizations given in <code>Stages</code>.
+%%
+%% @see normalize/2
+%% @see to_map/1
+
+-spec to_map(List, Stages) -> Map when
+      List :: [term()],
+      Stages :: [Operation],
+      Operation :: {'aliases', Aliases}
+                 | {'negations', Negations}
+                 | {'expand', Expansions},
+      Aliases :: [{Key, Key}],
+      Negations :: [{Key, Key}],
+      Expansions :: [{Property :: property(), Expansion :: [term()]}],
+      Map :: #{term() => term()}.
+
+to_map(List, Stages) ->
+    to_map(apply_stages(List, Stages)).
+
 %% @doc Converts the map <code>Map</code> to a property list.
 
 -spec from_map(Map) -> List when
diff --git a/lib/stdlib/test/proplists_SUITE.erl b/lib/stdlib/test/proplists_SUITE.erl
index 64c5e60125..d0ebd2423e 100644
--- a/lib/stdlib/test/proplists_SUITE.erl
+++ b/lib/stdlib/test/proplists_SUITE.erl
@@ -23,7 +23,8 @@
 -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, map_conversion/1]).
+         examples/1, map_conversion/1, map_conversion_normalize/1,
+         pm_fold_test/1]).
 
 init_per_testcase(_Case, Config) ->
     Config.
@@ -36,7 +37,7 @@ suite() ->
      {timetrap,{minutes,5}}].
 
 all() ->
-    [examples, map_conversion].
+    [examples, map_conversion, map_conversion_normalize, pm_fold_test].
 
 groups() ->
     [].
@@ -103,39 +104,78 @@ map_conversion(_Config) ->
     %% 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
-            )
+    Default = make_ref(),
+    InList=[a, b, {a, 1}, {}, {a}, {a, 1, 2}, {c, 1, 2}, "foo"],
+    Fun = fun (L1, Acc) ->
+        LKs = proplists:get_keys(L1),
+        M = proplists:to_map(L1),
+        L2 = proplists:from_map(M),
+        true = lists:sort(maps:keys(M)) =:= lists:sort(proplists:get_keys(L2)),
+        lists:foreach(
+            fun (K) ->
+                case
+                    {
+                        maps:get(K, M, Default),
+                        proplists:get_value(K, L1, Default),
+                        proplists:get_value(K, L2, Default)
+                    }
+                of
+                    {Default, Default, Default} -> ok;
+                    {V, V, V} -> ok
+                end
+            end,
+            LKs
+        ),
+        Acc
+    end,
+    _ = pm_fold(Fun, undefined, InList),
+    ok.
+
+map_conversion_normalize(_Config) ->
+    Stages = [
+        {aliases, [{a, alias_a}]},
+        {negations, [{no_b, b}]},
+        {expand, [{c, [d]}]}
+    ],
+
+    M1 = proplists:to_map([], Stages),
+    true = M1 =:= #{},
+    true = M1 =:= proplists:to_map(proplists:normalize([], Stages)),
+
+    List = [a, no_b, c],
+    M2 = proplists:to_map(List, Stages),
+    true = M2 =:= #{alias_a => true, b => false, d => true},
+    true = M2 =:= proplists:to_map(proplists:normalize(List, Stages)),
+
+    ok.
+
+pm_fold(_, _, []) ->
+    [];
+pm_fold(Fun, Acc0, L) ->
+    pm_fold(Fun, Acc0, L, []).
+
+pm_fold(Fun, Acc, [], Mut) ->
+    Fun(Mut, Acc);
+pm_fold(Fun, Acc, L, Mut) ->
+    lists:foldl(
+        fun
+            (X, AccIn) -> pm_fold(Fun, AccIn, lists:delete(X, L), [X|Mut])
         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]]
-    ),
+        Acc,
+        L
+    ).
+
+pm_fold_test(_Config) ->
+    Fun = fun (M, A) -> [M|A] end,
+
+    [] = pm_fold(Fun, [], []),
+
+    [[1]] = lists:sort(pm_fold(Fun, [], [1])),
+
+    Exp1 = lists:sort([[1, 2], [2, 1]]),
+    Exp1 = lists:sort(pm_fold(Fun, [], [1, 2])),
+
+    Exp2 = lists:sort([[1, 2, 3], [1, 3, 2], [2, 1, 3], [2, 3, 1], [3, 1, 2], [3, 2, 1]]),
+    Exp2 = lists:sort(pm_fold(Fun, [], [1, 2, 3])),
+
     ok.
-- 
2.26.2

openSUSE Build Service is sponsored by