Skip to content

Commit 83cb515

Browse files
author
José Valim
committed
Optimize reduce for maps
Signed-off-by: José Valim <[email protected]>
1 parent 3c10057 commit 83cb515

File tree

2 files changed

+14
-33
lines changed

2 files changed

+14
-33
lines changed

lib/elixir/lib/enum.ex

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1261,6 +1261,15 @@ defmodule Enum do
12611261
:lists.foldl(fun, acc, collection)
12621262
end
12631263

1264+
def reduce(%{__struct__: _} = collection, acc, fun) do
1265+
Enumerable.reduce(collection, {:cont, acc},
1266+
fn x, acc -> {:cont, fun.(x, acc)} end) |> elem(1)
1267+
end
1268+
1269+
def reduce(%{} = collection, acc, fun) do
1270+
:maps.fold(fn k, v, acc -> fun.({k, v}, acc) end, acc, collection)
1271+
end
1272+
12641273
def reduce(collection, acc, fun) do
12651274
Enumerable.reduce(collection, {:cont, acc},
12661275
fn x, acc -> {:cont, fun.(x, acc)} end) |> elem(1)

lib/elixir/src/elixir_for.erl

Lines changed: 5 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -126,29 +126,6 @@ collect_filters([H|T], Acc) ->
126126
collect_filters([], Acc) ->
127127
{Acc, []}.
128128

129-
%% If all we have is one enum generator, we check if it is a list
130-
%% for optimization otherwise fallback to the reduce generator.
131-
build_inline(Line, [{enum, Meta, Left, Right, Filters}] = Orig, Expr, Into, Var, Acc, S) ->
132-
case Right of
133-
{cons, _, _, _} ->
134-
build_comprehension(Line, Orig, Expr, Into);
135-
{Other, _, _} when Other == tuple; Other == map ->
136-
build_reduce(Orig, Expr, Into, Acc, S);
137-
_ ->
138-
Clauses = [{enum, Meta, Left, Var, Filters}],
139-
140-
{'case', -1, Right, [
141-
{clause, -1,
142-
[Var],
143-
[[elixir_utils:erl_call(Line, erlang, is_list, [Var])]],
144-
[build_comprehension(Line, Clauses, Expr, Into)]},
145-
{clause, -1,
146-
[Var],
147-
[],
148-
[build_reduce(Clauses, Expr, Into, Acc, S)]}
149-
]}
150-
end;
151-
152129
build_inline(Line, Clauses, Expr, Into, _Var, Acc, S) ->
153130
case lists:all(fun(Clause) -> element(1, Clause) == bin end, Clauses) of
154131
true -> build_comprehension(Line, Clauses, Expr, Into);
@@ -165,7 +142,7 @@ build_into(Line, Clauses, Expr, Into, Fun, Acc, S) ->
165142
MatchExpr = {match, Line,
166143
{tuple, Line, [Acc, Fun]},
167144
elixir_utils:erl_call(Line, 'Elixir.Collectable', into, [Into])
168-
},
145+
},
169146

170147
TryExpr =
171148
{'try', Line,
@@ -199,10 +176,8 @@ build_reduce(Clauses, Expr, {bin, _, _} = Into, Acc, S) ->
199176

200177
build_reduce_clause([{enum, Meta, Left, Right, Filters}|T], Expr, Arg, Acc, S) ->
201178
Line = ?line(Meta),
202-
Inner = build_reduce_clause(T, Expr, Acc, Acc, S),
203-
204-
True = pair(Line, cont, Inner),
205-
False = pair(Line, cont, Acc),
179+
True = build_reduce_clause(T, Expr, Acc, Acc, S),
180+
False = Acc,
206181

207182
Clauses0 =
208183
case is_var(Left) of
@@ -218,11 +193,8 @@ build_reduce_clause([{enum, Meta, Left, Right, Filters}|T], Expr, Arg, Acc, S) -
218193
[Left, Acc], [],
219194
[join_filters(Line, Filters, True, False)]}|Clauses0],
220195

221-
Args = [Right, pair(Line, cont, Arg), {'fun', Line, {clauses, Clauses1}}],
222-
Tuple = elixir_utils:erl_call(Line, 'Elixir.Enumerable', reduce, Args),
223-
224-
%% Use -1 because in case of no returns we don't care about the result
225-
elixir_utils:erl_call(-1, erlang, element, [{integer, Line, 2}, Tuple]);
196+
Args = [Right, Arg, {'fun', Line, {clauses, Clauses1}}],
197+
elixir_utils:erl_call(Line, 'Elixir.Enum', reduce, Args);
226198

227199
build_reduce_clause([{bin, Meta, Left, Right, Filters}|T], Expr, Arg, Acc, S) ->
228200
Line = ?line(Meta),

0 commit comments

Comments
 (0)