diff --git a/lib/hpax/table.ex b/lib/hpax/table.ex index e5bc92b..1299955 100644 --- a/lib/hpax/table.ex +++ b/lib/hpax/table.ex @@ -89,6 +89,7 @@ defmodule HPAX.Table do ] @static_table_size length(@static_table) + @static_table_by_index @static_table |> Enum.map(&{:ok, &1}) |> List.to_tuple() @dynamic_table_start @static_table_size + 1 @doc """ @@ -155,24 +156,23 @@ defmodule HPAX.Table do @spec lookup_by_index(t(), pos_integer()) :: {:ok, {binary(), binary()}} | :error def lookup_by_index(table, index) - # Static table - for {header, index} <- Enum.with_index(@static_table, 1) do - def lookup_by_index(%__MODULE__{}, unquote(index)), do: {:ok, unquote(header)} - end - - def lookup_by_index(%__MODULE__{length: 0}, _index) do - :error + def lookup_by_index(%__MODULE__{}, index) when index in 1..@static_table_size do + elem(@static_table_by_index, index - 1) end def lookup_by_index(%__MODULE__{entries: entries, length: length}, index) when index >= @dynamic_table_start and index <= @dynamic_table_start + length - 1 do - {:ok, Enum.at(entries, index - @dynamic_table_start)} + {:ok, get_dynamic_entry(entries, index - @dynamic_table_start)} end def lookup_by_index(%__MODULE__{}, _index) do :error end + @compile {:inline, get_dynamic_entry: 2} + defp get_dynamic_entry([entry | _], 0), do: entry + defp get_dynamic_entry([_ | rest], n), do: get_dynamic_entry(rest, n - 1) + @doc """ Looks up the index of a header by its name and value. diff --git a/test/hpax/table_test.exs b/test/hpax/table_test.exs index 83673a3..7d6ea6a 100644 --- a/test/hpax/table_test.exs +++ b/test/hpax/table_test.exs @@ -53,15 +53,28 @@ defmodule HPAX.TableTest do end test "with an index in the static table" do - assert Table.lookup_by_index(Table.new(100, :never), 1) == {:ok, {":authority", ""}} + table = Table.new(100, :never) + + for {header, index} <- Enum.with_index(Table.__static_table__(), 1) do + assert Table.lookup_by_index(table, index) == {:ok, header} + end end - test "with an index in the dynamic table" do - table = Table.new(100, :never) - table = Table.add(table, "my-header", "my-value") + test "with shallow and deep indices in the dynamic table" do + dynamic_table_start = length(Table.__static_table__()) + 1 + + table = + Enum.reduce(1..64, Table.new(10_000, :never), fn index, table -> + Table.add(table, "header-#{index}", "value-#{index}") + end) + + assert Table.lookup_by_index(table, dynamic_table_start) == + {:ok, {"header-64", "value-64"}} + + assert Table.lookup_by_index(table, dynamic_table_start + 63) == + {:ok, {"header-1", "value-1"}} - assert Table.lookup_by_index(table, length(Table.__static_table__()) + 1) == - {:ok, {"my-header", "my-value"}} + assert Table.lookup_by_index(table, dynamic_table_start + 64) == :error end end