Skip to content

Commit

Permalink
Rearrange unpacking clauses to optimize towards typical usage scenarios
Browse files Browse the repository at this point in the history
This should give around 20% speedup.
  • Loading branch information
lexmag committed Jan 3, 2021
1 parent 89ee44f commit a4bafb7
Show file tree
Hide file tree
Showing 2 changed files with 63 additions and 56 deletions.
115 changes: 61 additions & 54 deletions lib/msgpax/unpacker.ex
Original file line number Diff line number Diff line change
Expand Up @@ -47,34 +47,83 @@ defmodule Msgpax.Unpacker do
unpack(buffer, [], Map.new(options), [], 0, 1)
end

primitives = %{
defunpack = fn clauses ->
for {formats, value} <- clauses, format <- formats do
defp unpack(<<unquote(format), rest::bits>>, result, options, outer, index, count) do
unpack_continue(rest, [unquote(value) | result], options, outer, index, count)
end
end
end

defunpack.(%{
[quote(do: <<0xC0>>)] => nil,
[quote(do: <<0xC2>>)] => false,
[quote(do: <<0xC3>>)] => true,
# Strings
[
# Strings
quote(do: <<0b101::3, length::5, value::size(length)-bytes>>),
quote(do: <<0xD9, length::8, value::size(length)-bytes>>),
quote(do: <<0xDA, length::16, value::size(length)-bytes>>),
quote(do: <<0xDB, length::32, value::size(length)-bytes>>),

# Floats
quote(do: <<0xCA, value::32-float>>),
quote(do: <<0xCB, value::64-float>>),

# Integers
quote(do: <<0::1, value::7>>),
quote(do: <<0xCC, value::8>>),
quote(do: <<0xCD, value::16>>),
quote(do: <<0xD0, value::8-signed>>),
quote(do: <<0xD1, value::16-signed>>)
] => quote(do: value),
# Negative fixint
[quote(do: <<0b111::3, value::5>>)] => quote(do: value - 0b100000)
})

maps = [
quote(do: <<0b1000::4, length::4>>),
quote(do: <<0xDE, length::16>>),
quote(do: <<0xDF, length::32>>)
]

for format <- maps do
defp unpack(<<unquote(format), rest::bits>>, result, options, outer, index, count) do
case var!(length, __MODULE__) do
0 ->
unpack_continue(rest, [%{} | result], options, outer, index, count)

length ->
unpack(rest, result, options, [:map, index, count | outer], 0, length * 2)
end
end
end

lists = [
quote(do: <<0b1001::4, length::4>>),
quote(do: <<0xDC, length::16>>),
quote(do: <<0xDD, length::32>>)
]

for format <- lists do
defp unpack(<<unquote(format), rest::bits>>, result, options, outer, index, count) do
case var!(length, __MODULE__) do
0 ->
unpack_continue(rest, [[] | result], options, outer, index, count)

length ->
unpack(rest, result, options, [:list, index, count | outer], 0, length)
end
end
end

defunpack.(%{
[
# Strings
quote(do: <<0xDA, length::16, value::size(length)-bytes>>),
quote(do: <<0xDB, length::32, value::size(length)-bytes>>),
# Integers
quote(do: <<0xCE, value::32>>),
quote(do: <<0xCF, value::64>>),
quote(do: <<0xD0, value::8-signed>>),
quote(do: <<0xD1, value::16-signed>>),
quote(do: <<0xD2, value::32-signed>>),
quote(do: <<0xD3, value::64-signed>>)
] => quote(do: value),
# Negative fixint
[quote(do: <<0b111::3, value::5>>)] => quote(do: value - 0b100000),
# Extensions
[
quote(do: <<0xD4, type, content::1-bytes>>),
Expand All @@ -92,6 +141,7 @@ defmodule Msgpax.Unpacker do
quote(do: <<0xC5, length::16, content::size(length)-bytes>>),
quote(do: <<0xC6, length::32, content::size(length)-bytes>>)
] => quote(do: unpack_binary(content, var!(options))),
# NaN and ±infinity
[
quote(do: <<0xCA, 0::1, 0xFF, 0::23>>),
quote(do: <<0xCB, 0::1, 0xFF, 0b111::3, 0::52>>)
Expand All @@ -104,50 +154,7 @@ defmodule Msgpax.Unpacker do
quote(do: <<0xCA, _sign::1, 0xFF, _fraction::23>>),
quote(do: <<0xCB, _sign::1, 0xFF, 0b111::3, _fraction::52>>)
] => quote(do: unpack_float(NaN, var!(options)))
}

for {formats, value} <- primitives,
format <- formats do
defp unpack(<<unquote(format), rest::bits>>, result, options, outer, index, count) do
unpack_continue(rest, [unquote(value) | result], options, outer, index, count)
end
end

lists = [
quote(do: <<0b1001::4, length::4>>),
quote(do: <<0xDC, length::16>>),
quote(do: <<0xDD, length::32>>)
]

for format <- lists do
defp unpack(<<unquote(format), rest::bits>>, result, options, outer, index, count) do
case var!(length, __MODULE__) do
0 ->
unpack_continue(rest, [[] | result], options, outer, index, count)

length ->
unpack(rest, result, options, [:list, index, count | outer], 0, length)
end
end
end

maps = [
quote(do: <<0b1000::4, length::4>>),
quote(do: <<0xDE, length::16>>),
quote(do: <<0xDF, length::32>>)
]

for format <- maps do
defp unpack(<<unquote(format), rest::bits>>, result, options, outer, index, count) do
case var!(length, __MODULE__) do
0 ->
unpack_continue(rest, [%{} | result], options, outer, index, count)

length ->
unpack(rest, result, options, [:map, index, count | outer], 0, length * 2)
end
end
end
})

defp unpack(<<byte, _::bits>>, _result, _options, _outer, _index, _count) do
throw({:invalid_format, byte})
Expand Down
4 changes: 2 additions & 2 deletions test/msgpax_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -108,11 +108,11 @@ defmodule MsgpaxTest do
assert_format 42.1, <<203>>

for {packed, value} <- %{
# 32-bit.
# 32-bit
<<202, 0x7FC00000::32>> => Msgpax.NaN,
<<202, 0x7F800000::32>> => Msgpax.Infinity,
<<202, 0xFF800000::32>> => Msgpax.NegInfinity,
# 64-bit.
# 64-bit
<<203, 0x7FF8::16, 0::48>> => Msgpax.NaN,
<<203, 0x7FF0::16, 0::48>> => Msgpax.Infinity,
<<203, 0xFFF0::16, 0::48>> => Msgpax.NegInfinity
Expand Down

0 comments on commit a4bafb7

Please sign in to comment.