exercism/elixir/take-a-number-deluxe/lib/take_a_number_deluxe/queue.ex

43 lines
1.4 KiB
Elixir

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