rebar3/_build/default/lib/erlware_commons/src/ec_dictionary.erl

177 lines
5.9 KiB
Erlang

%%% vi:ts=4 sw=4 et
%%%-------------------------------------------------------------------
%%% @author Eric Merritt <ericbmerritt@gmail.com>
%%% @copyright 2011 Erlware, LLC.
%%% @doc
%%% A module that supports association of keys to values. A map cannot
%%% contain duplicate keys; each key can map to at most one value.
%%%
%%% This interface is a member of the Erlware Commons Library.
%%% @end
%%%-------------------------------------------------------------------
-module(ec_dictionary).
%% API
-export([new/1,
has_key/2,
get/2,
get/3,
add/3,
remove/2,
has_value/2,
size/1,
to_list/1,
from_list/2,
keys/1]).
-export_type([dictionary/2,
key/1,
value/1]).
%%%===================================================================
%%% Types
%%%===================================================================
-record(dict_t,
{callback,
data}).
%% This should be opaque, but that kills dialyzer so for now we export it
%% however you should not rely on the internal representation here
-type dictionary(_K, _V) :: #dict_t{}.
-type key(T) :: T.
-type value(T) :: T.
-ifdef(have_callback_support).
-callback new() -> any().
-callback has_key(key(any()), any()) -> boolean().
-callback get(key(any()), any()) -> any().
-callback add(key(any()), value(any()), T) -> T.
-callback remove(key(any()), T) -> T.
-callback has_value(value(any()), any()) -> boolean().
-callback size(any()) -> non_neg_integer().
-callback to_list(any()) -> [{key(any()), value(any())}].
-callback from_list([{key(any()), value(any())}]) -> any().
-callback keys(any()) -> [key(any())].
-else.
%% In the case where R14 or lower is being used to compile the system
%% we need to export a behaviour info
-export([behaviour_info/1]).
-spec behaviour_info(atom()) -> [{atom(), arity()}] | undefined.
behaviour_info(callbacks) ->
[{new, 0},
{has_key, 2},
{get, 2},
{add, 3},
{remove, 2},
{has_value, 2},
{size, 1},
{to_list, 1},
{from_list, 1},
{keys, 1}];
behaviour_info(_Other) ->
undefined.
-endif.
%%%===================================================================
%%% API
%%%===================================================================
%% @doc create a new dictionary object from the specified module. The
%% module should implement the dictionary behaviour.
%%
%% @param ModuleName The module name.
-spec new(module()) -> dictionary(_K, _V).
new(ModuleName) when is_atom(ModuleName) ->
#dict_t{callback = ModuleName, data = ModuleName:new()}.
%% @doc check to see if the dictionary provided has the specified key.
%%
%% @param Dict The dictory object to check
%% @param Key The key to check the dictionary for
-spec has_key(key(K), dictionary(K, _V)) -> boolean().
has_key(Key, #dict_t{callback = Mod, data = Data}) ->
Mod:has_key(Key, Data).
%% @doc given a key return that key from the dictionary. If the key is
%% not found throw a 'not_found' exception.
%%
%% @param Dict The dictionary object to return the value from
%% @param Key The key requested
%% when the key does not exist @throws not_found
-spec get(key(K), dictionary(K, V)) -> value(V).
get(Key, #dict_t{callback = Mod, data = Data}) ->
Mod:get(Key, Data).
%% @doc given a key return that key from the dictionary. If the key is
%% not found then the default value is returned.
%%
%% @param Dict The dictionary object to return the value from
%% @param Key The key requested
%% @param Default The value that will be returned if no value is found
%% in the database.
-spec get(key(K), value(V), dictionary(K, V)) -> value(V).
get(Key, Default, #dict_t{callback = Mod, data = Data}) ->
Mod:get(Key, Default, Data).
%% @doc add a new value to the existing dictionary. Return a new
%% dictionary containing the value.
%%
%% @param Dict the dictionary object to add too
%% @param Key the key to add
%% @param Value the value to add
-spec add(key(K), value(V), dictionary(K, V)) -> dictionary(K, V).
add(Key, Value, #dict_t{callback = Mod, data = Data} = Dict) ->
Dict#dict_t{data = Mod:add(Key, Value, Data)}.
%% @doc Remove a value from the dictionary returning a new dictionary
%% with the value removed.
%%
%% @param Dict the dictionary object to remove the value from
%% @param Key the key of the key/value pair to remove
-spec remove(key(K), dictionary(K, V)) -> dictionary(K, V).
remove(Key, #dict_t{callback = Mod, data = Data} = Dict) ->
Dict#dict_t{data = Mod:remove(Key, Data)}.
%% @doc Check to see if the value exists in the dictionary
%%
%% @param Dict the dictionary object to check
%% @param Value The value to check if exists
-spec has_value(value(V), dictionary(_K, V)) -> boolean().
has_value(Value, #dict_t{callback = Mod, data = Data}) ->
Mod:has_value(Value, Data).
%% @doc return the current number of key value pairs in the dictionary
%%
%% @param Dict the object return the size for.
-spec size(dictionary(_K, _V)) -> integer().
size(#dict_t{callback = Mod, data = Data}) ->
Mod:size(Data).
%% @doc Return the contents of this dictionary as a list of key value
%% pairs.
%%
%% @param Dict the base dictionary to make use of.
-spec to_list(Dict::dictionary(K, V)) -> [{key(K), value(V)}].
to_list(#dict_t{callback = Mod, data = Data}) ->
Mod:to_list(Data).
%% @doc Create a new dictionary, of the specified implementation using
%% the list provided as the starting contents.
%%
%% @param ModuleName the type to create the dictionary from
%% @param List The list of key value pairs to start with
-spec from_list(module(), [{key(K), value(V)}]) -> dictionary(K, V).
from_list(ModuleName, List) when is_list(List) ->
#dict_t{callback = ModuleName, data = ModuleName:from_list(List)}.
%% @doc Return the keys of this dictionary as a list
%%
%% @param Dict the base dictionary to make use of.
-spec keys(Dict::dictionary(K, _V)) -> [key(K)].
keys(#dict_t{callback = Mod, data = Data}) ->
Mod:keys(Data).