blob: daaf5ead5ca800c3fe46a0808c830c77767be9c6 [file] [log] [blame]
%% This file is part of khash released under the MIT license.
%% See the LICENSE file for more information.
%% Copyright 2013 Cloudant, Inc <support@cloudant.com>
-module(khash).
-on_load(init/0).
-export([
new/0,
new/1,
from_list/1,
from_list/2,
to_list/1,
clear/1,
lookup/2,
get/2,
get/3,
put/3,
del/2,
size/1,
iter/1,
iter_next/1,
fold/3
]).
-define(NOT_LOADED, not_loaded(?LINE)).
-type kv() :: {any(), any()}.
-type khash() :: term().
-type khash_iter() :: term().
-type option() :: [].
-spec new() -> {ok, khash()}.
new() ->
new([]).
-spec new([option()]) -> {ok, khash()}.
new(_Options) ->
?NOT_LOADED.
-spec from_list([kv()]) -> {ok, khash()}.
from_list(KVList) ->
from_list(KVList, []).
-spec from_list([kv()], [option()]) -> {ok, khash()}.
from_list(KVList, Options) ->
{ok, Hash} = ?MODULE:new(Options),
lists:foreach(fun({Key, Val}) ->
?MODULE:put(Hash, Key, Val)
end, KVList),
{ok, Hash}.
-spec to_list(khash()) -> [kv()].
to_list(_Hash) ->
?NOT_LOADED.
-spec clear(khash()) -> ok.
clear(_Hash) ->
?NOT_LOADED.
-spec lookup(khash(), any()) -> {value, any()} | not_found.
lookup(Hash, Key) ->
lookup_int(Hash, erlang:phash2(Key), Key).
-spec get(khash(), any()) -> any().
get(Hash, Key) ->
get(Hash, Key, undefined).
-spec get(khash(), any(), any()) -> any().
get(Hash, Key, Default) ->
get_int(Hash, erlang:phash2(Key), Key, Default).
-spec put(khash(), any(), any()) -> ok.
put(Hash, Key, Value) ->
put_int(Hash, erlang:phash2(Key), Key, Value).
-spec del(khash(), any()) -> ok.
del(Hash, Key) ->
del_int(Hash, erlang:phash2(Key), Key).
-spec size(khash()) -> non_neg_integer().
size(_Hash) ->
?NOT_LOADED.
-spec iter(khash()) -> {ok, khash_iter()}.
iter(_Hash) ->
?NOT_LOADED.
-spec iter_next(khash_iter()) ->
kv() | end_of_table | {error, expired_iterator}.
iter_next(_Iter) ->
?NOT_LOADED.
-spec fold(khash(), fun(), any()) -> any().
fold(Hash, FoldFun, Acc) ->
{ok, Iter} = ?MODULE:iter(Hash),
fold_int(Iter, FoldFun, Acc).
fold_int(Iter, FoldFun, Acc) ->
case ?MODULE:iter_next(Iter) of
{Key, Value} ->
NewAcc = FoldFun(Key, Value, Acc),
fold_int(Iter, FoldFun, NewAcc);
end_of_table ->
Acc
end.
init() ->
PrivDir = case code:priv_dir(?MODULE) of
{error, _} ->
EbinDir = filename:dirname(code:which(?MODULE)),
AppPath = filename:dirname(EbinDir),
filename:join(AppPath, "priv");
Path ->
Path
end,
erlang:load_nif(filename:join(PrivDir, "khash"), 0).
lookup_int(_Hash, _HashValue, _Key) ->
?NOT_LOADED.
get_int(_Hash, _HashValue, _Key, _Default) ->
?NOT_LOADED.
put_int(_Hash, _HashValue, _Key, _Value) ->
?NOT_LOADED.
del_int(_Hash, _HashValue, _Key) ->
?NOT_LOADED.
not_loaded(Line) ->
erlang:nif_error({not_loaded, [{module, ?MODULE}, {line, Line}]}).