From 0beaad30f1785225361dd57b1ef130565ae2b049 Mon Sep 17 00:00:00 2001 From: preciz Date: Thu, 1 Oct 2026 16:39:34 +0200 Subject: [PATCH] Avoid UTF-8 re-encoding in StringIO line reads Carry the original input byte size while scanning and derive the consumed size from the remaining suffix. Assisted-by: Codex:GPT-6 --- lib/elixir/lib/string_io.ex | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/lib/elixir/lib/string_io.ex b/lib/elixir/lib/string_io.ex index 1cfb83f4ab..7b2c88e2c2 100644 --- a/lib/elixir/lib/string_io.ex +++ b/lib/elixir/lib/string_io.ex @@ -365,7 +365,7 @@ defmodule StringIO do ## get_line defp get_line(encoding, prompt, %{input: input} = state) do - case bytes_until_eol(input, encoding, 0) do + case bytes_until_eol(input, encoding, byte_size(input)) do {:split, 0} -> {:eof, state_after_read(state, "", prompt, 1)} @@ -413,7 +413,7 @@ defmodule StringIO do end defp get_until(chars, encoding, mod, fun, args, continuation, count) do - case bytes_until_eol(chars, encoding, 0) do + case bytes_until_eol(chars, encoding, byte_size(chars)) do {kind, size} when kind in [:split, :replace_split] -> <> = chars @@ -466,16 +466,20 @@ defmodule StringIO do %{state | input: remainder, output: output} end - defp bytes_until_eol("", _, count), do: {:split, count} - defp bytes_until_eol(<<"\r\n"::binary, _::binary>>, _, count), do: {:replace_split, count + 2} - defp bytes_until_eol(<<"\n"::binary, _::binary>>, _, count), do: {:split, count + 1} + defp bytes_until_eol("", _, size), do: {:split, size} - defp bytes_until_eol(<>, :unicode, count) do - bytes_until_eol(tail, :unicode, count + byte_size(<>)) + defp bytes_until_eol(<<"\r\n"::binary, rest::binary>>, _, size), + do: {:replace_split, size - byte_size(rest)} + + defp bytes_until_eol(<<"\n"::binary, rest::binary>>, _, size), + do: {:split, size - byte_size(rest)} + + defp bytes_until_eol(<<_::utf8, rest::binary>>, :unicode, size) do + bytes_until_eol(rest, :unicode, size) end - defp bytes_until_eol(<<_, tail::binary>>, :latin1, count) do - bytes_until_eol(tail, :latin1, count + 1) + defp bytes_until_eol(<<_, rest::binary>>, :latin1, size) do + bytes_until_eol(rest, :latin1, size) end defp bytes_until_eol(<<_::binary>>, _, _), do: :error