3939 min /1 ,
4040 conc /2 ]).
4141
42-
4342-type actor () :: any ().
44- -type vectorclock () :: dict : dict ( actor (), non_neg_integer ()) .
43+ -type vectorclock () :: #{ actor () => non_neg_integer ()} .
4544-export_type ([vectorclock / 0 ]).
4645
4746-spec new () -> vectorclock ().
4847new () ->
49- dict :new ().
48+ maps :new ().
5049
5150-spec get_clock_of_dc (any (), vectorclock ()) -> non_neg_integer ().
5251get_clock_of_dc (Key , VectorClock ) ->
53- case dict :find (Key , VectorClock ) of
54- {ok , Value } -> Value ;
55- error -> 0
56- end .
52+ maps :get (Key , VectorClock , 0 ).
5753
5854-spec set_clock_of_dc (any (), non_neg_integer (), vectorclock ()) -> vectorclock ().
5955set_clock_of_dc (Key , Value , VectorClock ) ->
60- dict : store ( Key , Value , VectorClock ) .
56+ VectorClock #{ Key => Value } .
6157
6258-spec from_list ([{any (), non_neg_integer ()}]) -> vectorclock ().
6359from_list (List ) ->
64- dict :from_list (List ).
60+ maps :from_list (List ).
6561
6662-spec max ([vectorclock ()]) -> vectorclock ().
6763max ([]) -> new ();
6864max ([V ]) -> V ;
69- max ([V1 , V2 |T ]) -> max ([merge (fun erlang :max /2 , V1 , V2 )|T ]).
65+ max ([V1 , V2 |T ]) -> max ([max2 (V1 , V2 )|T ]).
66+
67+ % % component-wise maximum of two clocks
68+ -spec max2 (vectorclock (), vectorclock ()) -> vectorclock ().
69+ max2 (V1 , V2 ) ->
70+ FoldFun =
71+ fun (DC , A , Acc ) ->
72+ B = get_clock_of_dc (DC , Acc ),
73+ case A > B of
74+ true -> Acc #{DC => A };
75+ false -> Acc
76+ end
77+ end ,
78+ maps :fold (FoldFun , V2 , V1 ).
7079
7180-spec min ([vectorclock ()]) -> vectorclock ().
7281min ([]) -> new ();
@@ -75,7 +84,7 @@ min([V1, V2|T]) -> min([merge(fun erlang:min/2, V1, V2)|T]).
7584
7685-spec merge (fun ((non_neg_integer (), non_neg_integer ()) -> non_neg_integer ()), vectorclock (), vectorclock ()) -> vectorclock ().
7786merge (F , V1 , V2 ) ->
78- AllDCs = dict : fetch_keys ( V1 ) ++ dict : fetch_keys ( V2 ),
87+ AllDCs = maps : keys ( maps : merge ( V1 , V2 ) ),
7988 Func = fun (DC ) ->
8089 A = get_clock_of_dc (DC , V1 ),
8190 B = get_clock_of_dc (DC , V2 ),
@@ -85,8 +94,7 @@ merge(F, V1, V2) ->
8594
8695-spec for_all_keys (fun ((non_neg_integer (), non_neg_integer ()) -> boolean ()), vectorclock (), vectorclock ()) -> boolean ().
8796for_all_keys (F , V1 , V2 ) ->
88- % % We could but do not care about duplicate DC keys - finding duplicates is not worth the effort
89- AllDCs = dict :fetch_keys (V1 ) ++ dict :fetch_keys (V2 ),
97+ AllDCs = maps :keys (maps :merge (V1 , V2 )),
9098 Func = fun (DC ) ->
9199 A = get_clock_of_dc (DC , V1 ),
92100 B = get_clock_of_dc (DC , V2 ),
@@ -95,13 +103,23 @@ for_all_keys(F, V1, V2) ->
95103 lists :all (Func , AllDCs ).
96104
97105-spec eq (vectorclock (), vectorclock ()) -> boolean ().
98- eq (V1 , V2 ) -> for_all_keys ( fun ( A , B ) -> A == B end , V1 , V2 ).
106+ eq (V1 , V2 ) -> le ( V1 , V2 ) andalso le ( V2 , V1 ).
99107
100108-spec le (vectorclock (), vectorclock ()) -> boolean ().
101- le (V1 , V2 ) -> for_all_keys (fun (A , B ) -> A =< B end , V1 , V2 ).
109+ le (V1 , V2 ) ->
110+ try
111+ maps :fold (fun (DC , V , true ) ->
112+ case V =< get_clock_of_dc (DC , V2 ) of
113+ true -> true ;
114+ false -> throw (false )
115+ end
116+ end , true , V1 )
117+ catch
118+ false -> false
119+ end .
102120
103121-spec ge (vectorclock (), vectorclock ()) -> boolean ().
104- ge (V1 , V2 ) -> for_all_keys ( fun ( A , B ) -> A >= B end , V1 , V2 ).
122+ ge (V1 , V2 ) -> le ( V2 , V1 ).
105123
106124-spec all_dots_smaller (vectorclock (), vectorclock ()) -> boolean ().
107125all_dots_smaller (V1 , V2 ) -> for_all_keys (fun (A , B ) -> A < B end , V1 , V2 ).
@@ -110,16 +128,41 @@ all_dots_smaller(V1, V2) -> for_all_keys(fun(A, B) -> A < B end, V1, V2).
110128all_dots_greater (V1 , V2 ) -> for_all_keys (fun (A , B ) -> A > B end , V1 , V2 ).
111129
112130-spec gt (vectorclock (), vectorclock ()) -> boolean ().
113- gt (V1 , V2 ) -> ge ( V1 , V2 ) and ( not eq ( V1 , V2 ) ).
131+ gt (V1 , V2 ) -> lt ( V2 , V1 ).
114132
115133-spec lt (vectorclock (), vectorclock ()) -> boolean ().
116- lt (V1 , V2 ) -> le (V1 , V2 ) and (not eq (V1 , V2 )).
134+ lt (V1 , V2 ) ->
135+ try
136+ maps :fold (fun (DC , V , Acc ) ->
137+ X = get_clock_of_dc (DC , V2 ),
138+ case V =< X of
139+ true -> Acc orelse V < X ;
140+ false -> throw (false )
141+ end
142+ end , false , V1 )
143+ orelse
144+ maps :fold (fun (DC , V , _ ) ->
145+ X = get_clock_of_dc (DC , V1 ),
146+ case V > X of
147+ true -> throw (true );
148+ false -> false
149+ end
150+ end , false , V2 )
151+ catch
152+ R -> R
153+ end .
117154
118155-spec conc (vectorclock (), vectorclock ()) -> boolean ().
119156conc (V1 , V2 ) -> (not ge (V1 , V2 )) andalso (not le (V1 , V2 )).
120157
121158-ifdef (TEST ).
122159
160+ vectorclock_empty_test () ->
161+ V1 = vectorclock :new (),
162+ V2 = vectorclock :from_list ([]),
163+ ? assertEqual (V1 , V2 ),
164+ ? assertEqual (eq (vectorclock :min ([]), vectorclock :max ([])), true ).
165+
123166vectorclock_test () ->
124167 V1 = vectorclock :from_list ([{1 , 5 }, {2 , 4 }, {3 , 5 }, {4 , 6 }]),
125168 V2 = vectorclock :from_list ([{1 , 4 }, {2 , 3 }, {3 , 4 }, {4 , 5 }]),
@@ -136,6 +179,11 @@ vectorclock_test() ->
136179 ? assertEqual (eq (V1 , V4 ), false ),
137180 ? assertEqual (ge (V1 , V5 ), false ).
138181
182+ vectorclock_lt_test () ->
183+ ? assertEqual (lt (from_list ([{a , 1 }]), from_list ([{a , 1 }, {b , 1 }])), true ),
184+ ? assertEqual (lt (from_list ([{a , 1 }]), from_list ([{a , 1 }])), false ),
185+ ? assertEqual (lt (from_list ([{a , 2 }]), from_list ([{a , 1 }])), false ).
186+
139187vectorclock_max_test () ->
140188 V1 = vectorclock :from_list ([{1 , 5 }, {2 , 4 }]),
141189 V2 = vectorclock :from_list ([{1 , 6 }, {2 , 3 }]),
@@ -153,7 +201,6 @@ vectorclock_max_test() ->
153201 ? assertEqual (eq (max ([V1 , V2 , V3 ]), Expected123 ), true ),
154202 ? assertEqual (eq (max ([V1 , V2 , V3 ]), Unexpected123 ), false ).
155203
156-
157204vectorclock_min_test () ->
158205 V1 = vectorclock :from_list ([{1 , 5 }, {2 , 4 }]),
159206 V2 = vectorclock :from_list ([{1 , 6 }, {2 , 3 }]),
@@ -169,7 +216,8 @@ vectorclock_min_test() ->
169216 ? assertEqual (eq (min ([V2 , V3 ]), Expected23 ), true ),
170217 ? assertEqual (eq (min ([V1 , V3 ]), Expected13 ), true ),
171218 ? assertEqual (eq (min ([V1 , V2 , V3 ]), Expected123 ), true ),
172- ? assertEqual (eq (min ([V1 , V2 , V3 ]), Unexpected123 ), false ).
219+ ? assertEqual (eq (min ([V1 , V2 , V3 ]), Unexpected123 ), false ),
220+ ? assertEqual (eq (vectorclock :min ([V1 ]), vectorclock :max ([V1 ])), true ).
173221
174222vectorclock_conc_test () ->
175223 V1 = vectorclock :from_list ([{1 , 5 }, {2 , 4 }]),
@@ -182,4 +230,13 @@ vectorclock_conc_test() ->
182230 ? assertEqual (conc (V2 , V3 ), true ),
183231 ? assertEqual (conc (V3 , V4 ), false ),
184232 ? assertEqual (conc (V5 , V4 ), false ).
233+
234+ vectorclock_set_test () ->
235+ V1 = vectorclock :from_list ([{1 , 1 }, {2 , 2 }]),
236+ V2 = vectorclock :from_list ([{1 , 1 }, {2 , 2 }, {3 , 3 }]),
237+ V3 = vectorclock :from_list ([{1 , 1 }, {2 , 4 }]),
238+
239+ ? assertEqual (eq (V2 , vectorclock :set_clock_of_dc (3 , 3 , V1 )), true ),
240+ ? assertEqual (eq (V3 , vectorclock :set_clock_of_dc (2 , 4 , V1 )), true ).
241+
185242-endif .
0 commit comments