Increase performance of Inspect.BitString.escape/2
This commit is contained in:
+62
-73
@@ -88,7 +88,7 @@ defimpl Inspect, for: Atom do
|
||||
atom in Macro.binary_ops or atom in Macro.unary_ops ->
|
||||
":" <> binary
|
||||
true ->
|
||||
<<?:, ?", Inspect.BitString.escape(binary, ?")::binary, ?">>
|
||||
IO.iodata_to_binary [?:, ?", Inspect.BitString.escape(binary, ?"), ?"]
|
||||
end
|
||||
end
|
||||
|
||||
@@ -143,7 +143,7 @@ end
|
||||
defimpl Inspect, for: BitString do
|
||||
def inspect(term, %Inspect.Opts{binaries: bins, base: base} = opts) when is_binary(term) do
|
||||
if base == :decimal and (bins == :as_strings or (bins == :infer and String.printable?(term))) do
|
||||
<<?", escape(term, ?")::binary, ?">>
|
||||
IO.iodata_to_binary([?", escape(term, ?"), ?"])
|
||||
else
|
||||
inspect_bitstring(term, opts)
|
||||
end
|
||||
@@ -157,88 +157,82 @@ defimpl Inspect, for: BitString do
|
||||
|
||||
@doc false
|
||||
def escape(other, char) do
|
||||
escape(other, char, <<>>)
|
||||
escape(other, char, [])
|
||||
end
|
||||
|
||||
defp escape(<<char, t::binary>>, char, binary) do
|
||||
escape(t, char, <<binary::binary, ?\\, char>>)
|
||||
defp escape(<<char, t::binary>>, char, acc) do
|
||||
escape(t, char, [char, ?\\ | acc])
|
||||
end
|
||||
defp escape(<<?#, ?{, t::binary>>, char, binary) do
|
||||
escape(t, char, <<binary::binary, ?\\, ?#, ?{>>)
|
||||
defp escape(<<?#, ?{, t::binary>>, char, acc) do
|
||||
escape(t, char, [?{, ?#, ?\\ | acc])
|
||||
end
|
||||
defp escape(<<?\a, t::binary>>, char, binary) do
|
||||
escape(t, char, <<binary::binary, ?\\, ?a>>)
|
||||
defp escape(<<?\a, t::binary>>, char, acc) do
|
||||
escape(t, char, [?a, ?\\ | acc])
|
||||
end
|
||||
defp escape(<<?\b, t::binary>>, char, binary) do
|
||||
escape(t, char, <<binary::binary, ?\\, ?b>>)
|
||||
defp escape(<<?\b, t::binary>>, char, acc) do
|
||||
escape(t, char, [?b, ?\\ | acc])
|
||||
end
|
||||
defp escape(<<?\d, t::binary>>, char, binary) do
|
||||
escape(t, char, <<binary::binary, ?\\, ?d>>)
|
||||
defp escape(<<?\d, t::binary>>, char, acc) do
|
||||
escape(t, char, [?d, ?\\ | acc])
|
||||
end
|
||||
defp escape(<<?\e, t::binary>>, char, binary) do
|
||||
escape(t, char, <<binary::binary, ?\\, ?e>>)
|
||||
defp escape(<<?\e, t::binary>>, char, acc) do
|
||||
escape(t, char, [?e, ?\\ | acc])
|
||||
end
|
||||
defp escape(<<?\f, t::binary>>, char, binary) do
|
||||
escape(t, char, <<binary::binary, ?\\, ?f>>)
|
||||
defp escape(<<?\f, t::binary>>, char, acc) do
|
||||
escape(t, char, [?f, ?\\ | acc])
|
||||
end
|
||||
defp escape(<<?\n, t::binary>>, char, binary) do
|
||||
escape(t, char, <<binary::binary, ?\\, ?n>>)
|
||||
defp escape(<<?\n, t::binary>>, char, acc) do
|
||||
escape(t, char, [?n, ?\\ | acc])
|
||||
end
|
||||
defp escape(<<?\r, t::binary>>, char, binary) do
|
||||
escape(t, char, <<binary::binary, ?\\, ?r>>)
|
||||
defp escape(<<?\r, t::binary>>, char, acc) do
|
||||
escape(t, char, [?r, ?\\ | acc])
|
||||
end
|
||||
defp escape(<<?\\, t::binary>>, char, binary) do
|
||||
escape(t, char, <<binary::binary, ?\\, ?\\>>)
|
||||
defp escape(<<?\\, t::binary>>, char, acc) do
|
||||
escape(t, char, [?\\, ?\\ | acc])
|
||||
end
|
||||
defp escape(<<?\t, t::binary>>, char, binary) do
|
||||
escape(t, char, <<binary::binary, ?\\, ?t>>)
|
||||
defp escape(<<?\t, t::binary>>, char, acc) do
|
||||
escape(t, char, [?t, ?\\ | acc])
|
||||
end
|
||||
defp escape(<<?\v, t::binary>>, char, binary) do
|
||||
escape(t, char, <<binary::binary, ?\\, ?v>>)
|
||||
defp escape(<<?\v, t::binary>>, char, acc) do
|
||||
escape(t, char, [?v, ?\\ | acc])
|
||||
end
|
||||
defp escape(<<h::utf8, t::binary>>, char, binary) do
|
||||
head = <<h::utf8>>
|
||||
if String.printable?(head) do
|
||||
escape(t, char, append(head, binary))
|
||||
else
|
||||
<<byte::8, h::binary>> = head
|
||||
t = <<h::binary, t::binary>>
|
||||
escape(t, char, <<binary::binary, escape_char(byte)::binary>>)
|
||||
end
|
||||
defp escape(<<h::utf8, t::binary>>, char, acc)
|
||||
when h in 0x20..0x7E
|
||||
when h in 0xA0..0xD7FF
|
||||
when h in 0xE000..0xFFFD
|
||||
when h in 0x10000..0x10FFFF do
|
||||
escape(t, char, [<<h::utf8>> | acc])
|
||||
end
|
||||
defp escape(<<h, t::binary>>, char, binary) do
|
||||
escape(t, char, <<binary::binary, escape_char(h)::binary>>)
|
||||
defp escape(<<h, t::binary>>, char, acc) do
|
||||
escape(t, char, [escape_char(h) | acc])
|
||||
end
|
||||
defp escape(<<>>, _char, binary), do: binary
|
||||
defp escape(<<>>, _char, acc), do: :lists.reverse(acc)
|
||||
|
||||
@doc false
|
||||
# Also used by Regex
|
||||
def escape_char(0) do
|
||||
<<?\\, ?0>>
|
||||
[?\\, ?0]
|
||||
end
|
||||
|
||||
def escape_char(char) when char < 0x100 do
|
||||
<<a::4, b::4>> = <<char::8>>
|
||||
<<?\\, ?x, to_hex(a), to_hex(b)>>
|
||||
[?\\, ?x, to_hex(a), to_hex(b)]
|
||||
end
|
||||
|
||||
def escape_char(char) when char < 0x10000 do
|
||||
<<a::4, b::4, c::4, d::4>> = <<char::16>>
|
||||
<<?\\, ?x, ?{, to_hex(a), to_hex(b), to_hex(c), to_hex(d), ?}>>
|
||||
[?\\, ?x, ?{, to_hex(a), to_hex(b), to_hex(c), to_hex(d), ?}]
|
||||
end
|
||||
|
||||
def escape_char(char) when char < 0x1000000 do
|
||||
<<a::4, b::4, c::4, d::4, e::4, f::4>> = <<char::24>>
|
||||
<<?\\, ?x, ?{, to_hex(a), to_hex(b), to_hex(c),
|
||||
to_hex(d), to_hex(e), to_hex(f), ?}>>
|
||||
[?\\, ?x, ?{, to_hex(a), to_hex(b), to_hex(c),
|
||||
to_hex(d), to_hex(e), to_hex(f), ?}]
|
||||
end
|
||||
|
||||
defp to_hex(c) when c in 0..9, do: ?0+c
|
||||
defp to_hex(c) when c in 10..15, do: ?A+c-10
|
||||
|
||||
defp append(<<h, t::binary>>, binary), do: append(t, <<binary::binary, h>>)
|
||||
defp append(<<>>, binary), do: binary
|
||||
|
||||
## Bitstrings
|
||||
|
||||
defp inspect_bitstring("", _opts) do
|
||||
@@ -295,7 +289,7 @@ defimpl Inspect, for: List do
|
||||
|
||||
cond do
|
||||
lists == :as_charlists or (lists == :infer and printable?(term)) ->
|
||||
<<?', Inspect.BitString.escape(IO.chardata_to_string(term), ?')::binary, ?'>>
|
||||
IO.iodata_to_binary [?', Inspect.BitString.escape(IO.chardata_to_string(term), ?'), ?']
|
||||
keyword?(term) ->
|
||||
surround_many("[", term, "]", opts, &keyword/2)
|
||||
true ->
|
||||
@@ -413,55 +407,50 @@ end
|
||||
|
||||
defimpl Inspect, for: Regex do
|
||||
def inspect(regex, _opts) do
|
||||
delim = ?/
|
||||
concat ["~r",
|
||||
<<delim, escape(regex.source, delim)::binary, delim>>,
|
||||
regex.opts]
|
||||
IO.iodata_to_binary ["~r", ?/, escape(regex.source, ?/), ?/, regex.opts]
|
||||
end
|
||||
|
||||
defp escape(bin, term),
|
||||
do: escape(bin, <<>>, term)
|
||||
do: escape(bin, [], term)
|
||||
|
||||
defp escape(<<?\\, term>> <> rest, buf, term),
|
||||
do: escape(rest, buf <> <<?\\, term>>, term)
|
||||
do: escape(rest, [term , ?\\ | buf], term)
|
||||
|
||||
defp escape(<<term>> <> rest, buf, term),
|
||||
do: escape(rest, buf <> <<?\\, term>>, term)
|
||||
do: escape(rest, [term, ?\\ | buf], term)
|
||||
|
||||
# the list of characters is from "String.printable?" impl
|
||||
# The list of characters is from "String.printable?" implementation
|
||||
# minus characters treated specially by regex: \s, \d, \b, \e
|
||||
|
||||
defp escape(<<?\n>> <> rest, buf, term),
|
||||
do: escape(rest, <<buf::binary, ?\\, ?n>>, term)
|
||||
do: escape(rest, [?n, ?\\ | buf], term)
|
||||
|
||||
defp escape(<<?\r>> <> rest, buf, term),
|
||||
do: escape(rest, <<buf::binary, ?\\, ?r>>, term)
|
||||
do: escape(rest, [?r, ?\\ | buf], term)
|
||||
|
||||
defp escape(<<?\t>> <> rest, buf, term),
|
||||
do: escape(rest, <<buf::binary, ?\\, ?t>>, term)
|
||||
do: escape(rest, [?t, ?\\ | buf], term)
|
||||
|
||||
defp escape(<<?\v>> <> rest, buf, term),
|
||||
do: escape(rest, <<buf::binary, ?\\, ?v>>, term)
|
||||
do: escape(rest, [?v, ?\\ | buf], term)
|
||||
|
||||
defp escape(<<?\f>> <> rest, buf, term),
|
||||
do: escape(rest, <<buf::binary, ?\\, ?f>>, term)
|
||||
do: escape(rest, [?f, ?\\ | buf], term)
|
||||
|
||||
defp escape(<<?\a>> <> rest, buf, term),
|
||||
do: escape(rest, <<buf::binary, ?\\, ?a>>, term)
|
||||
do: escape(rest, [?a, ?\\ | buf], term)
|
||||
|
||||
defp escape(<<c::utf8>> <> rest, buf, term) do
|
||||
charstr = <<c::utf8>>
|
||||
if String.printable?(charstr) and not c in [?\d, ?\b, ?\e] do
|
||||
escape(rest, buf <> charstr, term)
|
||||
else
|
||||
escape(rest, buf <> Inspect.BitString.escape_char(c), term)
|
||||
end
|
||||
end
|
||||
defp escape(<<c::utf8, rest::binary>>, buf, term)
|
||||
when c in 0x20..0x7E
|
||||
when c in 0xA0..0xD7FF
|
||||
when c in 0xE000..0xFFFD
|
||||
when c in 0x10000..0x10FFFF,
|
||||
do: escape(rest, [<<c::utf8>> | buf], term)
|
||||
|
||||
defp escape(<<c>> <> rest, buf, term),
|
||||
do: escape(rest, <<buf::binary, Inspect.BitString.escape_char(c)>>, term)
|
||||
defp escape(<<c, rest::binary>>, buf, term),
|
||||
do: escape(rest, [Inspect.BitString.escape_char(c) | buf], term)
|
||||
|
||||
defp escape(<<>>, buf, _), do: buf
|
||||
defp escape(<<>>, buf, _), do: :lists.reverse(buf)
|
||||
end
|
||||
|
||||
defimpl Inspect, for: Function do
|
||||
|
||||
@@ -740,7 +740,7 @@ defmodule Macro do
|
||||
list == [] ->
|
||||
"[]"
|
||||
:io_lib.printable_list(list) ->
|
||||
"'" <> Inspect.BitString.escape(IO.chardata_to_string(list), ?') <> "'"
|
||||
IO.iodata_to_binary [?', Inspect.BitString.escape(IO.chardata_to_string(list), ?'), ?']
|
||||
Inspect.List.keyword?(list) ->
|
||||
"[" <> kw_list_to_string(list, fun) <> "]"
|
||||
true ->
|
||||
|
||||
@@ -69,8 +69,8 @@ defmodule ExUnit.Diff do
|
||||
length1 = String.length(string1)
|
||||
length2 = String.length(string2)
|
||||
if bag_distance(string1, string2) / max(length1, length2) <= 0.6 do
|
||||
string1 = Inspect.BitString.escape(string1, token)
|
||||
string2 = Inspect.BitString.escape(string2, token)
|
||||
string1 = IO.iodata_to_binary Inspect.BitString.escape(string1, token)
|
||||
string2 = IO.iodata_to_binary Inspect.BitString.escape(string2, token)
|
||||
[{:eq, <<token>>}, script_string(string1, string2), {:eq, <<token>>}]
|
||||
end
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user