Packages

Fast bounded deque using two rotating lists.

Current section

Files

Jump to
deque lib deque.ex
Raw

lib/deque.ex

defmodule Deque do
@moduledoc """
A fast deque implementation using 2 rotating lists.
"""
@opaque t :: %__MODULE__{
size: integer,
max_size: integer,
list1: list,
list2: list,
}
@type value :: term
defstruct size: 0, max_size: nil, list1: [], list2: []
@spec new(integer) :: t
def new(max_size \\ 100) do
%Deque{max_size: max_size}
end
@spec append(t, value) :: t
def append(%Deque{size: size, max_size: max_size, list1: [], list2: list2}=deque, value) when size < max_size do
%{deque | size: size + 1, list2: [value|list2]}
end
def append(%Deque{size: size, max_size: max_size, list2: list2}=deque, value) when size < max_size do
%{deque | size: size + 1, list2: [value|list2]}
end
def append(%Deque{list1: [], list2: list2}=deque, value) do
%{deque | list1: Enum.reverse(list2), list2: []} |> append(value)
end
def append(%Deque{list1: [_|list1], list2: list2}=deque, value) do
%{deque | list1: list1, list2: [value|list2]}
end
@spec appendleft(t, value) :: t
def appendleft(%Deque{size: size, max_size: max_size, list1: list1, list2: []}=deque, value) when size < max_size do
%{deque | size: size + 1, list1: [value|list1]}
end
def appendleft(%Deque{size: size, max_size: max_size, list1: list1}=deque, value) when size < max_size do
%{deque | size: size + 1, list1: [value|list1]}
end
def appendleft(%Deque{list1: list1, list2: []}=deque, value) do
%{deque | list1: [], list2: Enum.reverse(list1)} |> appendleft(value)
end
def appendleft(%Deque{list1: list1, list2: [_|list2]}=deque, value) do
%{deque | list1: [value|list1], list2: list2}
end
@spec pop(t) :: {value | nil, t}
def pop(%Deque{list1: [], list2: []}=deque) do
{nil, deque}
end
def pop(%Deque{size: size, list2: [value|list2]}=deque) do
{value, %{deque | size: size - 1, list2: list2}}
end
def pop(%Deque{list1: list1}=deque) do
%{deque | list1: [], list2: Enum.reverse(list1)} |> pop
end
@spec popleft(t) :: {value | nil, t}
def popleft(%Deque{list1: [], list2: []}=deque) do
{nil, deque}
end
def popleft(%Deque{size: size, list1: [value|list1]}=deque) do
{value, %{deque | size: size - 1, list1: list1}}
end
def popleft(%Deque{list2: list2}=deque) do
%{deque | list1: Enum.reverse(list2), list2: []} |> popleft
end
@spec last(t) :: value | nil
def last(%Deque{list1: [], list2: []}), do: nil
def last(%Deque{list2: [value|_]}), do: value
def last(%Deque{list1: list1}=deque) do
%{deque | list1: [], list2: Enum.reverse(list1)} |> last
end
@spec first(t) :: value | nil
def first(%Deque{list1: [], list2: []}), do: nil
def first(%Deque{list1: [value|_]}), do: value
def first(%Deque{list2: list2}=deque) do
%{deque | list1: Enum.reverse(list2), list2: []} |> first
end
@spec clear(t) :: t
def clear(%Deque{max_size: max_size}), do: new(max_size)
defimpl Enumerable do
def reduce(_, {:halt, acc}, _fun) do
{:halted, acc}
end
def reduce(deque, {:suspend, acc}, fun) do
{:suspended, acc, &reduce(deque, &1, fun)}
end
def reduce(%Deque{list1: list1, list2: list2}, {:cont, acc}, fun) do
reduce({list1, list2}, {:cont, acc}, fun)
end
def reduce({[], []}, {:cont, acc}, _fun) do
{:done, acc}
end
def reduce({[h|list1], list2}, {:cont, acc}, fun) do
reduce({list1, list2}, fun.(h, acc), fun)
end
def reduce({[], list2}, {:cont, acc}, fun) do
reduce({Enum.reverse(list2), []}, {:cont, acc}, fun)
end
def member?(%Deque{list1: list1, list2: list2}, element) do
{:ok, element in list1 or element in list2}
end
def count(%Deque{size: size}) do
{:ok, size}
end
end
defimpl Collectable do
def into(original) do
{original, fn
deque, {:cont, value} -> Deque.append(deque, value)
deque, :done -> deque
_, :halt -> :ok
end}
end
end
defimpl Inspect do
import Inspect.Algebra
def inspect(deque, opts) do
concat ["#Deque<", Inspect.List.inspect(Enum.to_list(deque), opts), ">"]
end
end
end