Commit c1cea592 authored by benoît chesneau's avatar benoît chesneau

distinct add from add_with

we were trying to be too smart in checking if the value given was a
function or not in `lru:add/3` and `lru:contains_or_add/3` functions.
Instead we now have distinct `lru:add_with/3` and `lru:contains_or_add_with/3` to
pass a function.

fix #2
parent be2452de
Pipeline #4708891 passed with stage
in 51 seconds
...@@ -15,7 +15,9 @@ ...@@ -15,7 +15,9 @@
keys/1, keys/1,
peek/2, peek/3, peek/2, peek/3,
add/3, add/3,
add_with/3,
contains_or_add/3, contains_or_add/3,
contains_or_add_with/3,
remove/2, remove/2,
remove_oldest/1, remove_oldest/1,
purge/1, purge/1,
...@@ -52,6 +54,10 @@ ...@@ -52,6 +54,10 @@
-type cache() :: cache() | name(). -type cache() :: cache() | name().
-type callback() :: fun()
| {fun(), list()}
| {module(), fun(), list()}.
%%==================================================================== %%====================================================================
%% API functions %% API functions
%%==================================================================== %%====================================================================
...@@ -103,7 +109,7 @@ stop(Cache) -> ...@@ -103,7 +109,7 @@ stop(Cache) ->
end. end.
%% @doc adds a value to the cache. Returns true if an eviction occured. %% @doc adds a value to the cache. Returns true if an eviction occured.
-spec add(cache(), term(), term() | fun()) -> true | false. -spec add(cache(), term(), term()) -> true | false.
add(Cache, Key, Value) -> add(Cache, Key, Value) ->
Reply = call(Cache, {add, Key, Value}), Reply = call(Cache, {add, Key, Value}),
case Reply of case Reply of
...@@ -111,6 +117,14 @@ add(Cache, Key, Value) -> ...@@ -111,6 +117,14 @@ add(Cache, Key, Value) ->
_ -> Reply _ -> Reply
end. end.
%% @doc like add but with a callback
-spec add_with(cache(), term(), callback()) -> true | false.
add_with(Cache, Key, Callback) ->
Reply = call(Cache, {add_with, Key, Callback}),
case Reply of
{error, Error} -> erlang:error(Error);
_ -> Reply
end.
%% @doc lookup a key's value from the cache. Return undefined if it's not %% @doc lookup a key's value from the cache. Return undefined if it's not
%% found. %% found.
...@@ -150,7 +164,7 @@ keys(Cache) -> ...@@ -150,7 +164,7 @@ keys(Cache) ->
%% @doc checks if a key is in the cache (without updating the recent-ness or %% @doc checks if a key is in the cache (without updating the recent-ness or
%% deleting it for being stale), if not, adds the value. Returns whether found and whether an eviction %% deleting it for being stale), if not, adds the value. Returns whether found and whether an eviction
%% occurred. %% occurred.
-spec contains_or_add(cache(), term(), term() | fun()) -> -spec contains_or_add(cache(), term(), term()) ->
{Exists::boolean(), Evict::boolean()}. {Exists::boolean(), Evict::boolean()}.
contains_or_add(Cache, Key, Value) -> contains_or_add(Cache, Key, Value) ->
Reply = call(Cache, {contains_or_add, Key, Value}), Reply = call(Cache, {contains_or_add, Key, Value}),
...@@ -159,6 +173,18 @@ contains_or_add(Cache, Key, Value) -> ...@@ -159,6 +173,18 @@ contains_or_add(Cache, Key, Value) ->
_ -> Reply _ -> Reply
end. end.
%% @doc like contains_or_add but with a callback
-spec contains_or_add_with(cache(), term(), callback()) ->
{Exists::boolean(), Evict::boolean()}.
contains_or_add_with(Cache, Key, Callback) ->
Reply = call(Cache, {contains_or_add_with, Key, Callback}),
case Reply of
{error, Error} -> erlang:error(Error);
_ -> Reply
end.
%% @doc remove a key from the cache %% @doc remove a key from the cache
-spec remove(cache(), Key::term()) -> ok. -spec remove(cache(), Key::term()) -> ok.
remove(Cache, Key) -> remove(Cache, Key) ->
...@@ -229,7 +255,10 @@ init([Opts]) -> ...@@ -229,7 +255,10 @@ init([Opts]) ->
%% @private %% @private
handle_call({add, Key, Value}, From, Cache) -> handle_call({add, Key, Value}, From, Cache) ->
case value(Value) of do_add(Key, Value, From, Cache);
handle_call({add_with, Key, Callback}, From, Cache) ->
case value(Callback) of
{ok, Value2} -> {ok, Value2} ->
do_add(Key, Value2, From, Cache); do_add(Key, Value2, From, Cache);
Error -> Error ->
...@@ -252,7 +281,10 @@ handle_call({contains, Key}, _From, Cache) -> ...@@ -252,7 +281,10 @@ handle_call({contains, Key}, _From, Cache) ->
{reply, maps:is_key(Key, Cache#cache.items), Cache}; {reply, maps:is_key(Key, Cache#cache.items), Cache};
handle_call({contains_or_add, Key, Value}, From, Cache) -> handle_call({contains_or_add, Key, Value}, From, Cache) ->
case value(Value) of do_contains_or_add(Key, Value, From, Cache);
handle_call({contains_or_add_with, Key, Callback}, From, Cache) ->
case value(Callback) of
{ok, Value2} -> {ok, Value2} ->
do_contains_or_add(Key, Value2, From, Cache); do_contains_or_add(Key, Value2, From, Cache);
Error -> Error ->
...@@ -386,20 +418,20 @@ do_contains_or_add(Key, Value, From, Cache) -> ...@@ -386,20 +418,20 @@ do_contains_or_add(Key, Value, From, Cache) ->
{reply, {true, false}, Cache} {reply, {true, false}, Cache}
end. end.
value({M, F, A}) -> value({M, F, A}) when is_function(F) ->
case catch apply(M, F, A) of case catch apply(M, F, A) of
{'EXIT', Error} -> {error, Error}; {'EXIT', Error} -> {error, Error};
{ok, Val} -> {ok, Val}; {ok, Val} -> {ok, Val};
Val -> {ok, Val} Val -> {ok, Val}
end; end;
value({F, A}) -> value({F, A}) when is_function(F) ->
case catch apply(F, A) of case catch apply(F, A) of
{'EXIT', Error} -> {error, Error}; {'EXIT', Error} -> {error, Error};
{ok, Val} -> {ok, Val}; {ok, Val} -> {ok, Val};
Val -> {ok, Val} Val -> {ok, Val}
end; end;
value(Fun) when is_function(Fun) -> value(F) when is_function(F) ->
case catch Fun() of case catch F() of
{'EXIT', Error} -> {error, Error}; {'EXIT', Error} -> {error, Error};
{ok, Val} -> {ok, Val}; {ok, Val} -> {ok, Val};
Val -> {ok, Val} Val -> {ok, Val}
...@@ -546,10 +578,10 @@ lru_add_test() -> ...@@ -546,10 +578,10 @@ lru_add_test() ->
lru_add_fun_test() -> lru_add_fun_test() ->
{ok, Cache} = lru:start_link([{max_objs, 2}]), {ok, Cache} = lru:start_link([{max_objs, 2}]),
lru:add(Cache, 1, fun() -> 1 end), lru:add_with(Cache, 1, fun() -> 1 end),
?assert(lru:get(Cache, 1) =:= 1), ?assert(lru:get(Cache, 1) =:= 1),
lru:add(Cache, 2, fun() -> {ok, 2} end), lru:add_with(Cache, 2, fun() -> {ok, 2} end),
lru:add(Cache, 2, fun() -> 2 end), lru:add_with(Cache, 2, fun() -> 2 end),
lru:stop(Cache), lru:stop(Cache),
ok. ok.
...@@ -576,11 +608,11 @@ lru_contains_or_add_test() -> ...@@ -576,11 +608,11 @@ lru_contains_or_add_test() ->
lru_contains_or_add_with_fun_test() -> lru_contains_or_add_with_fun_test() ->
{ok, Cache} = lru:start_link([{max_objs, 2}]), {ok, Cache} = lru:start_link([{max_objs, 2}]),
lru:add(Cache, 1, fun() -> 1 end), lru:add(Cache, 1, 1),
lru:add(Cache, 2, fun() -> 2 end), lru:add(Cache, 2, 2),
?assertEqual(lru:contains_or_add(Cache, 1, 1), {true, false}), ?assertEqual(lru:contains_or_add_with(Cache, 1, fun() -> 1 end), {true, false}),
lru:add(Cache, 3, fun() -> 3 end), lru:add(Cache, 3, 3),
?assertEqual(lru:contains_or_add(Cache, 1, 1), {false, true}), ?assertEqual(lru:contains_or_add_with(Cache, 1, fun() -> 1 end), {false, true}),
?assert(lru:contains(Cache, 1)), ?assert(lru:contains(Cache, 1)),
lru:stop(Cache), lru:stop(Cache),
ok. ok.
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment