View Source Abit.Counter (abit v0.3.3)
Use :atomics
as an array of counters with N bits per counter.
An :atomics
is an array of 64 bit integers so the possible counters are below:
Possible counters:
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..2147483647
If you need 64 bit counters use Erlang counters
The option :wrap_around
is set to false
by default. With these
small-ish counters this is a safe default.
When :wrap_around
is false
using put/3
or add/3
when the value
would be out of bounds the error tuple {:error, :value_out_of_bounds}
will be returned and the stored counter value will not change.
While Erlang :atomics
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()
54321
Examples
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
with incr
.
Returns the value of counter at index
.
Returns all counters from atomics 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
with incr
.
Returns {:ok, {index, final_value}}
or {:error, :value_out_of_bounds}
if
option wrap_around
is false
and 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}
@spec get(t(), non_neg_integer()) :: integer()
Returns the value of 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 from atomics at index.
Index of 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, 0, -70, 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
- minimum number of counters to have, counters will fully fill the:atomics
. Check the:size
key in the returned%Abit.Counter{}
for the exact number of counterscounters_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
option wrap_around
is false
and 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}