# `Abit.Counter`
[🔗](https://github.com/preciz/abit/blob/v0.4.0/lib/abit/counter.ex#L1)

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](http://erlang.org/doc/man/counters.html)

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

# `t`

```elixir
@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()
}
```

# `add`

```elixir
@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}

# `clear`
*since 0.4.0* 

```elixir
@spec clear(t()) :: t()
```

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

# `get`

```elixir
@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

# `get_all_at_atomic`
*since 0.2.4* 

```elixir
@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, -70, 0, 0, 0, 0]

# `member?`
*since 0.2.4* 

```elixir
@spec 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

# `new`

```elixir
@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 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

# `put`

```elixir
@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}

---

*Consult [api-reference.md](api-reference.md) for complete listing*
