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..2147483647If you need 64 bit counters use Erlang counters
The option :wrap_around is set to false by default. With these
smallish 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()
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 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:sizekey 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}