-module(counter). -export([new/0, incr/2, tracker/0, counter/0, count/2, counting/1, counts/1]). %- Called from outside ------------------- new() -> Table = ets:new(tracker, [set, public]), Tracker = spawn(fun counter:tracker/0), Tracker ! { table, Table }, { Tracker, Table }. incr(Whatever, { Tracker, Table }) -> Counter = find_counter(Whatever, Tracker, Table), Counter ! { incr }. count(Whatever, { _, Tracking }) -> Lookup = ets:lookup(Tracking, Whatever), find_count(Lookup). counting({ _, Tracking }) -> Table = ets:tab2list(Tracking), lists:map(fun({ K, _ }) -> K end, Table). counts({ _, Tracking} ) -> Table = ets:tab2list(Tracking), lists:map(fun({ K, _ }) -> { K, counter:count(K, { 0, Tracking }) } end, Table). %- Internal ------------------------------ find_count([]) -> 0; find_count([{ _, Counter }]) -> Counter ! { report, self() }, receive { count, Count } -> Count end. find_counter(Whatever, Tracker, Table) -> case ets:lookup(Table, Whatever) of [ { _, Counter } ] -> Counter; [] -> Counter = spawn(fun counter:counter/0), Tracker ! { pid, Whatever, Counter }, Counter end. %- The Pid-tracker process --------------- tracker() -> tracker_loop([], 0). tracker_loop(Tracking, Table) -> receive { table, T } -> tracker_loop(Tracking, T); { pid, Whatever, Pid } -> ets:insert(Table, { Whatever, Pid }), tracker_loop([Pid | Tracking], Table); { report, To } -> To ! Tracking, tracker_loop(Tracking, Table) end. %- The counter process ------------------- counter() -> counter_loop(0). counter_loop(Count) -> receive { incr } -> counter_loop(Count + 1); { report, To } -> To ! { count, Count }, counter_loop(Count) end.