%% %% %CopyrightBegin% %% %% Copyright Ericsson AB 2010-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in %% compliance with the License. You should have received a copy of the %% Erlang Public License along with this software. If not, it can be %% retrieved online at http://www.erlang.org/. %% %% Software distributed under the License is distributed on an "AS IS" %% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See %% the License for the specific language governing rights and limitations %% under the License. %% %% %CopyrightEnd% %% %% %% This module provide OTP's dict interface built on top of ets. %% %% Note that while the interface is the same as dict the semantics %% aren't quite. A Dict here is just a table identifier (although %% this fact can't be used if you want dict/ets-based implementations %% to be interchangeable) so changes made to the Dict modify the %% underlying table. For merge/3, the first argument table is modified. %% %% The underlying ets table implementing a dict is deleted when the %% process from which new() was invoked exits and the dict is only %% writable from this process. %% %% The reason for this is to be able to swap dict/ets-based %% implementations: the former is easier to debug, the latter is %% faster for larger tables. It's also just a nice interface even %% when there's no need for swapability. %% -module(diameter_dict). -export([append/3, append_list/3, erase/2, fetch/2, fetch_keys/1, filter/2, find/2, fold/3, from_list/1, is_key/2, map/2, merge/3, new/0, store/3, to_list/1, update/3, update/4, update_counter/3]). %%% ---------------------------------------------------------- %%% EXPORTED INTERNAL FUNCTIONS %%% ---------------------------------------------------------- append(Key, Value, Dict) -> append_list(Key, [Value], Dict). append_list(Key, ValueList, Dict) when is_list(ValueList) -> update(Key, fun(V) -> V ++ ValueList end, ValueList, Dict). erase(Key, Dict) -> ets:delete(Dict, Key), Dict. fetch(Key, Dict) -> {ok, V} = find(Key, Dict), V. fetch_keys(Dict) -> ets:foldl(fun({K,_}, Acc) -> [K | Acc] end, [], Dict). filter(Pred, Dict) -> lists:foreach(fun({K,V}) -> filter(Pred(K,V), K, Dict) end, to_list(Dict)), Dict. find(Key, Dict) -> case ets:lookup(Dict, Key) of [{Key, V}] -> {ok, V}; [] -> error end. fold(Fun, Acc0, Dict) -> ets:foldl(fun({K,V}, Acc) -> Fun(K, V, Acc) end, Acc0, Dict). from_list(List) -> lists:foldl(fun store/2, new(), List). is_key(Key, Dict) -> ets:member(Dict, Key). map(Fun, Dict) -> lists:foreach(fun({K,V}) -> store(K, Fun(K,V), Dict) end, to_list(Dict)), Dict. merge(Fun, Dict1, Dict2) -> fold(fun(K2,V2,_) -> update(K2, fun(V1) -> Fun(K2, V1, V2) end, V2, Dict1) end, Dict1, Dict2). new() -> ets:new(?MODULE, [set]). store(Key, Value, Dict) -> store({Key, Value}, Dict). to_list(Dict) -> ets:tab2list(Dict). update(Key, Fun, Dict) -> store(Key, Fun(fetch(Key, Dict)), Dict). update(Key, Fun, Initial, Dict) -> store(Key, map(Key, Fun, Dict, Initial), Dict). update_counter(Key, Increment, Dict) when is_integer(Increment) -> update(Key, fun(V) -> V + Increment end, Increment, Dict). %%% --------------------------------------------------------- %%% INTERNAL FUNCTIONS %%% --------------------------------------------------------- store({_,_} = T, Dict) -> ets:insert(Dict, T), Dict. filter(true, _, _) -> ok; filter(false, K, Dict) -> erase(K, Dict). map(Key, Fun, Dict, Error) -> case find(Key, Dict) of {ok, V} -> Fun(V); error -> Error end.