Subversion Repositories SE.SVN

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
12 7u83 1
%% @author Bob Ippolito <bob@mochimedia.com>
2
%% @copyright 2010 Mochi Media, Inc.
3
%%
4
%% Permission is hereby granted, free of charge, to any person obtaining a
5
%% copy of this software and associated documentation files (the "Software"),
6
%% to deal in the Software without restriction, including without limitation
7
%% the rights to use, copy, modify, merge, publish, distribute, sublicense,
8
%% and/or sell copies of the Software, and to permit persons to whom the
9
%% Software is furnished to do so, subject to the following conditions:
10
%%
11
%% The above copyright notice and this permission notice shall be included in
12
%% all copies or substantial portions of the Software.
13
%%
14
%% THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
%% IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16
%% FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17
%% THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18
%% LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19
%% FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
20
%% DEALINGS IN THE SOFTWARE.
21
 
22
 
23
%% @doc Abuse module constant pools as a "read-only shared heap" (since erts 5.6)
24
%%      <a href="http://www.erlang.org/pipermail/erlang-questions/2009-March/042503.html">[1]</a>.
25
-module(mochiglobal).
26
-author("Bob Ippolito <bob@mochimedia.com>").
27
-export([get/1, get/2, put/2, delete/1]).
28
 
29
-spec get(atom()) -> any() | undefined.
30
%% @equiv get(K, undefined)
31
get(K) ->
32
    get(K, undefined).
33
 
34
-spec get(atom(), T) -> any() | T.
35
%% @doc Get the term for K or return Default.
36
get(K, Default) ->
37
    get(K, Default, key_to_module(K)).
38
 
39
get(_K, Default, Mod) ->
40
    try Mod:term()
41
    catch error:undef ->
42
            Default
43
    end.
44
 
45
-spec put(atom(), any()) -> ok.
46
%% @doc Store term V at K, replaces an existing term if present.
47
put(K, V) ->
48
    put(K, V, key_to_module(K)).
49
 
50
put(_K, V, Mod) ->
51
    Bin = compile(Mod, V),
52
    code:purge(Mod),
53
    {module, Mod} = code:load_binary(Mod, atom_to_list(Mod) ++ ".erl", Bin),
54
    ok.
55
 
56
-spec delete(atom()) -> boolean().
57
%% @doc Delete term stored at K, no-op if non-existent.
58
delete(K) ->
59
    delete(K, key_to_module(K)).
60
 
61
delete(_K, Mod) ->
62
    code:purge(Mod),
63
    code:delete(Mod).
64
 
65
-spec key_to_module(atom()) -> atom().
66
key_to_module(K) ->
67
    list_to_atom("mochiglobal:" ++ atom_to_list(K)).
68
 
69
-spec compile(atom(), any()) -> binary().
70
compile(Module, T) ->
71
    {ok, Module, Bin} = compile:forms(forms(Module, T),
72
                                      [verbose, report_errors]),
73
    Bin.
74
 
75
-spec forms(atom(), any()) -> [erl_syntax:syntaxTree()].
76
forms(Module, T) ->
77
    [erl_syntax:revert(X) || X <- term_to_abstract(Module, term, T)].
78
 
79
-spec term_to_abstract(atom(), atom(), any()) -> [erl_syntax:syntaxTree()].
80
term_to_abstract(Module, Getter, T) ->
81
    [%% -module(Module).
82
     erl_syntax:attribute(
83
       erl_syntax:atom(module),
84
       [erl_syntax:atom(Module)]),
85
     %% -export([Getter/0]).
86
     erl_syntax:attribute(
87
       erl_syntax:atom(export),
88
       [erl_syntax:list(
89
         [erl_syntax:arity_qualifier(
90
            erl_syntax:atom(Getter),
91
            erl_syntax:integer(0))])]),
92
     %% Getter() -> T.
93
     erl_syntax:function(
94
       erl_syntax:atom(Getter),
95
       [erl_syntax:clause([], none, [erl_syntax:abstract(T)])])].
96
 
97
%%
98
%% Tests
99
%%
100
-ifdef(TEST).
101
-include_lib("eunit/include/eunit.hrl").
102
get_put_delete_test() ->
103
    K = '$$test$$mochiglobal',
104
    delete(K),
105
    ?assertEqual(
106
       bar,
107
       get(K, bar)),
108
    try
109
        ?MODULE:put(K, baz),
110
        ?assertEqual(
111
           baz,
112
           get(K, bar)),
113
        ?MODULE:put(K, wibble),
114
        ?assertEqual(
115
           wibble,
116
           ?MODULE:get(K))
117
    after
118
        delete(K)
119
    end,
120
    ?assertEqual(
121
       bar,
122
       get(K, bar)),
123
    ?assertEqual(
124
       undefined,
125
       ?MODULE:get(K)),
126
    ok.
127
-endif.