typecode
ElixirGenServer/cache.ex
1defmodule Cache do
2 use GenServer
3
4 defstruct entries: %{}, max_size: 100
5
6 def start_link(opts \\ []) do
7 max_size = Keyword.get(opts, :max_size, 100)
8 GenServer.start_link(__MODULE__, max_size, name: __MODULE__)
9 end
10
11 def get(key), do: GenServer.call(__MODULE__, {:get, key})
12 def put(key, value), do: GenServer.cast(__MODULE__, {:put, key, value})
13 def delete(key), do: GenServer.cast(__MODULE__, {:delete, key})
14 def stats, do: GenServer.call(__MODULE__, :stats)
15
16 @impl true
17 def init(max_size) do
18 {:ok, %__MODULE__{max_size: max_size}}
19 end
20
21 @impl true
22 def handle_call({:get, key}, _from, state) do
23 result = Map.get(state.entries, key)
24 {:reply, result, state}
25 end
26
27 def handle_call(:stats, _from, state) do
28 stats =
29 state.entries
30 |> Map.values()
31 |> Enum.reduce(%{types: %{}, count: 0}, fn val, acc ->
32 type = val |> inspect() |> String.split("(") |> hd()
33 types = Map.update(acc.types, type, 1, &(&1 + 1))
34 %{acc | types: types, count: acc.count + 1}
35 end)
36
37 {:reply, stats, state}
38 end
39
40 @impl true
41 def handle_cast({:put, key, value}, state) do
42 entries =
43 if map_size(state.entries) >= state.max_size do
44 state.entries
45 |> Map.keys()
46 |> hd()
47 |> then(&Map.delete(state.entries, &1))
48 else
49 state.entries
50 end
51
52 {:noreply, %{state | entries: Map.put(entries, key, value)}}
53 end
54
55 def handle_cast({:delete, key}, state) do
56 {:noreply, %{state | entries: Map.delete(state.entries, key)}}
57 end
58
59 def transform_all(func) do
60 GenServer.call(__MODULE__, {:transform, func})
61 end
62
63 @impl true
64 def handle_call({:transform, func}, _from, state) do
65 new_entries =
66 state.entries
67 |> Enum.map(fn {k, v} -> {k, func.(v)} end)
68 |> Map.new()
69
70 {:reply, :ok, %{state | entries: new_entries}}
71 end
72end
0WPM
100%Accuracy
00:00Time
0%
Progress