abit v0.3.1 Abit.Counter View Source

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}

Link to this section 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.

Link to this section Types

Link to this type

t()

View Source
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()
}

Link to this section Functions

Link to this function

add(counter, index, incr)

View Source
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}

Returns the value of counter at index.

Examples

iex> c = Abit.Counter.new(10, 8)
iex> c |> Abit.Counter.get(7)
0
Link to this function

get_all_at_atomic(counter, atomic_index)

View Source (since 0.2.4)
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]
Link to this function

member?(counter, int)

View Source (since 0.2.4)
member?(t(), integer()) :: boolean()

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
Link to this function

new(size, counters_bit_size, options \\ [])

View Source
new(non_neg_integer(), 2 | 4 | 8 | 16 | 32, list()) :: 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 counters
  • counters_bit_size - how many bits a counter should use

Options

  • :signed - whether to have signed or unsigned counters. Defaults to true.
  • :wrap_around - whether counters should wrap around. Defaults to false.

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
Link to this function

put(counter, index, value)

View Source
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}