# `Drafter.RingBuffer`
[🔗](https://github.com/jaman/drafter/blob/main/lib/drafter/ring_buffer.ex#L1)

A bounded circular buffer backed by an integer-keyed map.

Push and single-element access are O(1); a slice is O(k) in the length
requested, without materializing the whole buffer. Once the buffer is full,
each push overwrites the oldest entry.

Implements `Enumerable`, in oldest-to-newest order.

## Examples

    iex> buffer = Drafter.RingBuffer.new(3)
    iex> buffer = Drafter.RingBuffer.push_many(buffer, [1, 2, 3, 4])
    iex> Drafter.RingBuffer.to_list(buffer)
    [2, 3, 4]
    iex> Drafter.RingBuffer.count(buffer)
    3
    iex> Drafter.RingBuffer.last(buffer)
    4
    iex> Drafter.RingBuffer.at(buffer, 0)
    2
    iex> Drafter.RingBuffer.last_n(buffer, 2)
    [3, 4]

# `t`

```elixir
@type t() :: %Drafter.RingBuffer{
  count: non_neg_integer(),
  max_size: pos_integer(),
  store: %{required(non_neg_integer()) =&gt; term()},
  write_pos: non_neg_integer()
}
```

# `at`

```elixir
@spec at(t(), non_neg_integer()) :: term() | nil
```

The item at `index`, counting `0` as the oldest, or `nil` when out of range.

## Examples

    iex> buf = Drafter.RingBuffer.push_many(Drafter.RingBuffer.new(3), [1, 2, 3, 4])
    iex> Drafter.RingBuffer.at(buf, 0)
    2
    iex> Drafter.RingBuffer.at(buf, 2)
    4
    iex> Drafter.RingBuffer.at(buf, 3)
    nil

# `count`

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

How many items the buffer currently holds, never more than `max_size/1`.

## Examples

    iex> Drafter.RingBuffer.new(2) |> Drafter.RingBuffer.push_many([1, 2, 3]) |> Drafter.RingBuffer.count()
    2

# `empty?`

```elixir
@spec empty?(t()) :: boolean()
```

Whether the buffer holds no items.

## Examples

    iex> Drafter.RingBuffer.empty?(Drafter.RingBuffer.new(3))
    true

    iex> Drafter.RingBuffer.new(3) |> Drafter.RingBuffer.push(:a) |> Drafter.RingBuffer.empty?()
    false

# `last`

```elixir
@spec last(t()) :: term() | nil
```

The most recently pushed item, or `nil` when the buffer is empty.

## Examples

    iex> Drafter.RingBuffer.new(3) |> Drafter.RingBuffer.push_many([1, 2]) |> Drafter.RingBuffer.last()
    2

    iex> Drafter.RingBuffer.last(Drafter.RingBuffer.new(3))
    nil

# `last_n`

```elixir
@spec last_n(t(), non_neg_integer()) :: [term()]
```

The newest `n` items, oldest first, or all of them when the buffer holds fewer.

## Examples

    iex> buf = Drafter.RingBuffer.push_many(Drafter.RingBuffer.new(5), [1, 2, 3, 4])
    iex> Drafter.RingBuffer.last_n(buf, 2)
    [3, 4]
    iex> Drafter.RingBuffer.last_n(buf, 10)
    [1, 2, 3, 4]
    iex> Drafter.RingBuffer.last_n(buf, 0)
    []

# `max_size`

```elixir
@spec max_size(t()) :: pos_integer()
```

The buffer's capacity, as given to `new/1` or `resize/2`.

## Examples

    iex> Drafter.RingBuffer.new(5) |> Drafter.RingBuffer.max_size()
    5

# `new`

```elixir
@spec new(pos_integer()) :: t()
```

An empty buffer holding at most `max_size` items.

`max_size` must be a positive integer; anything else raises `FunctionClauseError`.

## Examples

    iex> buf = Drafter.RingBuffer.new(3)
    iex> Drafter.RingBuffer.count(buf)
    0
    iex> Drafter.RingBuffer.max_size(buf)
    3

# `push`

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

Append `item`, dropping the oldest item once the buffer is full.

## Examples

    iex> Drafter.RingBuffer.new(2) |> Drafter.RingBuffer.push(:a) |> Drafter.RingBuffer.push(:b) |> Drafter.RingBuffer.push(:c) |> Drafter.RingBuffer.to_list()
    [:b, :c]

# `push_many`

```elixir
@spec push_many(t(), Enumerable.t()) :: t()
```

Append every item in `items`, in order.

Pushing more than `max_size` items keeps only the last `max_size`.

## Examples

    iex> Drafter.RingBuffer.new(3) |> Drafter.RingBuffer.push_many([1, 2, 3, 4]) |> Drafter.RingBuffer.to_list()
    [2, 3, 4]

# `resize`

```elixir
@spec resize(t(), pos_integer()) :: t()
```

A buffer with capacity `new_max`, keeping the newest items that still fit.

Shrinking discards the oldest items; growing keeps everything.

## Examples

    iex> buf = Drafter.RingBuffer.push_many(Drafter.RingBuffer.new(5), [1, 2, 3, 4, 5])
    iex> Drafter.RingBuffer.resize(buf, 2) |> Drafter.RingBuffer.to_list()
    [4, 5]

    iex> buf = Drafter.RingBuffer.push_many(Drafter.RingBuffer.new(2), [1, 2])
    iex> Drafter.RingBuffer.resize(buf, 4) |> Drafter.RingBuffer.to_list()
    [1, 2]

# `slice`

```elixir
@spec slice(t(), non_neg_integer(), non_neg_integer()) :: [term()]
```

`length` items starting at `offset`, oldest first.

A slice that runs past the end is truncated rather than padded. `offset` must be
non-negative; a negative one raises `FunctionClauseError`.

## Examples

    iex> buf = Drafter.RingBuffer.push_many(Drafter.RingBuffer.new(5), [1, 2, 3, 4, 5])
    iex> Drafter.RingBuffer.slice(buf, 1, 3)
    [2, 3, 4]
    iex> Drafter.RingBuffer.slice(buf, 3, 10)
    [4, 5]
    iex> Drafter.RingBuffer.slice(buf, 0, 0)
    []

# `to_list`

```elixir
@spec to_list(t()) :: [term()]
```

Every item, oldest first.

## Examples

    iex> Drafter.RingBuffer.new(3) |> Drafter.RingBuffer.push_many([1, 2, 3, 4]) |> Drafter.RingBuffer.to_list()
    [2, 3, 4]

---

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