# `Talan.Counter`
[🔗](https://github.com/preciz/talan/blob/v0.2.1/lib/talan/counter.ex#L1)

Linear probabilistic counter implementation with **concurrent accessibility**,
powered by [:atomics](http://erlang.org/doc/man/atomics.html) module for cardinality estimation.

Cardinality is the count of unique elements.

For more information about linear probabilistic counting:
[linear probabilistic counting](https://www.waitingforcode.com/big-data-algorithms/cardinality-estimation-linear-probabilistic-counting/read)

# `t`

```elixir
@type t() :: %Talan.Counter{
  atomics_ref: reference(),
  filter_length: non_neg_integer(),
  hash_function: function()
}
```

# `cardinality`

```elixir
@spec cardinality(t()) :: non_neg_integer()
```

Returns the estimated cardinality for the given
`%Talan.Counter{}` struct.

## Examples

    iex> c = Talan.Counter.new(10_000)
    iex> c |> Talan.Counter.put(["you", :can, Hash, {"any", "elixir", "term"}])
    iex> c |> Talan.Counter.put(["you", :can, Hash, {"any", "elixir", "term"}])
    iex> c |> Talan.Counter.cardinality()
    1
    iex> c |> Talan.Counter.put("more")
    iex> c |> Talan.Counter.cardinality()
    2

# `new`

```elixir
@spec new(non_neg_integer(), list()) :: t()
```

Returns a new `%Talan.Counter{}` struct.

`expected_cardinality` is the max number of uniq items the counter will
handle with approx 1% of error rate.

## Options
  * `hash_function` - defaults to `Murmur.hash_x64_128/1`

## Examples

    iex> c = Talan.Counter.new(10_000)
    iex> c |> Talan.Counter.put(["you", :can, Hash, {"any", "elixir", "term"}])
    iex> c |> Talan.Counter.put("more")
    iex> c |> Talan.Counter.put("another")
    iex> c |> Talan.Counter.cardinality()
    3

# `put`

```elixir
@spec put(t(), any()) :: :ok
```

Hashes `term` and sets a bit to mark it has been seen.

Doesn't store the `term` so it's space efficient.
Uses `:atomics` so it's mutable & highly concurrent.

Returns `:ok`.

## Examples

    iex> c = Talan.Counter.new(10_000)
    iex> c |> Talan.Counter.put(["you", :can, Hash, {"any", "elixir", "term"}])
    :ok

---

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