# `Qex`
[🔗](https://github.com/princemaple/elixir-queue/blob/v0.5.2/lib/qex.ex#L1)

A `:queue` wrapper with improvements in API and addition of Protocol implementations

## Protocols

`Inspect`, `Collectable` and `Enumerable` are implemented

    iex> inspect Qex.new
    "#Qex<[]>"

    iex> Enum.count Qex.new(1..5)
    5

    iex> Enum.empty? Qex.new
    true

    iex> Enum.map Qex.new([1, 2, 3]), &(&1 + 1)
    [2, 3, 4]

    iex> inspect Enum.into(1..5, %Qex{})
    "#Qex<[1, 2, 3, 4, 5]>"

# `t`

```elixir
@opaque t()
```

# `t`

```elixir
@opaque t(type)
```

# `first`

```elixir
@spec first(t()) :: {:value, term()} | :empty
```

Return the first item in the queue in {:value, term} tuple,
return :empty if the queue is empty

    iex> q1 = Qex.new 1..3
    iex> Qex.first(q1)
    {:value, 1}
    iex> q2 = Qex.new []
    iex> Qex.first(q2)
    :empty

# `first!`

```elixir
@spec first!(t()) :: term() | no_return()
```

Return the first item in the queue, raise if it's empty

    iex> q1 = Qex.new 1..3
    iex> Qex.first!(q1)
    1

# `join`

```elixir
@spec join(t(), t()) :: t()
```

Join two queues together

    iex> q1 = Qex.new 1..3
    iex> q2 = Qex.new 4..5
    iex> Enum.to_list Qex.join(q1, q2)
    [1, 2, 3, 4, 5]

# `last`

```elixir
@spec last(t()) :: {:value, term()} | :empty
```

Return the last item in the queue in {:value, term} tuple,
return :empty if the queue is empty

    iex> q1 = Qex.new 1..3
    iex> Qex.last(q1)
    {:value, 3}
    iex> q2 = Qex.new []
    iex> Qex.last(q2)
    :empty

# `last!`

```elixir
@spec last!(t()) :: term() | no_return()
```

Return the last item in the queue, raise if it's empty

    iex> q1 = Qex.new 1..3
    iex> Qex.last!(q1)
    3

# `len`

```elixir
@spec len(t()) :: non_neg_integer()
```

Return the number of elements in the queue.
This operation takes linear time.

    iex> q1 = Qex.new 1..3
    iex> Qex.len(q1)
    3

# `new`

```elixir
@spec new([term()] | Range.t()) :: t()
```

Create a new queue from a range

    iex> inspect Qex.new(1..3)
    "#Qex<[1, 2, 3]>"

Create a new queue from a list

    iex> inspect Qex.new([1, 2, 3])
    "#Qex<[1, 2, 3]>"

# `pop`

```elixir
@spec pop(t()) :: {{:value, term()}, t()} | {:empty, t()}
```

Get and remove an element from the front of the queue

    iex> q = Qex.new([:front, :mid])
    iex> {{:value, item}, _q} = Qex.pop(q)
    iex> item
    :front

    iex> q = Qex.new
    iex> {empty, _q} = Qex.pop(q)
    iex> empty
    :empty

# `pop!`

```elixir
@spec pop!(t()) :: {term(), t()} | no_return()
```

# `pop_back`

```elixir
@spec pop_back(t()) :: {{:value, term()}, t()} | {:empty, t()}
```

Get and remove an element from the back of the queue

    iex> q = Qex.new([:mid, :back])
    iex> {{:value, item}, _q} = Qex.pop_back(q)
    iex> item
    :back

    iex> q = Qex.new
    iex> {empty, _q} = Qex.pop_back(q)
    iex> empty
    :empty

# `pop_back!`

```elixir
@spec pop_back!(t()) :: {term(), t()} | no_return()
```

# `push`

```elixir
@spec push(t(), term()) :: t()
```

Add an element to the back of the queue

    iex> q = Qex.new([:mid])
    iex> Enum.to_list Qex.push(q, :back)
    [:mid, :back]

# `push_front`

```elixir
@spec push_front(t(), term()) :: t()
```

Add an element to the front of the queue

    iex> q = Qex.new([:mid])
    iex> Enum.to_list Qex.push_front(q, :front)
    [:front, :mid]

# `reverse`

```elixir
@spec reverse(t()) :: t()
```

Reverse a queue

    iex> q = Qex.new(1..3)
    iex> Enum.to_list q
    [1, 2, 3]
    iex> Enum.to_list Qex.reverse(q)
    [3, 2, 1]

# `split`

```elixir
@spec split(t(), pos_integer()) :: {t(), t()}
```

Split a queue into two, the front n items are put in the first queue

    iex> q = Qex.new 1..5
    iex> {q1, q2} = Qex.split(q, 3)
    iex> Enum.to_list q1
    [1, 2, 3]
    iex> Enum.to_list q2
    [4, 5]

---

*Consult [api-reference.md](api-reference.md) for complete listing*
