cbuf v0.7.1 Cbuf.ETS

Cbuf.ETS implements the Cbuf behaviour with an ETS table as its implementation.

For examples of typical use, see the documentation for new/1, insert/2, peek/1, and delete/1.

Each new buffer creates and owns a new ETS table.

Operations that must interact with the actual data of the buffer (new/1, insert/2, peek/1, pop/1, delete/1, to_list/1, member?/2), perform as well as ETS does.

Use this module if you have tried Cbuf.Map with a GenServer and benchmarked it against this one to determine that this one is faster for your application. I recommend defaulting to Cbuf.Map. This module is not currently designed or tested for parallel writes, and so I also recommend using it as part of a GenServer. Crucially, the start and current pointers are stored on the struct itself, rather than somewhere in ETS, so they are completely uncoordinated with the backing implementation and require updates to be serialized. This may change at some point if I can determine that this is a beneficial use case and can be implemented in a way that preserves the existing API.

Note that this module is a superset of the Cbuf behaviour, implementing one additional function, destroy/1, to destroy the buffer’s backing ETS table. See the function documentation for more details.

Link to this section Summary

Functions

Returns the count of the non-empty values in the buffer

Return a new buffer with the oldest item in the buffer removed

Destroy the backing ETS table of a buffer. This function exists if you wish to manually dispose of the ETS table that backs the buffer. The other option is to destroy the process in which the buffer was created, as the ETS table will be disposed of when its parent process dies. See http://erlang.org/doc/man/ets.html for more information about the behavior of ETS tables

Whether or not the buffer is empty. This value corresponds to when the buffer has a count of zero, not its size

Insert a value into a circular buffer. Values are inserted such that when the buffer is full, the oldest items are overwritten first

Queries buf for the presence of val

Create a new circular buffer of a given size

See the oldest value in the buffer. Works in constant time

Return the oldest value in the buffer, and a new buffer with that value removed

Calculate the allocated size for the buffer. This is maximum addressable size of the buffer, not how many values it currently contains. For the number of values in the current buffer, see count/1

Convert a circular buffer to a list. The list is ordered by age, oldest to newest. This operation takes linear time

Link to this section Types

Link to this opaque t() (opaque)
t()

Link to this section Functions

Link to this function count(buf)
count(t()) :: non_neg_integer()

Returns the count of the non-empty values in the buffer.

iex> Cbuf.ETS.new(5) |> Cbuf.ETS.insert("hi") |> Cbuf.ETS.count()
1

iex> Cbuf.ETS.new(5) |> Cbuf.ETS.count()
0

iex> Cbuf.ETS.new(5) |> Cbuf.ETS.insert(nil) |> Cbuf.ETS.count()
1

iex> Cbuf.ETS.new(5) |> Cbuf.ETS.insert("hi") |> Cbuf.ETS.delete() |> Cbuf.ETS.count()
0

iex> buf = Enum.reduce(1..13, Cbuf.ETS.new(5), &Cbuf.ETS.insert(&2, &1))
iex> Cbuf.ETS.delete(buf) |> Cbuf.ETS.count()
4

iex> Cbuf.ETS.new(3) |> Cbuf.ETS.delete() |> Cbuf.ETS.delete() |> Cbuf.ETS.count()
0
Link to this function delete(buf)
delete(t()) :: t()

Return a new buffer with the oldest item in the buffer removed.

iex> buf = Enum.reduce(1..20, Cbuf.ETS.new(3), fn(val, acc) -> Cbuf.ETS.insert(acc, val) end)
iex> buf = Cbuf.ETS.delete(buf)
iex> Cbuf.ETS.peek(buf)
19

iex> buf = Enum.reduce(1..6, Cbuf.ETS.new(5), fn(val, acc) -> Cbuf.ETS.insert(acc, val) end)
iex> buf = Cbuf.ETS.delete(buf)
iex> Cbuf.ETS.peek(buf)
3

iex> buf = Enum.reduce(1..6, Cbuf.ETS.new(5), fn(val, acc) -> Cbuf.ETS.insert(acc, val) end)
iex> Cbuf.ETS.delete(buf) |> Cbuf.ETS.count()
4

iex> buf = Cbuf.ETS.new(5)
iex> buf = Cbuf.ETS.insert(buf, "ok")
iex> Cbuf.ETS.delete(buf)
#Cbuf<[]>

iex> buf = Cbuf.ETS.new(5)
iex> Cbuf.ETS.delete(buf)
#Cbuf<[]>
Link to this function destroy(buf)
destroy(t()) :: true

Destroy the backing ETS table of a buffer. This function exists if you wish to manually dispose of the ETS table that backs the buffer. The other option is to destroy the process in which the buffer was created, as the ETS table will be disposed of when its parent process dies. See http://erlang.org/doc/man/ets.html for more information about the behavior of ETS tables.

