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]
Summary
Functions
The item at index, counting 0 as the oldest, or nil when out of range.
How many items the buffer currently holds, never more than max_size/1.
Whether the buffer holds no items.
The most recently pushed item, or nil when the buffer is empty.
The newest n items, oldest first, or all of them when the buffer holds fewer.
An empty buffer holding at most max_size items.
Append item, dropping the oldest item once the buffer is full.
Append every item in items, in order.
A buffer with capacity new_max, keeping the newest items that still fit.
length items starting at offset, oldest first.
Every item, oldest first.
Types
@type t() :: %Drafter.RingBuffer{ count: non_neg_integer(), max_size: pos_integer(), store: %{required(non_neg_integer()) => term()}, write_pos: non_neg_integer() }
Functions
@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
@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
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
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
@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)
[]
@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
@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
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]
@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]
@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]
@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)
[]
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]