Skip to content
Browse files

add batch operation support

  • Loading branch information...
1 parent 1f03046 commit c4f8083392f1c546e07608689ea17704bb2a7081 @etrepum etrepum committed
Showing with 38 additions and 14 deletions.
  1. +2 −1 README.md
  2. +36 −13 src/statebox.erl
View
3 README.md
@@ -29,7 +29,8 @@ resolved in a deterministic manner.
An `op()` is a `{fun(), [term()]}`, with all but the last argument specified
in the term list. For example `{ordsets:add_element/2, [a]}`. To evaluate
this op, `ordsets:add_element(a, value(Statebox))` will be called. It is also
-possible to specify an `op()` as a `{module(), atom(), [term()]}` tuple.
+possible to specify an `op()` as a `{module(), atom(), [term()]}` tuple, or
+as a list of `op()` when performing several operations at the same timestamp.
There are several important limitations on the kinds of `op()` that are safe
to use (`{F, [Arg]}` is the example `op()` used below):
View
49 src/statebox.erl
@@ -24,8 +24,9 @@
-type event() :: {timestamp(), op()}.
-type timestamp() :: integer().
-type timedelta() :: integer().
--type op() :: {module(), atom(), [term()]} |
- {fun((...) -> statebox()), [term()]}.
+-type basic_op() :: {module(), atom(), [term()]} |
+ {fun((...) -> statebox()), [term()]}.
+-type op() :: basic_op() | [op()].
%% Used in a test, must be done before function definitions.
-ifdef(TEST).
@@ -108,8 +109,7 @@ merge(Unordered) ->
-spec modify(timestamp(), op(), statebox()) -> statebox().
modify(T, Op, #statebox{value=Value, queue=Queue, last_modified=OldT})
when OldT =< T ->
- Event = {T, Op},
- new(T, apply_event(Event, Value), queue_in(Event, Queue));
+ new(T, apply_op(Op, Value), queue_in({T, Op}, Queue));
modify(T, _Op, #statebox{last_modified=OldT}) ->
throw({invalid_timestamp, {T, '<', OldT}}).
@@ -142,21 +142,28 @@ new(T, V, Q) ->
queue_in(Event, Queue) ->
Queue ++ [Event].
-apply_queue(Data, Queue) ->
- lists:foldl(fun apply_event/2, Data, Queue).
+apply_queue(Data, [{_T, Op} | Rest]) ->
+ apply_queue(apply_op(Op, Data), Rest);
+apply_queue(Data, []) ->
+ Data.
-apply_event({_T, {F, [A]}}, Data) when is_function(F, 2) ->
+apply_op({F, [A]}, Data) when is_function(F, 2) ->
F(A, Data);
-apply_event({_T, {F, [A, B]}}, Data) when is_function(F, 3) ->
+apply_op({F, [A, B]}, Data) when is_function(F, 3) ->
F(A, B, Data);
-apply_event({_T, {F, A}}, Data) when is_function(F) ->
+apply_op({F, A}, Data) when is_function(F) ->
apply(F, A ++ [Data]);
-apply_event({_T, {M, F, [A]}}, Data) ->
+apply_op({M, F, [A]}, Data) ->
M:F(A, Data);
-apply_event({_T, {M, F, [A, B]}}, Data) ->
+apply_op({M, F, [A, B]}, Data) ->
M:F(A, B, Data);
-apply_event({_T, {M, F, A}}, Data) ->
- apply(M, F, A ++ [Data]).
+apply_op({M, F, A}, Data) ->
+ apply(M, F, A ++ [Data]);
+apply_op([Op | Rest], Data) ->
+ apply_op(Rest, apply_op(Op, Data));
+apply_op([], Data) ->
+ Data.
+
-ifdef(TEST).
-include_lib("eunit/include/eunit.hrl").
@@ -202,6 +209,22 @@ bad_modify_test() ->
dummy_mfa_4(a, b, C, D) ->
ordsets:add_element(C, D).
+batch_apply_op_test() ->
+ S = new(0, fun () -> [] end),
+ S0 = modify([], S),
+ S1 = modify([{ordsets, add_element, [N]} || N <- lists:seq(1, 1)], S),
+ S10 = modify([{ordsets, add_element, [N]} || N <- lists:seq(1, 10)], S),
+ ?assertEqual(
+ [],
+ value(S0)),
+ ?assertEqual(
+ lists:seq(1, 1),
+ value(S1)),
+ ?assertEqual(
+ lists:seq(1, 10),
+ value(S10)),
+ ok.
+
alt_apply_op_test() ->
L = [fun (N=1) -> {ordsets, add_element, [N]} end,
fun (N=2) ->

0 comments on commit c4f8083

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