Uses :atomics as an array of counters with N bits per counter.
An :atomics reference stores an array of 64-bit integers.
Supported counter widths and value ranges:
bits | unsigned value range | signed value range
2 | 0..3 | -2..1
4 | 0..15 | -8..7
8 | 0..255 | -128..127
16 | 0..65535 | -32768..32767
32 | 0..4294967295 | -2147483648..2147483647If you need 64-bit counters, use Erlang counters.
The :wrap_around option defaults to false, which is a safe default for
these small counters. When :wrap_around is false and an operation would
produce an out-of-bounds value, put/3 and add/3 return
{:error, :value_out_of_bounds} without changing the stored value.
While Erlang :atomics elements are 1-indexed, Abit.Counter counters are
0-indexed.
Enumerable protocol
Abit.Counter implements the Enumerable protocol, so all Enum functions can be used:
iex> c = Abit.Counter.new(1000, 16, signed: false)
iex> c |> Abit.Counter.put(700, 54321)
iex> c |> Enum.max()
54321Examples
iex> c = Abit.Counter.new(1000, 8, signed: false)
iex> c |> Abit.Counter.put(0, 100)
{:ok, {0, 100}}
iex> c |> Abit.Counter.add(0, 100)
{:ok, {0, 200}}
iex> c |> Abit.Counter.add(0, 100)
{:error, :value_out_of_bounds}
Summary
Functions
Increments the value of the counter at index by incr.
Sets all elements in the given counter array to 0.
Returns the value of the counter at index.
Returns all counters packed into the atomics element at index.
Returns true if any counter has the value integer,
false otherwise.
Returns a new %Abit.Counter{} struct.
Puts the value into the counter at index.
Types
@type t() :: %Abit.Counter{ atomics_ref: reference(), counters_bit_size: 2 | 4 | 8 | 16 | 32, max: pos_integer(), min: integer(), signed: boolean(), size: pos_integer(), wrap_around: boolean() }
Functions
@spec add(t(), non_neg_integer(), integer()) :: {:ok, {non_neg_integer(), integer()}} | {:error, :value_out_of_bounds}
Increments the value of the counter at index by incr.
Returns {:ok, {index, final_value}}, or {:error, :value_out_of_bounds} if
wrap_around is false and the value is out of bounds.
Examples
iex> c = Abit.Counter.new(10, 8)
iex> c |> Abit.Counter.add(7, -12)
{:ok, {7, -12}}
iex> c |> Abit.Counter.add(7, 36)
{:ok, {7, 24}}
iex> c |> Abit.Counter.put(1, 1000)
{:error, :value_out_of_bounds}
Sets all elements in the given counter array to 0.
Returns counter.
Examples
iex> c = Abit.Counter.new(100, 8)
iex> c |> Abit.Counter.put(3, 70)
iex> c |> Abit.Counter.clear()
iex> c |> Abit.Counter.get(3)
0
@spec get(t(), non_neg_integer()) :: integer()
Returns the value of the counter at index.
Examples
iex> c = Abit.Counter.new(10, 8)
iex> c |> Abit.Counter.get(7)
0
@spec get_all_at_atomic(t(), pos_integer()) :: [integer()]
Returns all counters packed into the atomics element at index.
Indices in :atomics are one-based.
Examples
iex> c = Abit.Counter.new(100, 8)
iex> c |> Abit.Counter.put(3, -70)
iex> c |> Abit.Counter.get_all_at_atomic(1)
[0, 0, 0, -70, 0, 0, 0, 0]
Returns true if any counter has the value integer,
false otherwise.
Examples
iex> c = Abit.Counter.new(100, 8)
iex> c |> Abit.Counter.member?(0)
true
iex> c |> Abit.Counter.member?(80)
false
@spec new(non_neg_integer(), 2 | 4 | 8 | 16 | 32, keyword()) :: t()
Returns a new %Abit.Counter{} struct.
size- the minimum number of counters. Counters fully fill the:atomicsarray, so check the:sizekey in the returned%Abit.Counter{}for the exact count.counters_bit_size- how many bits a counter should use
Options
:signed- whether to have signed or unsigned counters. Defaults totrue.:wrap_around- whether counters should wrap around. Defaults tofalse.
Examples
Abit.Counter.new(100, 8) # minimum 100 counters; 8 bits signed
Abit.Counter.new(10_000, 16, signed: false) # minimum 10_000 counters; 16 bits unsigned
Abit.Counter.new(10_000, 16, wrap_around: false) # don't wrap around
@spec put(t(), non_neg_integer(), integer()) :: {:ok, {non_neg_integer(), integer()}} | {:error, :value_out_of_bounds}
Puts the value into the counter at index.
Returns {:ok, {index, final_value}}, or {:error, :value_out_of_bounds} if
wrap_around is false and the value is out of bounds.
Examples
iex> c = Abit.Counter.new(10, 8)
iex> c |> Abit.Counter.put(7, -12)
{:ok, {7, -12}}
iex> c |> Abit.Counter.get(7)
-12
iex> c |> Abit.Counter.put(7, 128)
{:error, :value_out_of_bounds}