Skip to content
Browse files

Cleanup, refactor, and enhance for namespace support

  • Loading branch information...
1 parent 0adb99e commit 9501436edb8be1587ef15318a948a81259118be9 @norton committed Sep 17, 2012
Showing with 1,208 additions and 640 deletions.
  1. +15 −5 doc/overview.edoc
  2. +1 −0 include/gen_ets.hrl
  3. +1 −1 src/gen_ets.app.src
  4. +49 −470 src/gen_ets.erl
  5. +1 −1 src/gen_ets_impl_ets.erl
  6. +2 −163 src/gen_ets_lib.erl
  7. +907 −0 src/gen_ets_ns.erl
  8. +232 −0 src/gen_ets_reg.erl
View
20 doc/overview.edoc
@@ -7,11 +7,6 @@
GEN_ETS is an generic wrapper for Erlang Term Storage with a callback
interface for a backend implementation.
-For testing purposes, GEN_ETS supports a default backend
-implementation:
-
-- +ets+ Erlang ETS backend
-
GEN_ETS is not intended to be an exact clone of ETS. The currently
supported ETS APIs are:
@@ -50,6 +45,21 @@ supported ETS APIs are:
- +select_reverse/3+
- +tab2list/1+
+In particular, GEN_ETS differs from ETS in the following ways:
+
+- The name of a table can be any Erlang term.
+
+- All APIs require a namespace. A namespace must be a unique,
+ reserved atom. Due to limitiations of the current implementation of
+ GEN_ETS, this reserved atom is used to register a local named
+ process and to create a named ets table.
++
+CAUTION: Choose your application's namespace(s) wisely.
+
+For convience and testing purposes, GEN_ETS provides a default
+namespace wrapper and backend implementation based on ETS. See
++gen_ets+ and +gen_ets_impl_ets+ for further details.
+
_This repository is experimental in nature - use at your own risk and
please contribute if you find GEN_ETS useful._
View
1 include/gen_ets.hrl
@@ -32,6 +32,7 @@
protection=protected :: public|protected|private,
compressed=false :: boolean(),
async=false :: boolean(),
+ ns :: atom(),
mod :: module(),
impl :: term()
}).
View
2 src/gen_ets.app.src
@@ -28,6 +28,6 @@
{vsn, git},
{registered, []},
{applications, [kernel, stdlib, sasl]},
- {modules, [gen_ets, gen_ets_impl_ets, gen_ets_lib]}
+ {modules, [gen_ets, gen_ets_impl_ets, gen_ets_ns, gen_ets_lib, gen_ets_reg]}
]
}.
View
519 src/gen_ets.erl
@@ -65,158 +65,33 @@
%% DEBUG -compile(export_all).
--export_type([gen_tab/0, gen_tid/0, name/0, match_pattern/0, match_spec/0]).
-
-%% Interface Functions
--ifndef(old_callbacks).
-
--callback open(#gen_tid{}, impl_opts()) -> impl().
--callback destroy(#gen_tid{}, impl_opts()) -> true.
--callback repair(#gen_tid{}, impl_opts()) -> true.
--callback delete(#gen_tid{}) -> true.
--callback delete(#gen_tid{}, key()) -> true.
--callback delete_all_objects(#gen_tid{}) -> true.
--callback first(#gen_tid{}) -> key() | '$end_of_table'.
--callback first_iter(#gen_tid{}) -> object() | '$end_of_table'.
--callback info_memory(#gen_tid{}) -> non_neg_integer().
--callback info_size(#gen_tid{}) -> non_neg_integer().
--callback insert(#gen_tid{}, object() | [object()]) -> true.
--callback insert_new(#gen_tid{}, object() | [object()]) -> true.
--callback last(#gen_tid{}) -> key() | '$end_of_table'.
--callback last_iter(#gen_tid{}) -> object() | '$end_of_table'.
--callback lookup(#gen_tid{}, key()) -> [object()].
--callback lookup_element(#gen_tid{}, key(), pos()) -> term().
--callback member(#gen_tid{}, key()) -> true | false.
--callback next(#gen_tid{}, key()) -> key() | '$end_of_table'.
--callback next_iter(#gen_tid{}, key()) -> object() | '$end_of_table'.
--callback prev(#gen_tid{}, key()) -> key() | '$end_of_table'.
--callback prev_iter(#gen_tid{}, key()) -> object() | '$end_of_table'.
-
--else. % -ifndef(old_callbacks).
-
--export([behaviour_info/1]).
-
-%% Define the behaviour's required mods.
-behaviour_info(callbacks) ->
- [{open,2}
- , {destroy,2}
- , {repair,2}
- , {delete,1}
- , {delete,2}
- , {delete_all_objects,1}
- , {first,1}
- , {first_iter,1}
- , {info_memory,1}
- , {info_size,1}
- , {insert,2}
- , {insert_new,2}
- , {last,1}
- , {last_iter,1}
- , {lookup,2}
- , {lookup_element,3}
- , {member,2}
- , {next,2}
- , {next_iter,2}
- , {prev,2}
- , {prev_iter,2}
- ];
-behaviour_info(_Other) ->
- undefined.
-
--endif. % -ifndef(old_callbacks).
-
-%%
-%% ETS exports
-%%
-%% -export([all/0
-%% , delete/1 %% mnesia
-%% , delete/2 %% mnesia
-%% , delete_all_objects/1
-%% , delete_object/2
-%% , file2tab/1
-%% , file2tab/2
-%% , filter/3 %% mnesia
-%% , first/1 %% mnesia
-%% , foldl/3 %% mnesia
-%% , foldr/3
-%% , from_dets/2
-%% , fun2ms/1
-%% , give_away/3
-%% , i/0
-%% , i/1
-%% , info/1
-%% , info/2 %% mnesia
-%% , init_table/2 %% mnesia
-%% , insert/2 %% mnesia
-%% , insert_new/2
-%% , is_compiled_ms/1
-%% , last/1 %% mnesia
-%% , lookup/2 %% mnesia
-%% , lookup_element/3 %% mnesia
-%% , match/1
-%% , match/2 %% mnesia
-%% , match/3
-%% , match_delete/2 %% mnesia
-%% , match_object/1
-%% , match_object/2 %% mnesia
-%% , match_object/3
-%% , match_spec_compile/1
-%% , match_spec_run/2 %% mnesia
-%% , member/2
-%% , new/2 %% mnesia
-%% , next/2 %% mnesia
-%% , prev/2 %% mnesia
-%% , rename/2
-%% , repair_continuation/2 %% mnesia
-%% , safe_fixtable/2
-%% , select/1
-%% , select/2
-%% , select/3
-%% , select_count/2
-%% , select_delete/2
-%% , select_reverse/1
-%% , select_reverse/2
-%% , select_reverse/3
-%% , setopts/2
-%% , slot/2 %% mnesia
-%% , tab2file/2
-%% , tab2file/3
-%% , tab2list/1 %% mnesia
-%% , tabfile_info/1
-%% , table/1
-%% , table/2
-%% , test_ms/2
-%% , to_dets/2
-%% , update_counter/3 %% mnesia
-%% , update_element/3
-%% ]).
+-export_type([gen_tab/0, gen_tid/0, name/0, key/0, object/0, match_pattern/0, match_spec/0]).
%%%----------------------------------------------------------------------
%%% Types/Specs/Records
%%%----------------------------------------------------------------------
--opaque gen_tid() :: #gen_tid{}.
--type gen_tab() :: name() | gen_tid().
+-type gen_tid() :: gen_ets_ns:gen_tid().
+-type gen_tab() :: gen_ets_ns:gen_tab().
-type opts() :: [opt() | {impl, {module(), impl_opts()}}].
-type opt() :: set | ordered_set | named_table | {keypos,pos_integer()} | public | protected | private | compressed | async.
-type impl_opts() :: [impl_opt()].
-type impl_opt() :: term().
--type impl() :: term().
--type key() :: term().
--type object() :: tuple().
+-type key() :: gen_ets_ns:key().
+-type object() :: gen_ets_ns:object().
--type name() :: term().
+-type name() :: gen_ets_ns:name().
-type item() :: owner | name | named_table | type | keypos | protection | compressed | async | memory | size.
-type pos() :: pos_integer().
--type match_pattern() :: atom() | tuple(). % ets:match_pattern() is not exported!
--type match_spec() :: ets:match_spec().
+-type match_pattern() :: gen_ets:match_pattern().
+-type match_spec() :: gen_ets:match_spec().
-type match() :: term().
-type limit() :: pos_integer().
--opaque cont() :: {cont, #gen_tid{}, term()}.
+-opaque cont() :: {cont, gen_tid(), term()}.
--define(DEFAULT_IMPL, gen_ets_impl_ets).
+-define(NS, gen_ets_reg).
%%%----------------------------------------------------------------------
%%% API
@@ -228,7 +103,7 @@ behaviour_info(_Other) ->
-spec all() -> [gen_tab()].
all() ->
- gen_ets_lib:reg_list().
+ gen_ets_ns:all(?NS).
%% @doc Creates a new table and returns a table identifier which can
%% be used in subsequent operations. The table identifier can be sent
@@ -275,7 +150,7 @@ all() ->
-spec new(name(), opts()) -> gen_tab().
new(Name, Opts) ->
- create(open, Name, Opts).
+ create(new, Name, Opts).
%% @doc Destroy the contents of the specified table.
%% @end
@@ -300,25 +175,15 @@ repair(Name, Opts) ->
-spec delete(gen_tab()) -> true.
delete(Tab) ->
- case check_access(Tab) of
- undefined ->
- erlang:error(badarg, [Tab]);
- Tid ->
- gen_ets_lib:reg_delete(Tid)
- end.
+ gen_ets_ns:delete(?NS, Tab).
%% @doc Deletes all objects with the key +Key+ from the table +Tab+.
%% @end
%% @see ets:delete/2
-spec delete(gen_tab(), key()) -> true.
delete(Tab, Key) ->
- case check_access(Tab) of
- undefined ->
- erlang:error(badarg, [Tab]);
- #gen_tid{mod=Mod}=Tid ->
- Mod:delete(Tid, Key)
- end.
+ gen_ets_ns:delete(?NS, Tab, Key).
%% @doc Delete all objects in the table +Tab+. The operation is
%% guaranteed to be atomic and isolated. This function only applies
@@ -328,12 +193,7 @@ delete(Tab, Key) ->
-spec delete_all_objects(gen_tab()) -> true.
delete_all_objects(Tab) ->
- case check_access(Tab) of
- undefined ->
- erlang:error(badarg, [Tab]);
- #gen_tid{mod=Mod}=Tid ->
- Mod:delete_all_objects(Tid)
- end.
+ gen_ets_ns:delete_all_objects(?NS, Tab).
%% @doc Returns the first key +Key+ in the table +Tab+. If the table
%% is empty, +'$end_of_table'+ will be returned.
@@ -342,12 +202,7 @@ delete_all_objects(Tab) ->
-spec first(gen_tab()) -> key() | '$end_of_table'.
first(Tab) ->
- case check_access(Tab) of
- undefined ->
- erlang:error(badarg, [Tab]);
- #gen_tid{mod=Mod}=Tid ->
- Mod:first(Tid)
- end.
+ gen_ets_ns:first(?NS, Tab).
%% @doc Fold from left to right over the elements of the table.
%% @end
@@ -356,12 +211,7 @@ first(Tab) ->
-spec foldl(Fun, Acc0::term(), gen_tab()) -> Acc1::term() when
Fun :: fun((Element::term(), AccIn::term()) -> AccOut::term()).
foldl(Function, Acc0, Tab) ->
- case check_access(Tab) of
- undefined ->
- erlang:error(badarg, [Tab]);
- Tid ->
- gen_ets_lib:foldl(Function, Acc0, Tid)
- end.
+ gen_ets_ns:foldl(?NS, Function, Acc0, Tab).
%% @doc Fold from right to left over the elements of the table.
%% @end
@@ -370,12 +220,7 @@ foldl(Function, Acc0, Tab) ->
-spec foldr(Fun, Acc0::term(), gen_tab()) -> Acc1::term() when
Fun :: fun((Element::term(), AccIn::term()) -> AccOut::term()).
foldr(Function, Acc0, Tab) ->
- case check_access(Tab) of
- undefined ->
- erlang:error(badarg, [Tab]);
- Tid ->
- gen_ets_lib:foldr(Function, Acc0, Tid)
- end.
+ gen_ets_ns:foldr(?NS, Function, Acc0, Tab).
%% @doc Returns information about the table +Tab+ as a list of +{Item,
%% Value}+ tuples.
@@ -385,21 +230,7 @@ foldr(Function, Acc0, Tab) ->
-spec info(gen_tab()) -> [{item(), term()}].
info(Tab) ->
- case check_access(Tab) of
- undefined ->
- erlang:error(badarg, [Tab]);
- #gen_tid{mod=Mod}=Tid ->
- [{owner, Tid#gen_tid.owner},
- {name, Tid#gen_tid.name},
- {named_table, Tid#gen_tid.named_table},
- {type, Tid#gen_tid.type},
- {keypos, Tid#gen_tid.keypos},
- {protection, Tid#gen_tid.protection},
- {compressed, Tid#gen_tid.compressed},
- {async, Tid#gen_tid.async},
- {memory, Mod:info_memory(Tid)},
- {size, Mod:info_size(Tid)}]
- end.
+ gen_ets_ns:info(?NS, Tab).
%% @doc Returns the information associated with +Item+ for the table +Tab+.
%%
@@ -421,35 +252,7 @@ info(Tab) ->
-spec info(gen_tab(), item()) -> term().
info(Tab, Item) ->
- case check_access(Tab) of
- undefined ->
- erlang:error(badarg, [Tab]);
- #gen_tid{mod=Mod}=Tid ->
- case Item of
- owner ->
- Tid#gen_tid.owner;
- name ->
- Tid#gen_tid.name;
- named_table ->
- Tid#gen_tid.named_table;
- type ->
- Tid#gen_tid.type;
- keypos ->
- Tid#gen_tid.keypos;
- protection ->
- Tid#gen_tid.protection;
- compressed ->
- Tid#gen_tid.compressed;
- async ->
- Tid#gen_tid.async;
- memory ->
- Mod:info_memory(Tid);
- size ->
- Mod:info_size(Tid);
- _ ->
- erlang:error(badarg, [Tab, Item])
- end
- end.
+ gen_ets_ns:info(?NS, Tab, Item).
%% @doc Inserts the object or all of the objects in the list
%% +ObjOrObjs+ into the table +Tab+.
@@ -458,12 +261,7 @@ info(Tab, Item) ->
-spec insert(gen_tab(), object() | [object()]) -> true.
insert(Tab, ObjOrObjs) ->
- case check_access(Tab) of
- undefined ->
- erlang:error(badarg, [Tab]);
- #gen_tid{mod=Mod}=Tid ->
- Mod:insert(Tid, ObjOrObjs)
- end.
+ gen_ets_ns:insert(?NS, Tab, ObjOrObjs).
%% @doc This function works exactly like +insert/2+, with the
%% exception that instead of overwriting objects with the same key, it
@@ -474,12 +272,7 @@ insert(Tab, ObjOrObjs) ->
-spec insert_new(gen_tab(), object() | [object()]) -> true.
insert_new(Tab, ObjOrObjs) ->
- case check_access(Tab) of
- undefined ->
- erlang:error(badarg, [Tab]);
- #gen_tid{mod=Mod}=Tid ->
- Mod:insert_new(Tid, ObjOrObjs)
- end.
+ gen_ets_ns:insert_new(?NS, Tab, ObjOrObjs).
%% @doc Returns the last key +Key+ in the table +Tab+. If the table
%% is empty, +'$end_of_table'+ will be returned.
@@ -488,12 +281,7 @@ insert_new(Tab, ObjOrObjs) ->
-spec last(gen_tab()) -> key() | '$end_of_table'.
last(Tab) ->
- case check_access(Tab) of
- undefined ->
- erlang:error(badarg, [Tab]);
- #gen_tid{mod=Mod}=Tid ->
- Mod:last(Tid)
- end.
+ gen_ets_ns:last(?NS, Tab).
%% @doc Returns a list of all objects with the key +Key+ in the table
%% +Tab+.
@@ -502,12 +290,7 @@ last(Tab) ->
-spec lookup(gen_tab(), key()) -> [object()].
lookup(Tab, Key) ->
- case check_access(Tab) of
- undefined ->
- erlang:error(badarg, [Tab]);
- #gen_tid{mod=Mod}=Tid ->
- Mod:lookup(Tid, Key)
- end.
+ gen_ets_ns:lookup(?NS, Tab, Key).
%% @doc Returns the +Pos+:th element of the object with the key +Key+
%% in the table +Tab+.
@@ -516,12 +299,7 @@ lookup(Tab, Key) ->
-spec lookup_element(gen_tab(), key(), pos()) -> term().
lookup_element(Tab, Key, Pos) ->
- case check_access(Tab) of
- undefined ->
- erlang:error(badarg, [Tab]);
- #gen_tid{mod=Mod}=Tid ->
- Mod:lookup_element(Tid, Key, Pos)
- end.
+ gen_ets_ns:lookup_element(?NS, Tab, Key, Pos).
%% @doc Matches the objects in the table +Tab+ against the pattern
%% +Pattern+.
@@ -530,12 +308,7 @@ lookup_element(Tab, Key, Pos) ->
-spec match(gen_tab(), match_pattern()) -> [match()].
match(Tab, Pattern) ->
- case check_access(Tab) of
- undefined ->
- erlang:error(badarg, [Tab]);
- Tid ->
- gen_ets_lib:match(Tid, Pattern)
- end.
+ gen_ets_ns:match(?NS, Tab, Pattern).
%% @doc Matches the objects in the table +Tab+ against the pattern
%% +Pattern+ and returns a limited (+Limit+) number of matching
@@ -545,27 +318,15 @@ match(Tab, Pattern) ->
-spec match(gen_tab(), match_pattern(), limit()) -> {[match()], cont() | '$end_of_table'} | '$end_of_table'.
match(Tab, Pattern, Limit) ->
- case check_access(Tab) of
- undefined ->
- erlang:error(badarg, [Tab]);
- Tid ->
- wrap_cont_reply(Tid, gen_ets_lib:match(Tid, Pattern, Limit))
- end.
+ gen_ets_ns:match(?NS, Tab, Pattern, Limit).
%% @doc Continues a match started with +match/3+.
%% @end
%% @see ets:match/1
-spec match(cont() | '$end_of_table') -> {[match()], cont() | '$end_of_table'} | '$end_of_table'.
-match({cont, Tab, Cont}) ->
- case check_access(Tab) of
- undefined ->
- erlang:error(badarg, [Tab]);
- Tid ->
- wrap_cont_reply(Tid, gen_ets_lib:match(Cont))
- end;
-match('$end_of_table') ->
- '$end_of_table'.
+match(Cont) ->
+ gen_ets_ns:match(?NS, Cont).
%% @doc Deletes all objects which match the pattern +Pattern+ from the
%% table +Tab+.
@@ -574,12 +335,7 @@ match('$end_of_table') ->
-spec match_delete(gen_tab(), match_pattern()) -> true.
match_delete(Tab, Pattern) ->
- case check_access(Tab) of
- undefined ->
- erlang:error(badarg, [Tab]);
- Tid ->
- gen_ets_lib:match_delete(Tid, Pattern)
- end.
+ gen_ets_ns:match_delete(?NS, Tab, Pattern).
%% @doc Matches the objects in the table +Tab+ against the pattern
%% +Pattern+.
@@ -588,12 +344,7 @@ match_delete(Tab, Pattern) ->
-spec match_object(gen_tab(), match_pattern()) -> [match()].
match_object(Tab, Pattern) ->
- case check_access(Tab) of
- undefined ->
- erlang:error(badarg, [Tab]);
- Tid ->
- gen_ets_lib:match_object(Tid, Pattern)
- end.
+ gen_ets_ns:match_object(?NS, Tab, Pattern).
%% @doc Matches the objects in the table +Tab+ against the pattern
%% +Pattern+ and returns a limited (+Limit+) number of matching
@@ -603,27 +354,15 @@ match_object(Tab, Pattern) ->
-spec match_object(gen_tab(), match_pattern(), limit()) -> {[match()], cont() | '$end_of_table'} | '$end_of_table'.
match_object(Tab, Pattern, Limit) ->
- case check_access(Tab) of
- undefined ->
- erlang:error(badarg, [Tab]);
- Tid ->
- wrap_cont_reply(Tid, gen_ets_lib:match_object(Tid, Pattern, Limit))
- end.
+ gen_ets_ns:match_object(?NS, Tab, Pattern, Limit).
%% @doc Continues a match started with +match_object/3+.
%% @end
%% @see ets:match_object/1
-spec match_object(cont() | '$end_of_table') -> {[match()], cont() | '$end_of_table'} | '$end_of_table'.
-match_object({cont, Tab, Cont}) ->
- case check_access(Tab) of
- undefined ->
- erlang:error(badarg, [Tab]);
- Tid ->
- wrap_cont_reply(Tid, gen_ets_lib:match_object(Cont))
- end;
-match_object('$end_of_table') ->
- '$end_of_table'.
+match_object(Cont) ->
+ gen_ets_ns:match_object(?NS, Cont).
%% @doc Returns +true+ if one or more elements in the table +Tab+ has
%% the key +Key+, +false+ otherwise.
@@ -632,12 +371,7 @@ match_object('$end_of_table') ->
-spec member(gen_tab(), key()) -> true | false.
member(Tab, Key) ->
- case check_access(Tab) of
- undefined ->
- erlang:error(badarg, [Tab]);
- #gen_tid{mod=Mod}=Tid ->
- Mod:member(Tid, Key)
- end.
+ gen_ets_ns:member(?NS, Tab, Key).
%% @doc Returns the next key +Key2+, following the key +Key1+ in the
%% table +Tab+. If there is no next key, +'$end_of_table'+ is
@@ -647,12 +381,7 @@ member(Tab, Key) ->
-spec next(gen_tab(), key()) -> key() | '$end_of_table'.
next(Tab, Key) ->
- case check_access(Tab) of
- undefined ->
- erlang:error(badarg, [Tab]);
- #gen_tid{mod=Mod}=Tid ->
- Mod:next(Tid, Key)
- end.
+ gen_ets_ns:next(?NS, Tab, Key).
%% @doc Returns the previous key +Key2+, following the key +Key1+ in
%% the table +Tab+. If there is no previous key, +'$end_of_table'+ is
@@ -662,12 +391,7 @@ next(Tab, Key) ->
-spec prev(gen_tab(), key()) -> key() | '$end_of_table'.
prev(Tab, Key) ->
- case check_access(Tab) of
- undefined ->
- erlang:error(badarg, [Tab]);
- #gen_tid{mod=Mod}=Tid ->
- Mod:prev(Tid, Key)
- end.
+ gen_ets_ns:prev(?NS, Tab, Key).
%% @doc Matches the objects in the table +Tab+ against the spec
%% +Spec+.
@@ -676,12 +400,7 @@ prev(Tab, Key) ->
-spec select(gen_tab(), match_spec()) -> [match()].
select(Tab, Spec) ->
- case check_access(Tab) of
- undefined ->
- erlang:error(badarg, [Tab]);
- Tid ->
- gen_ets_lib:select(Tid, Spec)
- end.
+ gen_ets_ns:select(?NS, Tab, Spec).
%% @doc Matches the objects in the table +Tab+ against the spec +Spec+
%% and returns a limited (+Limit+) number of matching objects.
@@ -690,27 +409,15 @@ select(Tab, Spec) ->
-spec select(gen_tab(), match_spec(), limit()) -> {[match()], cont() | '$end_of_table'} | '$end_of_table'.
select(Tab, Spec, Limit) ->
- case check_access(Tab) of
- undefined ->
- erlang:error(badarg, [Tab]);
- Tid ->
- wrap_cont_reply(Tid, gen_ets_lib:select(Tid, Spec, Limit))
- end.
+ gen_ets_ns:select(?NS, Tab, Spec, Limit).
%% @doc Continues a select started with +select/3+.
%% @end
%% @see ets:select/1
-spec select(cont() | '$end_of_table') -> {[match()], cont() | '$end_of_table'} | '$end_of_table'.
-select({cont, Tab, Cont}) ->
- case check_access(Tab) of
- undefined ->
- erlang:error(badarg, [Tab]);
- Tid ->
- wrap_cont_reply(Tid, gen_ets_lib:select(Cont))
- end;
-select('$end_of_table') ->
- '$end_of_table'.
+select(Cont) ->
+ gen_ets_ns:select(?NS, Cont).
%% @doc Counts all objects which match the spec +Spec+ from the
%% table +Tab+ and returns the number matched.
@@ -719,12 +426,7 @@ select('$end_of_table') ->
-spec select_count(gen_tab(), match_spec()) -> pos_integer().
select_count(Tab, Spec) ->
- case check_access(Tab) of
- undefined ->
- erlang:error(badarg, [Tab]);
- Tid ->
- gen_ets_lib:select_count(Tid, Spec)
- end.
+ gen_ets_ns:select_count(?NS, Tab, Spec).
%% @doc Deletes all objects which match the spec +Spec+ from the
%% table +Tab+ and returns the number deleted.
@@ -733,12 +435,7 @@ select_count(Tab, Spec) ->
-spec select_delete(gen_tab(), match_spec()) -> pos_integer().
select_delete(Tab, Spec) ->
- case check_access(Tab) of
- undefined ->
- erlang:error(badarg, [Tab]);
- Tid ->
- gen_ets_lib:select_delete(Tid, Spec)
- end.
+ gen_ets_ns:select_delete(?NS, Tab, Spec).
%% @doc Matches in reverse the objects in the table +Tab+ against the
%% spec +Spec+.
@@ -747,12 +444,7 @@ select_delete(Tab, Spec) ->
-spec select_reverse(gen_tab(), match_spec()) -> [match()].
select_reverse(Tab, Spec) ->
- case check_access(Tab) of
- undefined ->
- erlang:error(badarg, [Tab]);
- Tid ->
- gen_ets_lib:select_reverse(Tid, Spec)
- end.
+ gen_ets_ns:select_reverse(?NS, Tab, Spec).
%% @doc Matches in reverse the objects in the table +Tab+ against the
%% spec +Spec+ and returns a limited (+Limit+) number of matching
@@ -762,27 +454,15 @@ select_reverse(Tab, Spec) ->
-spec select_reverse(gen_tab(), match_spec(), limit()) -> {[match()], cont() | '$end_of_table'} | '$end_of_table'.
select_reverse(Tab, Spec, Limit) ->
- case check_access(Tab) of
- undefined ->
- erlang:error(badarg, [Tab]);
- Tid ->
- wrap_cont_reply(Tid, gen_ets_lib:select_reverse(Tid, Spec, Limit))
- end.
+ gen_ets_ns:select_reverse(?NS, Tab, Spec, Limit).
%% @doc Continues a select reverse started with +select_reverse/3+.
%% @end
%% @see ets:select_reverse/1
-spec select_reverse(cont() | '$end_of_table') -> {[match()], cont() | '$end_of_table'} | '$end_of_table'.
-select_reverse({cont, Tab, Cont}) ->
- case check_access(Tab) of
- undefined ->
- erlang:error(badarg, [Tab]);
- Tid ->
- wrap_cont_reply(Tid, gen_ets_lib:select_reverse(Cont))
- end;
-select_reverse('$end_of_table') ->
- '$end_of_table'.
+select_reverse(Cont) ->
+ gen_ets_ns:select_reverse(?NS, Cont).
%% @doc Returns a list of all objects in the table +Tab+. The
%% operation is *not* guaranteed to be atomic and isolated.
@@ -791,112 +471,11 @@ select_reverse('$end_of_table') ->
-spec tab2list(gen_tab()) -> [object()].
tab2list(Tab) ->
- case check_access(Tab) of
- undefined ->
- erlang:error(badarg, [Tab]);
- Tid ->
- gen_ets_lib:tab2list(Tid)
- end.
+ gen_ets_ns:tab2list(?NS, Tab).
%%%----------------------------------------------------------------------
%%% Internal functions
%%%----------------------------------------------------------------------
--spec check_access(gen_tab()) -> gen_tid() | undefined.
-check_access(#gen_tid{impl=undefined}) ->
- undefined;
-check_access(#gen_tid{protection=Protection, owner=Owner}=Tid)
- when Protection==public orelse Owner==self() ->
- Tid;
-check_access(#gen_tid{}) ->
- undefined;
-check_access(Name) ->
- case gen_ets_lib:reg_lookup(Name) of
- undefined ->
- undefined;
- Tid ->
- check_access(Tid)
- end.
-
create(Op, Name, Opts) ->
- case options(Opts) of
- {POpts, []} ->
- POpts;
- {POpts, BadArgs} ->
- erlang:error(badarg, [Name, BadArgs])
- end,
-
- Owner = self(),
- NamedTable = proplists:get_bool(named_table, POpts),
- Type =
- case proplists:get_bool(ordered_set, POpts) of
- true ->
- ordered_set;
- false ->
- set
- end,
- KeyPos = proplists:get_value(keypos, POpts, 1),
- Protection =
- case proplists:get_bool(private, POpts) of
- true ->
- private;
- false ->
- case proplists:get_bool(protected, POpts) of
- true ->
- protected;
- false ->
- case proplists:get_bool(public, POpts) of
- true ->
- public;
- false ->
- protected
- end
- end
- end,
- Compressed = proplists:get_bool(compressed, POpts),
- Async = proplists:get_bool(async, POpts),
-
- {ImplMod, ImplOpts} = proplists:get_value(impl, POpts, {?DEFAULT_IMPL, []}),
- Tid = #gen_tid{owner=Owner,
- name=Name,
- named_table=NamedTable,
- type=Type,
- keypos=KeyPos,
- protection=Protection,
- compressed=Compressed,
- async=Async,
- mod=ImplMod},
-
- case gen_ets_lib:reg_insert(Tid, Op, ImplOpts) of
- undefined ->
- erlang:error(badarg, [Name, Opts]);
- Ok ->
- Ok
- end.
-
-options(Options) ->
- Keys = [set, ordered_set, named_table, keypos, public, protected, private, compressed, async, impl],
- options(Options, Keys).
-
-options(Options, Keys) when is_list(Options) ->
- options(Options, Keys, []);
-options(Option, Keys) ->
- options([Option], Keys, []).
-
-options(Options, [Key|Keys], L) when is_list(Options) ->
- case proplists:lookup(Key, Options) of
- none ->
- options(Options, Keys, L);
- {Key, Value} ->
- NewOptions = proplists:delete(Key, Options),
- options(NewOptions, Keys, [{Key,Value}|L])
- end;
-options(Options, [], L) ->
- {lists:reverse(L), Options}.
-
-wrap_cont_reply(_Tid, '$end_of_table'=Reply) ->
- Reply;
-wrap_cont_reply(_Tid, {_Match, '$end_of_table'}=Reply) ->
- Reply;
-wrap_cont_reply(Tid, {_Match, Cont}=Reply) ->
- setelement(2, Reply, {cont, Tid, Cont}).
+ gen_ets_ns:Op(?NS, Name, Opts).
View
2 src/gen_ets_impl_ets.erl
@@ -21,7 +21,7 @@
%%% THE SOFTWARE.
-module(gen_ets_impl_ets).
--behaviour(gen_ets).
+-behaviour(gen_ets_ns).
-include("gen_ets.hrl").
View
165 src/gen_ets_lib.erl
@@ -25,14 +25,8 @@
-include("gen_ets.hrl").
%% External exports
--export([reg_setup/0
- , reg_teardown/0
- , reg_list/0
- , reg_insert/3
- , reg_delete/1
- , reg_lookup/1
- %% ets friends
- , foldl/3
+-export([%% ets friends
+ foldl/3
, foldr/3
%% , nfoldl/4
%% , nfoldr/4
@@ -60,165 +54,10 @@
%%% Types/Specs/Records
%%%----------------------------------------------------------------------
--record(gen_reg, {name :: gen_ets:name(), pid::pid(), tid :: #gen_tid{}}).
--define(TAB, ?MODULE).
-
%%%----------------------------------------------------------------------
%%% API
%%%----------------------------------------------------------------------
-reg_setup() ->
- case ets:info(?TAB, name) of
- undefined ->
- Caller = self(),
- Fun = fun() ->
- register(?MODULE, self()),
- ?TAB = ets:new(?TAB, [ordered_set, public, named_table, {keypos, #gen_reg.name}, {read_concurrency, true}]),
- Caller ! self(),
- receive
- {Pid, stop} ->
- Pid ! self()
- end
- end,
-
- {Pid, Ref} = spawn_monitor(Fun),
- try
- receive
- Pid ->
- ok;
- {'DOWN', Ref, process, _Object, _Info} ->
- ok
- end
- after
- demonitor(Ref, [flush])
- end;
- _ ->
- ok
- end.
-
-reg_teardown() ->
- case whereis(?MODULE) of
- undefined ->
- ok;
- Pid ->
- Ref = monitor(process, Pid),
- try
- Pid ! {self(), stop},
- receive
- Pid ->
- ok;
- {'DOWN', Ref, process, _Object, _Info} ->
- ok
- end
- after
- demonitor(Ref, [flush])
- end
- end.
-
-reg_list() ->
- reg_setup(),
- [ if Named -> Name; true -> Tid end
- || #gen_reg{name=Name, tid=#gen_tid{named_table=Named}=Tid} <- ets:tab2list(?TAB) ].
-
-reg_insert(#gen_tid{name=Name, named_table=Named}=PreTid, open=Op, Opts) ->
- reg_setup(),
- PreReg = #gen_reg{name=Name, tid=undefined},
- case ets:insert_new(?TAB, PreReg) of
- true ->
- try
- Parent = self(),
- Fun = fun() -> reg_loop(PreTid, Op, Opts, PreReg, Parent) end,
-
- {Child, ChildRef} = spawn_monitor(Fun),
- receive
- {Child, Tid} ->
- if Named ->
- Name;
- true ->
- Tid
- end;
- {'DOWN', ChildRef, process, _Object, _Info} ->
- undefined
- end
- after
- %% cleanup failures
- catch ets:delete_object(?TAB, PreReg)
- end;
- false ->
- undefined
- end;
-reg_insert(#gen_tid{name=Name, mod=Mod}=Tid, Op, Opts) ->
- reg_setup(),
- case reg_lookup(Name) of
- undefined ->
- Mod:Op(Tid, Opts);
- _ ->
- undefined
- end.
-
-reg_delete(#gen_tid{name=Name}) ->
- try
- case ets:lookup(?TAB, Name) of
- [#gen_reg{pid=undefined}] ->
- false;
- [#gen_reg{pid=Pid}] ->
- Ref = monitor(process, Pid),
- Pid ! stop,
- try
- receive
- {'DOWN', Ref, process, _Object, _Info} ->
- true
- end
- after
- demonitor(Ref, [flush])
- end;
- [] ->
- false
- end
- catch
- error:badarg ->
- false
- end.
-
-reg_lookup(Name) ->
- try
- case ets:lookup(?TAB, Name) of
- [#gen_reg{tid=undefined}] ->
- undefined;
- [#gen_reg{tid=Tid}] ->
- Tid;
- [] ->
- undefined
- end
- catch
- error:badarg ->
- undefined
- end.
-
-reg_loop(#gen_tid{mod=Mod}=PreTid, Op, Opts, PreReg, Parent) ->
- ParentRef = monitor(process, Parent),
-
- Impl = Mod:Op(PreTid, Opts),
- Tid = PreTid#gen_tid{impl=Impl},
- Reg = PreReg#gen_reg{pid=self(), tid=Tid},
-
- ets:insert(?TAB, Reg),
- try
- Parent ! {self(), Tid},
- receive
- stop ->
- ok;
- {'DOWN', ParentRef, process, _Object, _Info} ->
- ok
- end,
- %% delete
- Mod:delete(Tid)
- after
- %% cleanup
- ets:delete_object(?TAB, Reg),
- demonitor(ParentRef, [flush])
- end.
-
foldl(Fun, Acc0, #gen_tid{mod=Mod}=Tid) ->
foldl(Fun, Acc0, Tid, Mod:first_iter(Tid)).
View
907 src/gen_ets_ns.erl
@@ -0,0 +1,907 @@
+%%% The MIT License
+%%%
+%%% Copyright (C) 2011-2012 by Joseph Wayne Norton <norton@alum.mit.edu>
+%%%
+%%% Permission is hereby granted, free of charge, to any person obtaining a copy
+%%% of this software and associated documentation files (the "Software"), to deal
+%%% in the Software without restriction, including without limitation the rights
+%%% to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+%%% copies of the Software, and to permit persons to whom the Software is
+%%% furnished to do so, subject to the following conditions:
+%%%
+%%% The above copyright notice and this permission notice shall be included in
+%%% all copies or substantial portions of the Software.
+%%%
+%%% THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+%%% IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+%%% FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+%%% AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+%%% LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+%%% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+%%% THE SOFTWARE.
+
+-module(gen_ets_ns).
+
+-include("gen_ets.hrl").
+
+%% External exports
+-export([all/1
+ , new/3
+ , destroy/3
+ , repair/3
+ , delete/2
+ , delete/3
+ , delete_all_objects/2
+ , first/2
+ , foldl/4
+ , foldr/4
+ , info/2
+ , info/3
+ , insert/3
+ , insert_new/3
+ , last/2
+ , lookup/3
+ , lookup_element/4
+ , match/3
+ , match/4
+ , match/2
+ , match_delete/3
+ , match_object/3
+ , match_object/4
+ , match_object/2
+ , member/3
+ , next/3
+ , prev/3
+ , select/3
+ , select/4
+ , select/2
+ , select_count/3
+ , select_delete/3
+ , select_reverse/3
+ , select_reverse/4
+ , select_reverse/2
+ , tab2list/2
+ ]).
+
+%% DEBUG -compile(export_all).
+
+-export_type([gen_tab/0, gen_tid/0, gen_ns/0]).
+-export_type([name/0, key/0, object/0]).
+-export_type([match_pattern/0, match_spec/0]).
+
+%% Interface Functions
+-ifndef(old_callbacks).
+
+-callback open(#gen_tid{}, impl_opts()) -> impl().
+-callback destroy(#gen_tid{}, impl_opts()) -> true.
+-callback repair(#gen_tid{}, impl_opts()) -> true.
+-callback delete(#gen_tid{}) -> true.
+-callback delete(#gen_tid{}, key()) -> true.
+-callback delete_all_objects(#gen_tid{}) -> true.
+-callback first(#gen_tid{}) -> key() | '$end_of_table'.
+-callback first_iter(#gen_tid{}) -> object() | '$end_of_table'.
+-callback info_memory(#gen_tid{}) -> non_neg_integer().
+-callback info_size(#gen_tid{}) -> non_neg_integer().
+-callback insert(#gen_tid{}, object() | [object()]) -> true.
+-callback insert_new(#gen_tid{}, object() | [object()]) -> true.
+-callback last(#gen_tid{}) -> key() | '$end_of_table'.
+-callback last_iter(#gen_tid{}) -> object() | '$end_of_table'.
+-callback lookup(#gen_tid{}, key()) -> [object()].
+-callback lookup_element(#gen_tid{}, key(), pos()) -> term().
+-callback member(#gen_tid{}, key()) -> true | false.
+-callback next(#gen_tid{}, key()) -> key() | '$end_of_table'.
+-callback next_iter(#gen_tid{}, key()) -> object() | '$end_of_table'.
+-callback prev(#gen_tid{}, key()) -> key() | '$end_of_table'.
+-callback prev_iter(#gen_tid{}, key()) -> object() | '$end_of_table'.
+
+-else. % -ifndef(old_callbacks).
+
+-export([behaviour_info/1]).
+
+%% Define the behaviour's required mods.
+behaviour_info(callbacks) ->
+ [{open,2}
+ , {destroy,2}
+ , {repair,2}
+ , {delete,1}
+ , {delete,2}
+ , {delete_all_objects,1}
+ , {first,1}
+ , {first_iter,1}
+ , {info_memory,1}
+ , {info_size,1}
+ , {insert,2}
+ , {insert_new,2}
+ , {last,1}
+ , {last_iter,1}
+ , {lookup,2}
+ , {lookup_element,3}
+ , {member,2}
+ , {next,2}
+ , {next_iter,2}
+ , {prev,2}
+ , {prev_iter,2}
+ ];
+behaviour_info(_Other) ->
+ undefined.
+
+-endif. % -ifndef(old_callbacks).
+
+%%
+%% ETS exports
+%%
+%% -export([all/0
+%% , delete/1 %% mnesia
+%% , delete/2 %% mnesia
+%% , delete_all_objects/1
+%% , delete_object/2
+%% , file2tab/1
+%% , file2tab/2
+%% , filter/3 %% mnesia
+%% , first/1 %% mnesia
+%% , foldl/3 %% mnesia
+%% , foldr/3
+%% , from_dets/2
+%% , fun2ms/1
+%% , give_away/3
+%% , i/0
+%% , i/1
+%% , info/1
+%% , info/2 %% mnesia
+%% , init_table/2 %% mnesia
+%% , insert/2 %% mnesia
+%% , insert_new/2
+%% , is_compiled_ms/1
+%% , last/1 %% mnesia
+%% , lookup/2 %% mnesia
+%% , lookup_element/3 %% mnesia
+%% , match/1
+%% , match/2 %% mnesia
+%% , match/3
+%% , match_delete/2 %% mnesia
+%% , match_object/1
+%% , match_object/2 %% mnesia
+%% , match_object/3
+%% , match_spec_compile/1
+%% , match_spec_run/2 %% mnesia
+%% , member/2
+%% , new/2 %% mnesia
+%% , next/2 %% mnesia
+%% , prev/2 %% mnesia
+%% , rename/2
+%% , repair_continuation/2 %% mnesia
+%% , safe_fixtable/2
+%% , select/1
+%% , select/2
+%% , select/3
+%% , select_count/2
+%% , select_delete/2
+%% , select_reverse/1
+%% , select_reverse/2
+%% , select_reverse/3
+%% , setopts/2
+%% , slot/2 %% mnesia
+%% , tab2file/2
+%% , tab2file/3
+%% , tab2list/1 %% mnesia
+%% , tabfile_info/1
+%% , table/1
+%% , table/2
+%% , test_ms/2
+%% , to_dets/2
+%% , update_counter/3 %% mnesia
+%% , update_element/3
+%% ]).
+
+%%%----------------------------------------------------------------------
+%%% Types/Specs/Records
+%%%----------------------------------------------------------------------
+
+-type gen_ns() :: atom().
+-opaque gen_tid() :: #gen_tid{}.
+-type gen_tab() :: name() | gen_tid().
+
+-type opts() :: [opt() | {impl, {module(), impl_opts()}}].
+-type opt() :: set | ordered_set | named_table | {keypos,pos_integer()} | public | protected | private | compressed | async.
+-type impl_opts() :: [impl_opt()].
+-type impl_opt() :: term().
+-type impl() :: term().
+
+-type key() :: term().
+-type object() :: tuple().
+
+-type name() :: term().
+-type item() :: owner | name | named_table | type | keypos | protection | compressed | async | memory | size.
+-type pos() :: pos_integer().
+-type match_pattern() :: atom() | tuple(). % ets:match_pattern() is not exported!
+-type match_spec() :: ets:match_spec().
+-type match() :: term().
+-type limit() :: pos_integer().
+-opaque cont() :: {cont, #gen_tid{}, term()}.
+
+-define(DEFAULT_MOD, gen_ets_impl_ets).
+
+%%%----------------------------------------------------------------------
+%%% API
+%%%----------------------------------------------------------------------
+
+%% @doc Returns a list of all tables at the node.
+%% @end
+%% @see ets:all/0
+
+-spec all(gen_ns()) -> [gen_tab()].
+all(NS) ->
+ gen_ets_reg:list(NS).
+
+%% @doc Creates a new table and returns a table identifier which can
+%% be used in subsequent operations. The table identifier can be sent
+%% to other processes so that a table can be shared between different
+%% processes within a node.
+%%
+%% Valid GEN_ETS properties for +Options+ are:
+%%
+%% - +set+ The table is a set table - one key, one object, no order
+%% among objects. This is the default table type.
+%%
+%% - +ordered_set+ The table is an ordered_set table - one key, one
+%% object, ordered in Erlang term order, which is the order implied
+%% by the +<+ and +>+ operators.
+%%
+%% - +named_table+ If this option is present, the name +Name+ is
+%% associated with the table identifier.
+%%
+%% - +{keypos,pos_integer()}+ Specfies which element in the stored
+%% tuples should be used as key. By default, it is the first
+%% element, i.e. +Pos=1+.
+%%
+%% - +public+ Any process may read or write to the table.
+%%
+%% - +protected+ The owner process can read and write to the table.
+%% Other processes can only read the table. This is the default
+%% setting for the access rights.
+%%
+%% - +private+ Only the owner process can read or write to the table.
+%%
+%% - +compressed+ If this option is present, the table data will be
+%% stored in a compressed format.
+%%
+%% - +async+ If this option is present and supported by the
+%% implementation, the emulator\'s async thread pool will be used
+%% when accessing the table data.
+%%
+%% - +{impl, module(), [impl_option()]}+ The module that implements
+%% GEN_ETS callback functions. Implementation specific options can
+%% be given. The default is +{impl, gen_ets_impl_ets, []}+.
+%%
+%% @end
+%% @see ets:new/2
+
+-spec new(gen_ns(), name(), opts()) -> gen_tab().
+new(NS, Name, Opts) ->
+ create(NS, open, Name, Opts).
+
+%% @doc Destroy the contents of the specified table.
+%% @end
+
+-spec destroy(gen_ns(), name(), opts()) -> true.
+destroy(NS, Name, Opts) ->
+ create(NS, destroy, Name, Opts).
+
+%% @doc If a table cannot be opened, you may attempt to call this
+%% method to resurrect as much of the contents of the table as
+%% possible. Some data may be lost, so be careful when calling this
+%% function on a table that contains important information.
+%% @end
+
+-spec repair(gen_ns(), name(), opts()) -> true.
+repair(NS, Name, Opts) ->
+ create(NS, repair, Name, Opts).
+
+%% @doc Deletes the entire table +Tab+.
+%% @end
+%% @see ets:delete/1
+
+-spec delete(gen_ns(), gen_tab()) -> true.
+delete(NS, Tab) ->
+ case check_access(NS, Tab) of
+ undefined ->
+ erlang:error(badarg, [NS, Tab]);
+ Tid ->
+ gen_ets_reg:delete(Tid)
+ end.
+
+%% @doc Deletes all objects with the key +Key+ from the table +Tab+.
+%% @end
+%% @see ets:delete/2
+
+-spec delete(gen_ns(), gen_tab(), key()) -> true.
+delete(NS, Tab, Key) ->
+ case check_access(NS, Tab) of
+ undefined ->
+ erlang:error(badarg, [NS, Tab]);
+ #gen_tid{mod=Mod}=Tid ->
+ Mod:delete(Tid, Key)
+ end.
+
+%% @doc Delete all objects in the table +Tab+. The operation is
+%% guaranteed to be atomic and isolated. This function only applies
+%% to the +ets+ implementation.
+%% @end
+%% @see ets:delete_all_objects/1
+
+-spec delete_all_objects(gen_ns(), gen_tab()) -> true.
+delete_all_objects(NS, Tab) ->
+ case check_access(NS, Tab) of
+ undefined ->
+ erlang:error(badarg, [NS, Tab]);
+ #gen_tid{mod=Mod}=Tid ->
+ Mod:delete_all_objects(Tid)
+ end.
+
+%% @doc Returns the first key +Key+ in the table +Tab+. If the table
+%% is empty, +'$end_of_table'+ will be returned.
+%% @end
+%% @see ets:first/1
+
+-spec first(gen_ns(), gen_tab()) -> key() | '$end_of_table'.
+first(NS, Tab) ->
+ case check_access(NS, Tab) of
+ undefined ->
+ erlang:error(badarg, [NS, Tab]);
+ #gen_tid{mod=Mod}=Tid ->
+ Mod:first(Tid)
+ end.
+
+%% @doc Fold from left to right over the elements of the table.
+%% @end
+%% @see ets:foldl/3
+
+-spec foldl(gen_ns(), Fun, Acc0::term(), gen_tab()) -> Acc1::term() when
+ Fun :: fun((Element::term(), AccIn::term()) -> AccOut::term()).
+foldl(NS, Function, Acc0, Tab) ->
+ case check_access(NS, Tab) of
+ undefined ->
+ erlang:error(badarg, [NS, Tab]);
+ Tid ->
+ gen_ets_lib:foldl(Function, Acc0, Tid)
+ end.
+
+%% @doc Fold from right to left over the elements of the table.
+%% @end
+%% @see ets:foldr/3
+
+-spec foldr(gen_ns(), Fun, Acc0::term(), gen_tab()) -> Acc1::term() when
+ Fun :: fun((Element::term(), AccIn::term()) -> AccOut::term()).
+foldr(NS, Function, Acc0, Tab) ->
+ case check_access(NS, Tab) of
+ undefined ->
+ erlang:error(badarg, [NS, Tab]);
+ Tid ->
+ gen_ets_lib:foldr(Function, Acc0, Tid)
+ end.
+
+%% @doc Returns information about the table +Tab+ as a list of +{Item,
+%% Value}+ tuples.
+%%
+%% @end
+%% @see info/2
+
+-spec info(gen_ns(), gen_tab()) -> [{item(), term()}].
+info(NS, Tab) ->
+ case check_access(NS, Tab) of
+ undefined ->
+ erlang:error(badarg, [NS, Tab]);
+ #gen_tid{mod=Mod}=Tid ->
+ [{owner, Tid#gen_tid.owner},
+ {name, Tid#gen_tid.name},
+ {named_table, Tid#gen_tid.named_table},
+ {type, Tid#gen_tid.type},
+ {keypos, Tid#gen_tid.keypos},
+ {protection, Tid#gen_tid.protection},
+ {compressed, Tid#gen_tid.compressed},
+ {async, Tid#gen_tid.async},
+ {memory, Mod:info_memory(Tid)},
+ {size, Mod:info_size(Tid)}]
+ end.
+
+%% @doc Returns the information associated with +Item+ for the table +Tab+.
+%%
+%% Valid +Item+ options are:
+%%
+%% - +owner+
+%% - +name+
+%% - +named_table+ _only the ets implementation_
+%% - +type+
+%% - +keypos+
+%% - +protection+
+%% - +compressed+
+%% - +async+ _only the drv implementation_
+%% - +memory+ _only the ets implementation_
+%% - +size+ _only the ets implementation_
+%%
+%% @end
+%% @see ets:info/2
+
+-spec info(gen_ns(), gen_tab(), item()) -> term().
+info(NS, Tab, Item) ->
+ case check_access(NS, Tab) of
+ undefined ->
+ erlang:error(badarg, [NS, Tab]);
+ #gen_tid{mod=Mod}=Tid ->
+ case Item of
+ owner ->
+ Tid#gen_tid.owner;
+ name ->
+ Tid#gen_tid.name;
+ named_table ->
+ Tid#gen_tid.named_table;
+ type ->
+ Tid#gen_tid.type;
+ keypos ->
+ Tid#gen_tid.keypos;
+ protection ->
+ Tid#gen_tid.protection;
+ compressed ->
+ Tid#gen_tid.compressed;
+ async ->
+ Tid#gen_tid.async;
+ memory ->
+ Mod:info_memory(Tid);
+ size ->
+ Mod:info_size(Tid);
+ _ ->
+ erlang:error(badarg, [NS, Tab, Item])
+ end
+ end.
+
+%% @doc Inserts the object or all of the objects in the list
+%% +ObjOrObjs+ into the table +Tab+.
+%% @end
+%% @see ets:insert/2
+
+-spec insert(gen_ns(), gen_tab(), object() | [object()]) -> true.
+insert(NS, Tab, ObjOrObjs) ->
+ case check_access(NS, Tab) of
+ undefined ->
+ erlang:error(badarg, [NS, Tab]);
+ #gen_tid{mod=Mod}=Tid ->
+ Mod:insert(Tid, ObjOrObjs)
+ end.
+
+%% @doc This function works exactly like +insert/2+, with the
+%% exception that instead of overwriting objects with the same key, it
+%% simply returns false. This function only applies to the +ets+
+%% implementation.
+%% @end
+%% @see ets:insert_new/2
+
+-spec insert_new(gen_ns(), gen_tab(), object() | [object()]) -> true.
+insert_new(NS, Tab, ObjOrObjs) ->
+ case check_access(NS, Tab) of
+ undefined ->
+ erlang:error(badarg, [NS, Tab]);
+ #gen_tid{mod=Mod}=Tid ->
+ Mod:insert_new(Tid, ObjOrObjs)
+ end.
+
+%% @doc Returns the last key +Key+ in the table +Tab+. If the table
+%% is empty, +'$end_of_table'+ will be returned.
+%% @end
+%% @see ets:last/1
+
+-spec last(gen_ns(), gen_tab()) -> key() | '$end_of_table'.
+last(NS, Tab) ->
+ case check_access(NS, Tab) of
+ undefined ->
+ erlang:error(badarg, [NS, Tab]);
+ #gen_tid{mod=Mod}=Tid ->
+ Mod:last(Tid)
+ end.
+
+%% @doc Returns a list of all objects with the key +Key+ in the table
+%% +Tab+.
+%% @end
+%% @see ets:lookup/2
+
+-spec lookup(gen_ns(), gen_tab(), key()) -> [object()].
+lookup(NS, Tab, Key) ->
+ case check_access(NS, Tab) of
+ undefined ->
+ erlang:error(badarg, [NS, Tab]);
+ #gen_tid{mod=Mod}=Tid ->
+ Mod:lookup(Tid, Key)
+ end.
+
+%% @doc Returns the +Pos+:th element of the object with the key +Key+
+%% in the table +Tab+.
+%% @end
+%% @see ets:lookup_element/3
+
+-spec lookup_element(gen_ns(), gen_tab(), key(), pos()) -> term().
+lookup_element(NS, Tab, Key, Pos) ->
+ case check_access(NS, Tab) of
+ undefined ->
+ erlang:error(badarg, [NS, Tab]);
+ #gen_tid{mod=Mod}=Tid ->
+ Mod:lookup_element(Tid, Key, Pos)
+ end.
+
+%% @doc Matches the objects in the table +Tab+ against the pattern
+%% +Pattern+.
+%% @end
+%% @see ets:match/2
+
+-spec match(gen_ns(), gen_tab(), match_pattern()) -> [match()].
+match(NS, Tab, Pattern) ->
+ case check_access(NS, Tab) of
+ undefined ->
+ erlang:error(badarg, [NS, Tab]);
+ Tid ->
+ gen_ets_lib:match(Tid, Pattern)
+ end.
+
+%% @doc Matches the objects in the table +Tab+ against the pattern
+%% +Pattern+ and returns a limited (+Limit+) number of matching
+%% objects.
+%% @end
+%% @see ets:match/3
+
+-spec match(gen_ns(), gen_tab(), match_pattern(), limit()) -> {[match()], cont() | '$end_of_table'} | '$end_of_table'.
+match(NS, Tab, Pattern, Limit) ->
+ case check_access(NS, Tab) of
+ undefined ->
+ erlang:error(badarg, [NS, Tab]);
+ Tid ->
+ wrap_cont_reply(Tid, gen_ets_lib:match(Tid, Pattern, Limit))
+ end.
+
+%% @doc Continues a match started with +match/3+.
+%% @end
+%% @see ets:match/1
+
+-spec match(gen_ns(), cont() | '$end_of_table') -> {[match()], cont() | '$end_of_table'} | '$end_of_table'.
+match(NS, {cont, Tab, Cont}) ->
+ case check_access(NS, Tab) of
+ undefined ->
+ erlang:error(badarg, [NS, Tab]);
+ Tid ->
+ wrap_cont_reply(Tid, gen_ets_lib:match(Cont))
+ end;
+match(_NS, '$end_of_table') ->
+ '$end_of_table'.
+
+%% @doc Deletes all objects which match the pattern +Pattern+ from the
+%% table +Tab+.
+%% @end
+%% @see ets:match_delete/2
+
+-spec match_delete(gen_ns(), gen_tab(), match_pattern()) -> true.
+match_delete(NS, Tab, Pattern) ->
+ case check_access(NS, Tab) of
+ undefined ->
+ erlang:error(badarg, [NS, Tab]);
+ Tid ->
+ gen_ets_lib:match_delete(Tid, Pattern)
+ end.
+
+%% @doc Matches the objects in the table +Tab+ against the pattern
+%% +Pattern+.
+%% @end
+%% @see ets:match_object/2
+
+-spec match_object(gen_ns(), gen_tab(), match_pattern()) -> [match()].
+match_object(NS, Tab, Pattern) ->
+ case check_access(NS, Tab) of
+ undefined ->
+ erlang:error(badarg, [NS, Tab]);
+ Tid ->
+ gen_ets_lib:match_object(Tid, Pattern)
+ end.
+
+%% @doc Matches the objects in the table +Tab+ against the pattern
+%% +Pattern+ and returns a limited (+Limit+) number of matching
+%% objects.
+%% @end
+%% @see ets:match_object/3
+
+-spec match_object(gen_ns(), gen_tab(), match_pattern(), limit()) -> {[match()], cont() | '$end_of_table'} | '$end_of_table'.
+match_object(NS, Tab, Pattern, Limit) ->
+ case check_access(NS, Tab) of
+ undefined ->
+ erlang:error(badarg, [NS, Tab]);
+ Tid ->
+ wrap_cont_reply(Tid, gen_ets_lib:match_object(Tid, Pattern, Limit))
+ end.
+
+%% @doc Continues a match started with +match_object/3+.
+%% @end
+%% @see ets:match_object/1
+
+-spec match_object(gen_ns(), cont() | '$end_of_table') -> {[match()], cont() | '$end_of_table'} | '$end_of_table'.
+match_object(NS, {cont, Tab, Cont}) ->
+ case check_access(NS, Tab) of
+ undefined ->
+ erlang:error(badarg, [NS, Tab]);
+ Tid ->
+ wrap_cont_reply(Tid, gen_ets_lib:match_object(Cont))
+ end;
+match_object(_NS, '$end_of_table') ->
+ '$end_of_table'.
+
+%% @doc Returns +true+ if one or more elements in the table +Tab+ has
+%% the key +Key+, +false+ otherwise.
+%% @end
+%% @see ets:member/2
+
+-spec member(gen_ns(), gen_tab(), key()) -> true | false.
+member(NS, Tab, Key) ->
+ case check_access(NS, Tab) of
+ undefined ->
+ erlang:error(badarg, [NS, Tab]);
+ #gen_tid{mod=Mod}=Tid ->
+ Mod:member(Tid, Key)
+ end.
+
+%% @doc Returns the next key +Key2+, following the key +Key1+ in the
+%% table +Tab+. If there is no next key, +'$end_of_table'+ is
+%% returned.
+%% @end
+%% @see ets:next/2
+
+-spec next(gen_ns(), gen_tab(), key()) -> key() | '$end_of_table'.
+next(NS, Tab, Key) ->
+ case check_access(NS, Tab) of
+ undefined ->
+ erlang:error(badarg, [NS, Tab]);
+ #gen_tid{mod=Mod}=Tid ->
+ Mod:next(Tid, Key)
+ end.
+
+%% @doc Returns the previous key +Key2+, following the key +Key1+ in
+%% the table +Tab+. If there is no previous key, +'$end_of_table'+ is
+%% returned.
+%% @end
+%% @see ets:prev/2
+
+-spec prev(gen_ns(), gen_tab(), key()) -> key() | '$end_of_table'.
+prev(NS, Tab, Key) ->
+ case check_access(NS, Tab) of
+ undefined ->
+ erlang:error(badarg, [NS, Tab]);
+ #gen_tid{mod=Mod}=Tid ->
+ Mod:prev(Tid, Key)
+ end.
+
+%% @doc Matches the objects in the table +Tab+ against the spec
+%% +Spec+.
+%% @end
+%% @see ets:select/2
+
+-spec select(gen_ns(), gen_tab(), match_spec()) -> [match()].
+select(NS, Tab, Spec) ->
+ case check_access(NS, Tab) of
+ undefined ->
+ erlang:error(badarg, [NS, Tab]);
+ Tid ->
+ gen_ets_lib:select(Tid, Spec)
+ end.
+
+%% @doc Matches the objects in the table +Tab+ against the spec +Spec+
+%% and returns a limited (+Limit+) number of matching objects.
+%% @end
+%% @see ets:select/3
+
+-spec select(gen_ns(), gen_tab(), match_spec(), limit()) -> {[match()], cont() | '$end_of_table'} | '$end_of_table'.
+select(NS, Tab, Spec, Limit) ->
+ case check_access(NS, Tab) of
+ undefined ->
+ erlang:error(badarg, [NS, Tab]);
+ Tid ->
+ wrap_cont_reply(Tid, gen_ets_lib:select(Tid, Spec, Limit))
+ end.
+
+%% @doc Continues a select started with +select/3+.
+%% @end
+%% @see ets:select/1
+
+-spec select(gen_ns(), cont() | '$end_of_table') -> {[match()], cont() | '$end_of_table'} | '$end_of_table'.
+select(NS, {cont, Tab, Cont}) ->
+ case check_access(NS, Tab) of
+ undefined ->
+ erlang:error(badarg, [NS, Tab]);
+ Tid ->
+ wrap_cont_reply(Tid, gen_ets_lib:select(Cont))
+ end;
+select(_NS, '$end_of_table') ->
+ '$end_of_table'.
+
+%% @doc Counts all objects which match the spec +Spec+ from the
+%% table +Tab+ and returns the number matched.
+%% @end
+%% @see ets:select_count/2
+
+-spec select_count(gen_ns(), gen_tab(), match_spec()) -> pos_integer().
+select_count(NS, Tab, Spec) ->
+ case check_access(NS, Tab) of
+ undefined ->
+ erlang:error(badarg, [NS, Tab]);
+ Tid ->
+ gen_ets_lib:select_count(Tid, Spec)
+ end.
+
+%% @doc Deletes all objects which match the spec +Spec+ from the
+%% table +Tab+ and returns the number deleted.
+%% @end
+%% @see ets:select_delete/2
+
+-spec select_delete(gen_ns(), gen_tab(), match_spec()) -> pos_integer().
+select_delete(NS, Tab, Spec) ->
+ case check_access(NS, Tab) of
+ undefined ->
+ erlang:error(badarg, [NS, Tab]);
+ Tid ->
+ gen_ets_lib:select_delete(Tid, Spec)
+ end.
+
+%% @doc Matches in reverse the objects in the table +Tab+ against the
+%% spec +Spec+.
+%% @end
+%% @see ets:select_reverse/2
+
+-spec select_reverse(gen_ns(), gen_tab(), match_spec()) -> [match()].
+select_reverse(NS, Tab, Spec) ->
+ case check_access(NS, Tab) of
+ undefined ->
+ erlang:error(badarg, [NS, Tab]);
+ Tid ->
+ gen_ets_lib:select_reverse(Tid, Spec)
+ end.
+
+%% @doc Matches in reverse the objects in the table +Tab+ against the
+%% spec +Spec+ and returns a limited (+Limit+) number of matching
+%% objects.
+%% @end
+%% @see ets:select_reverse/3
+
+-spec select_reverse(gen_ns(), gen_tab(), match_spec(), limit()) -> {[match()], cont() | '$end_of_table'} | '$end_of_table'.
+select_reverse(NS, Tab, Spec, Limit) ->
+ case check_access(NS, Tab) of
+ undefined ->
+ erlang:error(badarg, [NS, Tab]);
+ Tid ->
+ wrap_cont_reply(Tid, gen_ets_lib:select_reverse(Tid, Spec, Limit))
+ end.
+
+%% @doc Continues a select reverse started with +select_reverse/3+.
+%% @end
+%% @see ets:select_reverse/1
+
+-spec select_reverse(gen_ns(), cont() | '$end_of_table') -> {[match()], cont() | '$end_of_table'} | '$end_of_table'.
+select_reverse(NS, {cont, Tab, Cont}) ->
+ case check_access(NS, Tab) of
+ undefined ->
+ erlang:error(badarg, [NS, Tab]);
+ Tid ->
+ wrap_cont_reply(Tid, gen_ets_lib:select_reverse(Cont))
+ end;
+select_reverse(_NS, '$end_of_table') ->
+ '$end_of_table'.
+
+%% @doc Returns a list of all objects in the table +Tab+. The
+%% operation is *not* guaranteed to be atomic and isolated.
+%% @end
+%% @see ets:tab2list/1
+
+-spec tab2list(gen_ns(), gen_tab()) -> [object()].
+tab2list(NS, Tab) ->
+ case check_access(NS, Tab) of
+ undefined ->
+ erlang:error(badarg, [NS, Tab]);
+ Tid ->
+ gen_ets_lib:tab2list(Tid)
+ end.
+
+%%%----------------------------------------------------------------------
+%%% Internal functions
+%%%----------------------------------------------------------------------
+
+-spec check_access(gen_ns(), gen_tab()) -> gen_tid() | undefined.
+check_access(NS, #gen_tid{impl=X, ns=Y})
+ when X =:= undefined; Y =/= NS ->
+ undefined;
+check_access(NS, #gen_tid{ns=NS, protection=Protection, owner=Owner}=Tid)
+ when Protection==public orelse Owner==self() ->
+ Tid;
+check_access(_NS, #gen_tid{}) ->
+ undefined;
+check_access(NS, Name) ->
+ case gen_ets_reg:lookup(NS, Name) of
+ undefined ->
+ undefined;
+ Tid ->
+ check_access(NS, Tid)
+ end.
+
+create(NS, Op, Name, Opts) ->
+ case options(Opts) of
+ {POpts, []} ->
+ POpts;
+ {POpts, BadArgs} ->
+ erlang:error(badarg, [NS, Name, BadArgs])
+ end,
+
+ Owner = self(),
+ NamedTable = proplists:get_bool(named_table, POpts),
+ Type =
+ case proplists:get_bool(ordered_set, POpts) of
+ true ->
+ ordered_set;
+ false ->
+ set
+ end,
+ KeyPos = proplists:get_value(keypos, POpts, 1),
+ Protection =
+ case proplists:get_bool(private, POpts) of
+ true ->
+ private;
+ false ->
+ case proplists:get_bool(protected, POpts) of
+ true ->
+ protected;
+ false ->
+ case proplists:get_bool(public, POpts) of
+ true ->
+ public;
+ false ->
+ protected
+ end
+ end
+ end,
+ Compressed = proplists:get_bool(compressed, POpts),
+ Async = proplists:get_bool(async, POpts),
+
+ {ImplMod, ImplOpts} = proplists:get_value(impl, POpts, {?DEFAULT_MOD, []}),
+ Tid = #gen_tid{owner=Owner,
+ name=Name,
+ named_table=NamedTable,
+ type=Type,
+ keypos=KeyPos,
+ protection=Protection,
+ compressed=Compressed,
+ async=Async,
+ ns=NS,
+ mod=ImplMod},
+
+ case gen_ets_reg:insert(Tid, Op, ImplOpts) of
+ undefined ->
+ erlang:error(badarg, [NS, Name, Opts]);
+ Ok ->
+ Ok
+ end.
+
+options(Options) ->
+ Keys = [set, ordered_set, named_table, keypos, public, protected, private, compressed, async, impl],
+ options(Options, Keys).
+
+options(Options, Keys) when is_list(Options) ->
+ options(Options, Keys, []);
+options(Option, Keys) ->
+ options([Option], Keys, []).
+
+options(Options, [Key|Keys], L) when is_list(Options) ->
+ case proplists:lookup(Key, Options) of
+ none ->
+ options(Options, Keys, L);
+ {Key, Value} ->
+ NewOptions = proplists:delete(Key, Options),
+ options(NewOptions, Keys, [{Key,Value}|L])
+ end;
+options(Options, [], L) ->
+ {lists:reverse(L), Options}.
+
+wrap_cont_reply(_Tid, '$end_of_table'=Reply) ->
+ Reply;
+wrap_cont_reply(_Tid, {_Match, '$end_of_table'}=Reply) ->
+ Reply;
+wrap_cont_reply(Tid, {_Match, Cont}=Reply) ->
+ setelement(2, Reply, {cont, Tid, Cont}).
View
232 src/gen_ets_reg.erl
@@ -0,0 +1,232 @@
+%%% The MIT License
+%%%
+%%% Copyright (C) 2011-2012 by Joseph Wayne Norton <norton@alum.mit.edu>
+%%%
+%%% Permission is hereby granted, free of charge, to any person obtaining a copy
+%%% of this software and associated documentation files (the "Software"), to deal
+%%% in the Software without restriction, including without limitation the rights
+%%% to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+%%% copies of the Software, and to permit persons to whom the Software is
+%%% furnished to do so, subject to the following conditions:
+%%%
+%%% The above copyright notice and this permission notice shall be included in
+%%% all copies or substantial portions of the Software.
+%%%
+%%% THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+%%% IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+%%% FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+%%% AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+%%% LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+%%% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+%%% THE SOFTWARE.
+
+-module(gen_ets_reg).
+
+-include("gen_ets.hrl").
+
+%% External exports
+-export([setup/1
+ , teardown/1
+ , list/1
+ , insert/3
+ , delete/1
+ , lookup/2
+ %% low-level API
+ , insert_new/3
+ , delete_object/2
+ ]).
+
+%%%----------------------------------------------------------------------
+%%% Types/Specs/Records
+%%%----------------------------------------------------------------------
+
+-record(gen_reg, {name :: gen_ets:name(), pid::pid(), tid :: #gen_tid{}}).
+
+%%%----------------------------------------------------------------------
+%%% API
+%%%----------------------------------------------------------------------
+
+setup(NS) ->
+ case ets:info(NS, name) of
+ undefined ->
+ Caller = self(),
+ Fun = fun() ->
+ register(NS, self()),
+ NS = ets:new(NS, [ordered_set, public, named_table, {keypos, #gen_reg.name}, {read_concurrency, true}]),
+ Caller ! {NS, self()},
+ receive
+ {NS, Pid, stop} ->
+ Pid ! {NS, self()}
+ end
+ end,
+
+ {Pid, Ref} = spawn_monitor(Fun),
+ try
+ receive
+ {NS, Pid} ->
+ ok;
+ {'DOWN', Ref, process, _Object, _Info} ->
+ ok
+ end
+ after
+ demonitor(Ref, [flush])
+ end;
+ _ ->
+ ok
+ end.
+
+teardown(NS) ->
+ case whereis(NS) of
+ undefined ->
+ ok;
+ Pid ->
+ Ref = monitor(process, Pid),
+ try
+ Pid ! {NS, self(), stop},
+ receive
+ {NS, Pid} ->
+ ok;
+ {'DOWN', Ref, process, _Object, _Info} ->
+ ok
+ end
+ after
+ demonitor(Ref, [flush])
+ end
+ end.
+
+list(NS) ->
+ setup(NS),
+ [ if Named -> Name; true -> Tid end
+ || #gen_reg{name=Name, tid=#gen_tid{named_table=Named}=Tid} <- ets:tab2list(NS) ].
+
+insert(#gen_tid{name=Name, named_table=Named, ns=NS}=PreTid, open=Op, Opts) ->
+ setup(NS),
+ case insert_new(NS, Name, PreTid) of
+ undefined ->
+ undefined;
+ PreReg ->
+ try
+ Parent = self(),
+ Fun = fun() -> loop(PreTid, Op, Opts, PreReg, Parent) end,
+
+ {Child, ChildRef} = spawn_monitor(Fun),
+ receive
+ {NS, Child, Tid} ->
+ if Named ->
+ Name;
+ true ->
+ Tid
+ end;
+ {'DOWN', ChildRef, process, _Object, _Info} ->
+ undefined
+ end
+ after
+ %% cleanup failures
+ catch delete_object(NS, PreReg)
+ end
+ end;
+insert(#gen_tid{name=Name, ns=NS}=PreTid, Op, Opts) ->
+ setup(NS),
+ case insert_new(NS, Name, PreTid) of
+ undefined ->
+ false;
+ PreReg ->
+ try
+ Parent = self(),
+ Fun = fun() -> once(PreTid, Op, Opts, Parent) end,
+
+ {Child, ChildRef} = spawn_monitor(Fun),
+ receive
+ {NS, Child, Reply} ->
+ Reply;
+ {'DOWN', ChildRef, process, _Object, _Info} ->
+ false
+ end
+ after
+ %% cleanup failures
+ catch delete_object(NS, PreReg)
+ end
+ end.
+
+delete(#gen_tid{name=Name, ns=NS}) ->
+ try
+ case ets:lookup(NS, Name) of
+ [#gen_reg{pid=undefined}] ->
+ false;
+ [#gen_reg{pid=Pid}] ->
+ Ref = monitor(process, Pid),
+ Pid ! {NS, stop},
+ try
+ receive
+ {'DOWN', Ref, process, _Object, _Info} ->
+ true
+ end
+ after
+ demonitor(Ref, [flush])
+ end;
+ [] ->
+ false
+ end
+ catch
+ error:badarg ->
+ false
+ end.
+
+lookup(NS, Name) ->
+ try
+ case ets:lookup(NS, Name) of
+ [#gen_reg{tid=undefined}] ->
+ undefined;
+ [#gen_reg{tid=Tid}] ->
+ Tid;
+ [] ->
+ undefined
+ end
+ catch
+ error:badarg ->
+ undefined
+ end.
+
+insert_new(NS, Name, Tid) ->
+ Reg = #gen_reg{name=Name, tid=Tid},
+ case ets:insert_new(NS, Reg) of
+ true ->
+ Reg;
+ false ->
+ undefined
+ end.
+
+delete_object(NS, Reg) ->
+ ets:delete_object(NS, Reg).
+
+%%%----------------------------------------------------------------------
+%%% Internal functions
+%%%----------------------------------------------------------------------
+
+loop(#gen_tid{ns=NS, mod=Mod}=PreTid, Op, Opts, PreReg, Parent) ->
+ ParentRef = monitor(process, Parent),
+
+ Impl = Mod:Op(PreTid, Opts),
+ Tid = PreTid#gen_tid{impl=Impl},
+ Reg = PreReg#gen_reg{pid=self(), tid=Tid},
+
+ ets:insert(NS, Reg),
+ try
+ Parent ! {NS, self(), Tid},
+ receive
+ {NS, stop} ->
+ ok;
+ {'DOWN', ParentRef, process, _Object, _Info} ->
+ ok
+ end,
+ %% delete
+ Mod:delete(Tid)
+ after
+ %% cleanup
+ delete_object(NS, Reg),
+ demonitor(ParentRef, [flush])
+ end.
+
+once(#gen_tid{ns=NS, mod=Mod}=PreTid, Op, Opts, Parent) ->
+ Reply = Mod:Op(PreTid, Opts),
+ Parent ! {NS, self(), Reply}.

0 comments on commit 9501436

Please sign in to comment.
Something went wrong with that request. Please try again.