File 3746-stdlib-Optimize-fun-usage.patch of Package erlang

From 3346acf491bf33267242f9100bd32da92f090d44 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?John=20H=C3=B6gberg?= <john@erlang.org>
Date: Tue, 19 Oct 2021 20:18:51 +0200
Subject: [PATCH 6/6] stdlib: Optimize fun usage

Hoisting the fun check outside these loops lets us skip error
checks on the fun calls themselves, which is very nice for
functions like foldl/3.
---
 lib/debugger/test/fun_SUITE.erl |   2 +-
 lib/kernel/test/code_SUITE.erl  |  19 +++-
 lib/stdlib/src/gb_sets.erl      |   2 +-
 lib/stdlib/src/lists.erl        | 195 ++++++++++++++++++++++----------
 lib/stdlib/src/sets.erl         |  16 ++-
 5 files changed, 162 insertions(+), 72 deletions(-)

diff --git a/lib/debugger/test/fun_SUITE.erl b/lib/debugger/test/fun_SUITE.erl
index 7eb53e4ce4..962c54f22a 100644
--- a/lib/debugger/test/fun_SUITE.erl
+++ b/lib/debugger/test/fun_SUITE.erl
@@ -289,7 +289,7 @@ eep37(Config) when is_list(Config) ->
     10 = Add(9),
     50 = UnusedName(8),
     [1,1,2,6,24,120] = lists:map(F, lists:seq(0, 5)),
-    {'EXIT',{{badarity,_},_}} = (catch lists:map(fun G() -> G() end, [1])),
+    {'EXIT',{function_clause,_}} = (catch lists:map(fun G() -> G() end, [1])),
     {'EXIT',{{badarity,_},_}} = (catch F()),
 
     ok.
