Skip to content

Instantly share code, notes, and snippets.

@andrzejsliwa
Forked from ngerakines/memoize.erl
Created August 14, 2011 00:16
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save andrzejsliwa/1144411 to your computer and use it in GitHub Desktop.
Save andrzejsliwa/1144411 to your computer and use it in GitHub Desktop.
A small module to provide memoize functions in Erlang.
%% Copyright (c) 2008 Nick Gerakines <nick@gerakines.net>
%%
%% 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.
%%
%% @author Nick Gerakines <nick@gerakines.net>
%% @copyright 2008 Nick Gerakines
%% @version 0.1
%% @doc A simple memoize gen_server.
-module(memoize).
-behaviour(gen_server).
-export([memoize/2, start/0]).
-export([
init/1, terminate/2, code_change/3,
handle_call/3, handle_cast/2, handle_info/2
]).
%% @doc the public interface to this module.
memoize(Fun, Args) -> gen_server:call(?MODULE, {Fun, Args}, infinity).
start() -> gen_server:start_link({local, ?MODULE}, ?MODULE, [], []).
init(_) -> {ok, gb_trees:empty()}.
handle_call({Fun, Args}, _From, State) ->
FunSig = hash(Fun, Args),
{Resp, NewState} = case gb_trees:lookup(FunSig, State) of
{value, Value} -> {Value, State};
none ->
NewResp = apply(Fun, Args),
SavedState = gb_trees:enter(FunSig, NewResp, State),
{NewResp, SavedState}
end,
{reply, Resp, NewState};
handle_call(stop, _From, State) -> {stop, normalStop, State};
handle_call(_, _From, State) -> {reply, error, State}.
handle_cast(_Msg, State) -> {noreply, State}.
handle_info(_Info, State) -> {noreply, State}.
terminate(_Reason, _State) -> ok.
code_change(_OldVsn, State, _Extra) -> {ok, State}.
%% @doc Create a hash based on a mfa and it's arguments.
hash(Fun, Args) ->
{module, Module} = erlang:fun_info(Fun, module),
{name, Name} = erlang:fun_info(Fun, name),
{arity, Arity} = erlang:fun_info(Fun, arity),
erlang:md5(erlang:term_to_binary({Module, Name, Arity, Args})).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment