Skip to content

Commit 7181f2d

Browse files
committed
Fix perf regression on file reading, closes #11335
1 parent 29e40b1 commit 7181f2d

File tree

1 file changed

+20
-20
lines changed

1 file changed

+20
-20
lines changed

lib/elixir/lib/io.ex

Lines changed: 20 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -433,7 +433,6 @@ defmodule IO do
433433
Otherwise, `count` is the number of raw bytes to be retrieved.
434434
435435
See `IO.getn/3` for a description of return values.
436-
437436
"""
438437
@spec getn(
439438
device | chardata | String.Chars.t(),
@@ -474,31 +473,32 @@ defmodule IO do
474473
"""
475474
@spec getn(device, chardata | String.Chars.t(), pos_integer | :eof) :: chardata | nodata
476475
def getn(device, prompt, :eof) do
477-
request = {:get_until, :unicode, to_chardata(prompt), __MODULE__, :__eof__, []}
478-
device = map_dev(device)
479-
480-
case :io.request(device, request) do
481-
list when is_list(list) ->
482-
with [_ | _] = opts <- :io.getopts(device),
483-
false <- Keyword.get(opts, :binary, true) do
484-
list
485-
else
486-
_ -> :unicode.characters_to_binary(list)
487-
end
488-
489-
other ->
490-
other
491-
end
476+
getn_eof(map_dev(device), to_chardata(prompt), [])
492477
end
493478

494479
def getn(device, prompt, count) when is_integer(count) and count > 0 do
495480
:io.get_chars(map_dev(device), to_chardata(prompt), count)
496481
end
497482

498-
@doc false
499-
def __eof__([], :eof), do: {:done, :eof, []}
500-
def __eof__(state, :eof), do: {:done, :lists.reverse(state), []}
501-
def __eof__(state, data), do: {:more, :lists.reverse(data, state)}
483+
defp getn_eof(device, prompt, acc) do
484+
case :io.get_line(device, prompt) do
485+
line when is_binary(line) or is_list(line) -> getn_eof(device, '', [line | acc])
486+
:eof -> read_eof(device, :lists.reverse(acc))
487+
other -> other
488+
end
489+
end
490+
491+
defp read_eof(_device, [h | _] = acc) when is_binary(h), do: IO.iodata_to_binary(acc)
492+
defp read_eof(_device, [h | _] = acc) when is_list(h), do: :lists.flatten(acc)
493+
494+
defp read_eof(device, []) do
495+
with [_ | _] = opts <- :io.getopts(device),
496+
false <- Keyword.get(opts, :binary, true) do
497+
''
498+
else
499+
_ -> ""
500+
end
501+
end
502502

503503
@doc ~S"""
504504
Reads a line from the IO `device`.

0 commit comments

Comments
 (0)