diff --git a/lib/kernel/test/code_SUITE.erl b/lib/kernel/test/code_SUITE.erl
index 740f05ac94..5227346217 100644
--- a/lib/kernel/test/code_SUITE.erl
+++ b/lib/kernel/test/code_SUITE.erl
@@ -869,13 +869,15 @@ check_funs({'$M_EXPR','$F_EXPR',_},
 	   [{code_server,do_mod_call,4},
 	    {code_server,handle_call,3}|_]) -> 0;
 check_funs({'$M_EXPR','$F_EXPR',_},
-	   [{lists,flatmap,2},
+	   [{lists,flatmap_1,2},
+	    {lists,flatmap,2},
 	    {lists,concat,1},
 	    {code_server,load_abs,4},
 	    {code_server,handle_call,3},
 	    {code_server,loop,1}|_]) -> 0;
 check_funs({'$M_EXPR','$F_EXPR',_},
-	   [{lists,foreach,2},
+	   [{lists,foreach_1,2},
+	    {lists,foreach,2},
 	    {code_server,stick_dir,3},
 	    {code_server,handle_call,3},
 	    {code_server,loop,1}|_]) -> 0;
@@ -891,6 +893,19 @@ check_funs({'$M_EXPR','$F_EXPR',1},
 	    {code_server,get_user_lib_dirs,0},
 	    {code_server,init,3},
 	    {code_server,start_link,1}]) -> 0;
+check_funs({'$M_EXPR','$F_EXPR',1},
+	   [{lists,all_1,2},
+	    {lists,all,2},
+	    {code_server,is_numstr,1},
+	    {code_server,is_vsn,1},
+	    {code_server,vsn_to_num,1},
+	    {code_server,create_bundle,2},
+	    {code_server,choose_bundles,1},
+	    {code_server,make_path,2},
+	    {code_server,get_user_lib_dirs_1,1},
+	    {code_server,get_user_lib_dirs,0},
+	    {code_server,init,3},
+	    {code_server,start_link,1}]) -> 0;
 check_funs({'$M_EXPR','$F_EXPR',1},
 	   [{lists,filter,2},
 	    {code_server,try_archive_subdirs,3}|_]) -> 0;
diff --git a/lib/stdlib/src/gb_sets.erl b/lib/stdlib/src/gb_sets.erl
index 6d6f7d40ac..8dda0d4ee0 100644
--- a/lib/stdlib/src/gb_sets.erl
+++ b/lib/stdlib/src/gb_sets.erl
@@ -871,7 +871,7 @@ is_set(_) -> false.
       Set1 :: set(Element),
       Set2 :: set(Element).
 
-filter(F, S) ->
+filter(F, S) when is_function(F, 1) ->
     from_ordset([X || X <- to_list(S), F(X)]).
 
 -spec fold(Function, Acc0, Set) -> Acc1 when
diff --git a/lib/stdlib/src/lists.erl b/lib/stdlib/src/lists.erl
index b82732e0ca..63d55f5630 100644
--- a/lib/stdlib/src/lists.erl
+++ b/lib/stdlib/src/lists.erl
@@ -1231,24 +1231,46 @@ rumerge(T1, [H2 | T2]) ->
       List :: [T],
       T :: term().
 
-all(Pred, [Hd|Tail]) ->
+all(Pred, List) when is_function(Pred, 1) ->
+    case List of
+        [Hd | Tail] ->
+            case Pred(Hd) of
+                true -> all_1(Pred, Tail);
+                false -> false
+            end;
+        [] -> true
+    end.
+
+all_1(Pred, [Hd | Tail]) ->
     case Pred(Hd) of
-	true -> all(Pred, Tail);
-	false -> false
+        true -> all_1(Pred, Tail);
+        false -> false
     end;
-all(Pred, []) when is_function(Pred, 1) -> true. 
+all_1(_Pred, []) ->
+    true.
 
 -spec any(Pred, List) -> boolean() when
       Pred :: fun((Elem :: T) -> boolean()),
       List :: [T],
       T :: term().
 
-any(Pred, [Hd|Tail]) ->
+any(Pred, List) when is_function(Pred, 1) ->
+    case List of
+        [Hd | Tail] ->
+            case Pred(Hd) of
+                true -> true;
+                false -> any_1(Pred, Tail)
+            end;
+        [] -> false
+    end.
+
+any_1(Pred, [Hd | Tail]) ->
     case Pred(Hd) of
-	true -> true;
-	false -> any(Pred, Tail)
+        true -> true;
+        false -> any_1(Pred, Tail)
     end;
-any(Pred, []) when is_function(Pred, 1) -> false. 
+any_1(_Pred, []) ->
+    false.
 
 -spec map(Fun, List1) -> List2 when
       Fun :: fun((A) -> B),
@@ -1257,9 +1279,16 @@ any(Pred, []) when is_function(Pred, 1) -> false.
       A :: term(),
       B :: term().
 
-map(F, [H|T]) ->
-    [F(H)|map(F, T)];
-map(F, []) when is_function(F, 1) -> [].
+map(F, List) when is_function(F, 1) ->
+    case List of
+        [Hd | Tail] -> [F(Hd) | map_1(F, Tail)];
+        [] -> []
+    end.
+
+map_1(F, [Hd | Tail]) ->
+    [F(Hd) | map_1(F, Tail)];
+map_1(_F, []) ->
+    [].
 
 -spec flatmap(Fun, List1) -> List2 when
       Fun :: fun((A) -> [B]),
@@ -1268,9 +1297,13 @@ map(F, []) when is_function(F, 1) -> [].
       A :: term(),
       B :: term().
 
-flatmap(F, [Hd|Tail]) ->
-    F(Hd) ++ flatmap(F, Tail);
-flatmap(F, []) when is_function(F, 1) -> [].
+flatmap(F, List) when is_function(F, 1) ->
+    flatmap_1(F, List).
+
+flatmap_1(F, [Hd | Tail]) ->
+    F(Hd) ++ flatmap_1(F, Tail);
+flatmap_1(_F, []) ->
+    [].
 
 -spec foldl(Fun, Acc0, List) -> Acc1 when
       Fun :: fun((Elem :: T, AccIn) -> AccOut),
@@ -1281,9 +1314,16 @@ flatmap(F, []) when is_function(F, 1) -> [].
       List :: [T],
       T :: term().
 
-foldl(F, Accu, [Hd|Tail]) ->
-    foldl(F, F(Hd, Accu), Tail);
-foldl(F, Accu, []) when is_function(F, 2) -> Accu.
+foldl(F, Accu, List) when is_function(F, 2) ->
+    case List of
+        [Hd | Tail] -> foldl_1(F, F(Hd, Accu), Tail);
+        [] -> Accu
+    end.
+
+foldl_1(F, Accu, [Hd | Tail]) ->
+    foldl_1(F, F(Hd, Accu), Tail);
+foldl_1(_F, Accu, []) ->
+    Accu.
 
 -spec foldr(Fun, Acc0, List) -> Acc1 when
       Fun :: fun((Elem :: T, AccIn) -> AccOut),
@@ -1294,9 +1334,13 @@ foldl(F, Accu, []) when is_function(F, 2) -> Accu.
       List :: [T],
       T :: term().
 
-foldr(F, Accu, [Hd|Tail]) ->
-    F(Hd, foldr(F, Accu, Tail));
-foldr(F, Accu, []) when is_function(F, 2) -> Accu.
+foldr(F, Accu, List) when is_function(F, 2) ->
+    foldr_1(F, Accu, List).
+
+foldr_1(F, Accu, [Hd | Tail]) ->
+    F(Hd, foldr_1(F, Accu, Tail));
+foldr_1(_F, Accu, []) ->
+    Accu.
 
 -spec filter(Pred, List1) -> List2 when
       Pred :: fun((Elem :: T) -> boolean()),
@@ -1317,15 +1361,15 @@ filter(Pred, List) when is_function(Pred, 1) ->
       NotSatisfying :: [T],
       T :: term().
 
-partition(Pred, L) ->
-    partition(Pred, L, [], []).
+partition(Pred, L) when is_function(Pred, 1) ->
+    partition_1(Pred, L, [], []).
 
-partition(Pred, [H | T], As, Bs) ->
+partition_1(Pred, [H | T], As, Bs) ->
     case Pred(H) of
-	true -> partition(Pred, T, [H | As], Bs);
-	false -> partition(Pred, T, As, [H | Bs])
+        true -> partition_1(Pred, T, [H | As], Bs);
+        false -> partition_1(Pred, T, As, [H | Bs])
     end;
-partition(Pred, [], As, Bs) when is_function(Pred, 1) ->
+partition_1(_Pred, [], As, Bs) ->
     {reverse(As), reverse(Bs)}.
 
 -spec filtermap(Fun, List1) -> List2 when
@@ -1335,16 +1379,20 @@ partition(Pred, [], As, Bs) when is_function(Pred, 1) ->
       Elem :: term(),
       Value :: term().
 
-filtermap(F, [Hd|Tail]) ->
+filtermap(F, List) when is_function(F, 1) ->
+    filtermap_1(F, List).
+
+filtermap_1(F, [Hd|Tail]) ->
     case F(Hd) of
-	true ->
-	    [Hd|filtermap(F, Tail)];
-	{true,Val} ->
-	    [Val|filtermap(F, Tail)];
-	false ->
-	    filtermap(F, Tail)
+        true ->
+            [Hd | filtermap_1(F, Tail)];
+        {true,Val} ->
+            [Val | filtermap_1(F, Tail)];
+        false ->
+            filtermap_1(F, Tail)
     end;
-filtermap(F, []) when is_function(F, 1) -> [].
+filtermap_1(_F, []) ->
+    [].
 
 -spec zf(fun((T) -> boolean() | {'true', X}), [T]) -> [(T | X)].
 
@@ -1356,10 +1404,14 @@ zf(F, L) ->
       List :: [T],
       T :: term().
 
-foreach(F, [Hd|Tail]) ->
+foreach(F, List) when is_function(F, 1) ->
+    foreach_1(F, List).
+
+foreach_1(F, [Hd | Tail]) ->
     F(Hd),
-    foreach(F, Tail);
-foreach(F, []) when is_function(F, 1) -> ok.
+    foreach_1(F, Tail);
+foreach_1(_F, []) ->
+    ok.
 
 -spec mapfoldl(Fun, Acc0, List1) -> {List2, Acc1} when
       Fun :: fun((A, AccIn) -> {B, AccOut}),
@@ -1372,11 +1424,15 @@ foreach(F, []) when is_function(F, 1) -> ok.
       A :: term(),
       B :: term().
 
-mapfoldl(F, Accu0, [Hd|Tail]) ->
-    {R,Accu1} = F(Hd, Accu0),
-    {Rs,Accu2} = mapfoldl(F, Accu1, Tail),
-    {[R|Rs],Accu2};
-mapfoldl(F, Accu, []) when is_function(F, 2) -> {[],Accu}.
+mapfoldl(F, Accu, List) when is_function(F, 2) ->
+    mapfoldl_1(F, Accu, List).
+
+mapfoldl_1(F, Accu0, [Hd | Tail]) ->
+    {R, Accu1} = F(Hd, Accu0),
+    {Rs, Accu2} = mapfoldl_1(F, Accu1, Tail),
+    {[R | Rs], Accu2};
+mapfoldl_1(_F, Accu, []) ->
+    {[], Accu}.
 
 -spec mapfoldr(Fun, Acc0, List1) -> {List2, Acc1} when
       Fun :: fun((A, AccIn) -> {B, AccOut}),
@@ -1389,11 +1445,15 @@ mapfoldl(F, Accu, []) when is_function(F, 2) -> {[],Accu}.
       A :: term(),
       B :: term().
 
-mapfoldr(F, Accu0, [Hd|Tail]) ->
-    {Rs,Accu1} = mapfoldr(F, Accu0, Tail),
-    {R,Accu2} = F(Hd, Accu1),
-    {[R|Rs],Accu2};
-mapfoldr(F, Accu, []) when is_function(F, 2) -> {[],Accu}.
+mapfoldr(F, Accu, List) when is_function(F, 2) ->
+    mapfoldr_1(F, Accu, List).
+
+mapfoldr_1(F, Accu0, [Hd|Tail]) ->
+    {Rs, Accu1} = mapfoldr_1(F, Accu0, Tail),
+    {R, Accu2} = F(Hd, Accu1),
+    {[R | Rs], Accu2};
+mapfoldr_1(_F, Accu, []) ->
+    {[], Accu}.
 
 -spec takewhile(Pred, List1) -> List2 when
       Pred :: fun((Elem :: T) -> boolean()),
@@ -1401,12 +1461,16 @@ mapfoldr(F, Accu, []) when is_function(F, 2) -> {[],Accu}.
       List2 :: [T],
       T :: term().
 
-takewhile(Pred, [Hd|Tail]) ->
+takewhile(Pred, List) when is_function(Pred, 1) ->
+    takewhile_1(Pred, List).
+
+takewhile_1(Pred, [Hd | Tail]) ->
     case Pred(Hd) of
-	true -> [Hd|takewhile(Pred, Tail)];
-	false -> []
+        true -> [Hd | takewhile_1(Pred, Tail)];
+        false -> []
     end;
-takewhile(Pred, []) when is_function(Pred, 1) -> [].
+takewhile_1(_Pred, []) ->
+    [].
 
 -spec dropwhile(Pred, List1) -> List2 when
       Pred :: fun((Elem :: T) -> boolean()),
@@ -1414,24 +1478,31 @@ takewhile(Pred, []) when is_function(Pred, 1) -> [].
       List2 :: [T],
       T :: term().
 
-dropwhile(Pred, [Hd|Tail]=Rest) ->
+dropwhile(Pred, List) when is_function(Pred, 1) ->
+    dropwhile_1(Pred, List).
+
+dropwhile_1(Pred, [Hd | Tail]=Rest) ->
     case Pred(Hd) of
-	true -> dropwhile(Pred, Tail);
-	false -> Rest
+        true -> dropwhile_1(Pred, Tail);
+        false -> Rest
     end;
-dropwhile(Pred, []) when is_function(Pred, 1) -> [].
+dropwhile_1(_Pred, []) ->
+    [].
 
 -spec search(Pred, List) -> {value, Value} | false when
       Pred :: fun((T) -> boolean()),
       List :: [T],
       Value :: T.
 
-search(Pred, [Hd|Tail]) ->
+search(Pred, List) when is_function(Pred, 1) ->
+    search_1(Pred, List).
+
+search_1(Pred, [Hd | Tail]) ->
     case Pred(Hd) of
         true -> {value, Hd};
-        false -> search(Pred, Tail)
+        false -> search_1(Pred, Tail)
     end;
-search(Pred, []) when is_function(Pred, 1) ->
+search_1(_Pred, []) ->
     false.
 
 -spec splitwith(Pred, List) -> {List1, List2} when
@@ -1442,14 +1513,14 @@ search(Pred, []) when is_function(Pred, 1) ->
       T :: term().
 
 splitwith(Pred, List) when is_function(Pred, 1) ->
-    splitwith(Pred, List, []).
+    splitwith_1(Pred, List, []).
 
-splitwith(Pred, [Hd|Tail], Taken) ->
+splitwith_1(Pred, [Hd|Tail], Taken) ->
     case Pred(Hd) of
-	true -> splitwith(Pred, Tail, [Hd|Taken]);
+	true -> splitwith_1(Pred, Tail, [Hd|Taken]);
 	false -> {reverse(Taken), [Hd|Tail]}
     end;
-splitwith(Pred, [], Taken) when is_function(Pred, 1) ->
+splitwith_1(_Pred, [], Taken) ->
     {reverse(Taken),[]}.
 
 -spec split(N, List1) -> {List2, List3} when
diff --git a/lib/stdlib/src/sets.erl b/lib/stdlib/src/sets.erl
index 086de0f202..e272b33bf6 100644
--- a/lib/stdlib/src/sets.erl
+++ b/lib/stdlib/src/sets.erl
@@ -266,7 +266,8 @@ is_subset(S1, S2) ->
       Acc1 :: Acc,
       AccIn :: Acc,
       AccOut :: Acc.
-fold(F, Acc, D) -> fold_set(F, Acc, D).
+fold(F, Acc, D) when is_function(F, 2)->
+    fold_set(F, Acc, D).
 
 %% filter(Fun, Set) -> Set.
 %%  Filter Set with Fun.
@@ -274,7 +275,8 @@ fold(F, Acc, D) -> fold_set(F, Acc, D).
       Pred :: fun((Element) -> boolean()),
       Set1 :: set(Element),
       Set2 :: set(Element).
-filter(F, D) -> filter_set(F, D).
+filter(F, D) when is_function(F, 1)->
+    filter_set(F, D).
 
 %% get_slot(Hashdb, Key) -> Slot.
 %%  Get the slot.  First hash on the new range, if we hit a bucket
@@ -299,7 +301,7 @@ get_bucket(T, Slot) -> get_bucket_s(T#set.segs, Slot).
 %%  implemented map and hash using fold but these should be faster.
 %%  We hope!
 
-fold_set(F, Acc, D) when is_function(F, 2) ->
+fold_set(F, Acc, D) ->
     Segs = D#set.segs,
     fold_segs(F, Acc, Segs, tuple_size(Segs)).
 
@@ -316,7 +318,7 @@ fold_bucket(F, Acc, [E|Bkt]) ->
     fold_bucket(F, F(E, Acc), Bkt);
 fold_bucket(_, Acc, []) -> Acc.
 
-filter_set(F, D) when is_function(F, 1) ->
+filter_set(F, D) ->
     Segs0 = tuple_to_list(D#set.segs),
     {Segs1,Fc} = filter_seg_list(F, Segs0, [], 0),
     maybe_contract(D#set{segs = list_to_tuple(Segs1)}, Fc).
-- 
2.31.1

openSUSE Build Service is sponsored by