defmodule TakeANumberDeluxe.Queue do # You don't need to read this module to solve this exercise. # We would have used Erlang's queue module instead # (https://www.erlang.org/doc/man/queue.html), # but it lacks a `delete` function before OTP 24, # and we want this exercise to work on older versions too. defstruct in: [], out: [] @type t :: %__MODULE__{} @spec new() :: t() def new(), do: %__MODULE__{} @spec push(t(), any()) :: t() def push(%__MODULE__{in: in_q} = q, a), do: %__MODULE__{q | in: [a | in_q]} @spec out(t()) :: {{:value, any()}, t()} | {:empty, t()} def out(%__MODULE__{in: [], out: []} = q), do: {:empty, q} def out(%__MODULE__{out: [head | tail]} = q), do: {{:value, head}, %__MODULE__{q | out: tail}} def out(%__MODULE__{in: in_q}), do: out(%__MODULE__{out: Enum.reverse(in_q)}) @spec empty?(t()) :: boolean() def empty?(%__MODULE__{in: [], out: []}), do: true def empty?(%__MODULE__{}), do: false @spec member?(t(), any()) :: boolean() def member?(%__MODULE__{in: in_q, out: out}, a), do: a in in_q or a in out @spec delete(t(), any()) :: t() def delete(%__MODULE__{in: in_q, out: out}, a) do out = out ++ Enum.reverse(in_q) out = List.delete(out, a) %__MODULE__{out: out} end @spec from_list([any()]) :: t() def from_list(list), do: %__MODULE__{out: list} @spec to_list(t()) :: [any()] def to_list(%__MODULE__{in: in_q, out: out}), do: out ++ Enum.reverse(in_q) end