iex> buf = Cbuf.ETS.new(5)
iex> buf = Cbuf.ETS.insert(buf, "ok")
iex> Cbuf.ETS.destroy(buf)
true

iex> buf = Cbuf.ETS.new(5)
iex> buf = Cbuf.ETS.insert(buf, "ok")
iex> Cbuf.ETS.destroy(buf)
iex> Cbuf.ETS.peek(buf)
** (ArgumentError) argument error
Link to this function empty?(buf)
empty?(t()) :: boolean()

Whether or not the buffer is empty. This value corresponds to when the buffer has a count of zero, not its size.

iex> buf = Cbuf.ETS.new(5)
iex> Cbuf.ETS.empty?(buf)
true

iex> buf = Cbuf.ETS.new(5) |> Cbuf.ETS.insert("hi")
iex> Cbuf.ETS.empty?(buf)
false

iex> buf = Cbuf.ETS.new(5) |> Cbuf.ETS.insert("hi") |> Cbuf.ETS.delete()
iex> Cbuf.ETS.empty?(buf)
true
Link to this function insert(buf, val)
insert(t(), term()) :: t()

Insert a value into a circular buffer. Values are inserted such that when the buffer is full, the oldest items are overwritten first.

iex> buf = Cbuf.ETS.new(5)
iex> buf |> Cbuf.ETS.insert("a") |> Cbuf.ETS.insert("b")
#Cbuf<["a", "b"]>

iex> buf = Cbuf.ETS.new(3)
iex> Enum.reduce(1..20, buf, fn(val, acc) -> Cbuf.ETS.insert(acc, val) end)
#Cbuf<[18, 19, 20]>

iex> buf = Cbuf.ETS.new(1)
iex> Enum.reduce(1..20, buf, fn(val, acc) -> Cbuf.ETS.insert(acc, val) end)
#Cbuf<[20]>
Link to this function member?(buf, val)
member?(t(), term()) :: boolean()

Queries buf for the presence of val.

iex> Cbuf.ETS.new(5) |> Cbuf.ETS.insert("hello") |> Cbuf.ETS.member?("hello")
true

iex> Cbuf.ETS.new(5) |> Cbuf.ETS.insert("hello") |> Cbuf.ETS.member?("nope")
false
Link to this function new(size)
new(pos_integer()) :: t()

Create a new circular buffer of a given size.

iex> Cbuf.ETS.new(5)
#Cbuf<[]>
Link to this function peek(buf)
peek(t()) :: term() | nil

See the oldest value in the buffer. Works in constant time.

iex> buf = Enum.reduce(1..20, Cbuf.ETS.new(3), fn(val, acc) -> Cbuf.ETS.insert(acc, val) end)
iex> Cbuf.ETS.peek(buf)
18

iex> buf = Cbuf.ETS.new(20) |> Cbuf.ETS.insert("ok") |> Cbuf.ETS.insert("fine")
iex> Cbuf.ETS.peek(buf)
"ok"

iex> Cbuf.ETS.new(3) |> Cbuf.ETS.peek()
nil
Link to this function pop(buf)
pop(t()) :: {term() | nil, t()}

Return the oldest value in the buffer, and a new buffer with that value removed.

iex> buf = Enum.reduce(1..20, Cbuf.ETS.new(3), fn(val, acc) -> Cbuf.ETS.insert(acc, val) end)
iex> {val, buf} = Cbuf.ETS.pop(buf)
iex> {val, Cbuf.ETS.to_list(buf)} # Elixir has trouble inspecting a nested struct, see https://hexdocs.pm/ex_unit/ExUnit.DocTest.html#module-opaque-types
{18, [19, 20]}

iex> {val, buf} = Cbuf.ETS.new(1) |> Cbuf.ETS.insert("hi") |> Cbuf.ETS.pop()
iex> {val, Cbuf.ETS.to_list(buf)}
{"hi", []}

Calculate the allocated size for the buffer. This is maximum addressable size of the buffer, not how many values it currently contains. For the number of values in the current buffer, see count/1

iex> Cbuf.ETS.new(5) |> Cbuf.ETS.size()
5
Link to this function to_list(buf)
to_list(t()) :: [term()] | []

Convert a circular buffer to a list. The list is ordered by age, oldest to newest. This operation takes linear time.

iex> buf = Cbuf.ETS.new(5)
iex> buf |> Cbuf.ETS.insert("a") |> Cbuf.ETS.insert("b") |> Cbuf.ETS.to_list()
["a", "b"]

iex> buf = Cbuf.ETS.new(3)
iex> Enum.reduce(1..20, buf, fn(val, acc) -> Cbuf.ETS.insert(acc, val) end) |> Cbuf.ETS.to_list()
[18, 19, 20]

iex> Cbuf.ETS.new(5) |> Cbuf.ETS.to_list()
[]