Skip to content

Commit

Permalink
generalize the ets interface and behaviour
Browse files Browse the repository at this point in the history
  • Loading branch information
etrepum committed May 17, 2012
1 parent 9218de6 commit 3644298
Show file tree
Hide file tree
Showing 4 changed files with 53 additions and 42 deletions.
3 changes: 3 additions & 0 deletions rebar.config
Expand Up @@ -3,3 +3,6 @@
{cover_enabled, true}. {cover_enabled, true}.
{eunit_opts, [verbose, {report, {eunit_surefire,[{dir,"."}]}}]}. {eunit_opts, [verbose, {report, {eunit_surefire,[{dir,"."}]}}]}.
{clean_files, ["*.eunit", "ebin/*.beam"]}. {clean_files, ["*.eunit", "ebin/*.beam"]}.
%%{deps,
%% [{lets, ".*",
%% {git, "git://github.com/norton/lets.git", {branch, "master"}}}]}.
15 changes: 10 additions & 5 deletions src/markov.erl
@@ -1,15 +1,20 @@
-module(markov). -module(markov).
-export([new/0]). -export([new/0, new/1, new/2]).
-export([new/1, input/2, output/1, output/2, from_list/2, to_list/1]). -export([input/2, output/1, output/2, from_list/2, to_list/1]).


-define(WORD_MAX, 100). -define(WORD_MAX, 100).
-define(DEFAULT_STORAGE, markov_ets). -define(DEFAULT_STORAGE, markov_ets).


new() -> new() ->
new(?DEFAULT_STORAGE). new(?DEFAULT_STORAGE, []).


new(M) -> new(M) when is_atom(M) ->
{M, M:new()}. new(M, []);
new(L) when is_list(L) ->
new(?DEFAULT_STORAGE, L).

new(M, Opts) ->
{M, M:new(Opts)}.


from_list(L, {M, T}) -> from_list(L, {M, T}) ->
{M, M:from_list(L, T)}. {M, M:from_list(L, T)}.
Expand Down
70 changes: 38 additions & 32 deletions src/markov_ets.erl
@@ -1,68 +1,74 @@
-module(markov_ets). -module(markov_ets).
-export([new/0, from_list/1, from_list/2, to_list/1, append/3, lookup/2, -export([new/1, from_list/2, to_list/1, append/3, lookup/2, choose_nth/2]).
choose_nth/2]).


-define(WORD_MAX, 100). -define(WORD_MAX, 100).


new() -> new(Opts) ->
%% {{{token(), token()}, pair}, integer()} %% {{{token(), token()}, pair}, integer()}
%% {{{token(), token()}, token()}, integer()} %% {{{token(), token()}, token()}, integer()}
ets:new(?MODULE, [ordered_set]). {Ets, Name, Opts1} = lists:foldr(fun optfold/2,
{ets, ?MODULE, [ordered_set]},
Opts),
{Ets, Ets:new(Name, Opts1)}.


from_list(L) -> optfold({module, Mod}, {_Mod, Name, Acc}) ->
from_list(L, new()). {Mod, Name, Acc};
optfold({name, Name}, {Mod, _Name, Acc}) ->
{Mod, Name, Acc};
optfold(Opt, {Mod, Name, Acc}) ->
{Mod, Name, [Opt | Acc]}.


from_list([{K, V} | Rest], T) -> from_list([{K, V} | Rest], State={Ets, T}) ->
Total = lists:foldl( Total = lists:foldl(
fun ({Token, C}, Acc) -> fun ({Token, C}, Acc) ->
true = ets:insert_new(T, {{K, Token}, C}), true = Ets:insert_new(T, {{K, Token}, C}),
C + Acc C + Acc
end, end,
0, 0,
V), V),
true = ets:insert_new(T, {{K, pair}, Total}), true = Ets:insert_new(T, {{K, pair}, Total}),
from_list(Rest, T); from_list(Rest, State);
from_list([], T) -> from_list([], State) ->
T. State.


to_list(T) -> to_list(State={Ets, T}) ->
[{K, unroll(K, T)} [{K, unroll(K, State)}
|| K <- ets:select(T, [{{{'$1',pair},'_'},[],['$1']}])]. || K <- Ets:select(T, [{{{'$1',pair},'_'},[],['$1']}])].


unroll(K, T) -> unroll(K, {Ets, T}) ->
ets:select( Ets:select(
T, T,
[{{{K, '$1'}, '$2'}, [{'=/=', '$1', pair}], [{{'$1', '$2'}}]}]). [{{{K, '$1'}, '$2'}, [{'=/=', '$1', pair}], [{{'$1', '$2'}}]}]).


inc(T, K) -> inc({Ets, T}, K) ->
try ets:update_counter(T, K, 1) try Ets:update_counter(T, K, 1)
catch error:badarg -> catch error:badarg ->
ets:insert_new(T, {K, 1}), Ets:insert_new(T, {K, 1}),
1 1
end. end.


append(K, V, T) -> append(K, V, State) ->
inc(T, {K, pair}), inc(State, {K, pair}),
inc(T, {K, V}), inc(State, {K, V}),
T. State.


lookup(K, T) -> lookup(K, State={Ets, T}) ->
try ets:lookup_element(T, {K, pair}, 2) try Ets:lookup_element(T, {K, pair}, 2)
of C -> of C ->
{value, {C, {K, T}}} {value, {C, {K, State}}}
catch error:badarg -> catch error:badarg ->
none none
end. end.


choose_nth(N, {K, T}) -> choose_nth(N, {K, State={Ets, T}}) ->
%% NOTE: It's important that 'pair' sorts lower than %% NOTE: It's important that 'pair' sorts lower than
%% 'start', 'stop', and any binary! %% 'start', 'stop', and any binary!
choose_nth_iter(N, ets:next(T, {K, pair}), T). choose_nth_iter(N, Ets:next(T, {K, pair}), State).


choose_nth_iter(N, K={_Prev, Next}, T) -> choose_nth_iter(N, K={_Prev, Next}, State={Ets, T}) ->
case ets:lookup_element(T, K, 2) of case Ets:lookup_element(T, K, 2) of
V when N > V -> V when N > V ->
choose_nth_iter(N - V, ets:next(T, K), T); choose_nth_iter(N - V, Ets:next(T, K), State);
_ -> _ ->
Next Next
end. end.
7 changes: 2 additions & 5 deletions src/markov_gb.erl
@@ -1,15 +1,12 @@
-module(markov_gb). -module(markov_gb).
-export([new/0, from_list/1, from_list/2, to_list/1, append/3, lookup/2, -export([new/1, from_list/2, to_list/1, append/3, lookup/2,
choose_nth/2]). choose_nth/2]).


-define(WORD_MAX, 100). -define(WORD_MAX, 100).


new() -> new([]) ->
gb_trees:empty(). gb_trees:empty().


from_list(L) ->
from_list(L, new()).

from_list(L, EmptyT) -> from_list(L, EmptyT) ->
lists:foldl(fun ({K, V}, T) -> lists:foldl(fun ({K, V}, T) ->
gb_trees:insert(K, subtree_from_list(V), T) gb_trees:insert(K, subtree_from_list(V), T)
Expand Down

0 comments on commit 3644298

Please sign in to comment.