@@ -100,9 +100,7 @@ defmodule Abit do
100100 defp do_union ( ref_a , _ , 0 ) , do: ref_a
101101
102102 defp do_union ( ref_a , ref_b , index ) do
103- unioned_value = :atomics . get ( ref_a , index ) ||| :atomics . get ( ref_b , index )
104-
105- :atomics . put ( ref_a , index , unioned_value )
103+ update_atomic ( ref_a , ref_b , index , :union )
106104
107105 do_union ( ref_a , ref_b , index - 1 )
108106 end
@@ -124,9 +122,7 @@ defmodule Abit do
124122 defp do_intersect ( ref_a , _ , 0 ) , do: ref_a
125123
126124 defp do_intersect ( ref_a , ref_b , index ) do
127- intersected_value = :atomics . get ( ref_a , index ) &&& :atomics . get ( ref_b , index )
128-
129- :atomics . put ( ref_a , index , intersected_value )
125+ update_atomic ( ref_a , ref_b , index , :intersect )
130126
131127 do_intersect ( ref_a , ref_b , index - 1 )
132128 end
@@ -150,9 +146,7 @@ defmodule Abit do
150146 defp do_difference ( ref_a , _ , 0 ) , do: ref_a
151147
152148 defp do_difference ( ref_a , ref_b , index ) do
153- diff_value = :atomics . get ( ref_a , index ) &&& bnot ( :atomics . get ( ref_b , index ) )
154-
155- :atomics . put ( ref_a , index , diff_value )
149+ update_atomic ( ref_a , ref_b , index , :difference )
156150
157151 do_difference ( ref_a , ref_b , index - 1 )
158152 end
@@ -175,13 +169,35 @@ defmodule Abit do
175169 defp do_symmetric_difference ( ref_a , _ , 0 ) , do: ref_a
176170
177171 defp do_symmetric_difference ( ref_a , ref_b , index ) do
178- xor_value = :atomics . get ( ref_a , index ) |> bxor ( :atomics . get ( ref_b , index ) )
179-
180- :atomics . put ( ref_a , index , xor_value )
172+ update_atomic ( ref_a , ref_b , index , :symmetric_difference )
181173
182174 do_symmetric_difference ( ref_a , ref_b , index - 1 )
183175 end
184176
177+ defp update_atomic ( ref_a , ref_b , index , operation ) do
178+ current_value = :atomics . get ( ref_a , index )
179+
180+ do_update_atomic ( ref_a , ref_b , index , operation , current_value )
181+ end
182+
183+ defp do_update_atomic ( ref_a , ref_b , index , operation , current_value ) do
184+ other_value = :atomics . get ( ref_b , index )
185+ next_value = apply_bitwise_operation ( operation , current_value , other_value )
186+
187+ case :atomics . compare_exchange ( ref_a , index , current_value , next_value ) do
188+ :ok ->
189+ :ok
190+
191+ new_current_value ->
192+ do_update_atomic ( ref_a , ref_b , index , operation , new_current_value )
193+ end
194+ end
195+
196+ defp apply_bitwise_operation ( :union , left , right ) , do: left ||| right
197+ defp apply_bitwise_operation ( :intersect , left , right ) , do: left &&& right
198+ defp apply_bitwise_operation ( :difference , left , right ) , do: left &&& bnot ( right )
199+ defp apply_bitwise_operation ( :symmetric_difference , left , right ) , do: bxor ( left , right )
200+
185201 @ doc """
186202 Inverts all bits in the signed atomics reference `ref` using bitwise NOT.
187203
0 commit comments