Skip to content

Commit

Permalink
Compile enums into case statements
Browse files Browse the repository at this point in the history
Elixir is slow to compile functions with many heads, which is how we generate
enums in this library. It's faster to compile an equivalent case statement
inside a single function head. I observed that it reduced the time to compile
an enum with about 2500 values from 24s to 3s.
  • Loading branch information
pguillory committed Oct 19, 2020
1 parent d6bfeea commit 9668f00
Show file tree
Hide file tree
Showing 2 changed files with 84 additions and 48 deletions.
68 changes: 36 additions & 32 deletions example/lib/calculator/generated/vector_product_type.ex

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

64 changes: 48 additions & 16 deletions lib/thrift/generator/enum_generator.ex
Original file line number Diff line number Diff line change
Expand Up @@ -20,36 +20,36 @@ defmodule Thrift.Generator.EnumGenerator do
end)

member_defs =
Enum.map(enum.values, fn {_key, value} ->
Enum.flat_map(enum.values, fn {_key, value} ->
quote do
def member?(unquote(value)), do: true
unquote(value) -> true
end
end)

name_member_defs =
Enum.map(enum.values, fn {key, _value} ->
Enum.flat_map(enum.values, fn {key, _value} ->
enum_name = to_name(key)

quote do
def name?(unquote(enum_name)), do: true
unquote(enum_name) -> true
end
end)

value_to_name_defs =
Enum.map(enum.values, fn {key, value} ->
Enum.flat_map(enum.values, fn {key, value} ->
enum_name = to_name(key)

quote do
def value_to_name(unquote(value)), do: {:ok, unquote(enum_name)}
unquote(value) -> {:ok, unquote(enum_name)}
end
end)

name_to_value_defs =
Enum.map(enum.values, fn {key, value} ->
Enum.flat_map(enum.values, fn {key, value} ->
enum_name = to_name(key)

quote do
def name_to_value(unquote(enum_name)), do: {:ok, unquote(value)}
unquote(enum_name) -> {:ok, unquote(value)}
end
end)

Expand All @@ -63,11 +63,27 @@ defmodule Thrift.Generator.EnumGenerator do
@moduledoc false
unquote_splicing(macro_defs)

unquote_splicing(value_to_name_defs)
def value_to_name(v), do: {:error, {:invalid_enum_value, v}}
def value_to_name(v) do
case v do
unquote(
value_to_name_defs ++
quote do
_ -> {:error, {:invalid_enum_value, v}}
end
)
end
end

unquote_splicing(name_to_value_defs)
def name_to_value(k), do: {:error, {:invalid_enum_name, k}}
def name_to_value(k) do
case k do
unquote(
name_to_value_defs ++
quote do
_ -> {:error, {:invalid_enum_name, k}}
end
)
end
end

def value_to_name!(value) do
{:ok, name} = value_to_name(value)
Expand All @@ -82,11 +98,27 @@ defmodule Thrift.Generator.EnumGenerator do
def meta(:names), do: unquote(names)
def meta(:values), do: unquote(Keyword.values(enum.values))

unquote_splicing(member_defs)
def member?(_), do: false
def member?(v) do
case v do
unquote(
member_defs ++
quote do
_ -> false
end
)
end
end

unquote_splicing(name_member_defs)
def name?(_), do: false
def name?(k) do
case k do
unquote(
name_member_defs ++
quote do
_ -> false
end
)
end
end
end
end
end
Expand Down

0 comments on commit 9668f00

Please sign in to comment.