Skip to content

Commit 4693b0b

Browse files
committed
Refactor counter bit operations
1 parent ad3a103 commit 4693b0b

1 file changed

Lines changed: 29 additions & 70 deletions

File tree

lib/abit/counter.ex

Lines changed: 29 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,8 @@ defmodule Abit.Counter do
4545

4646
@bit_sizes [2, 4, 8, 16, 32]
4747

48+
import Bitwise
49+
4850
alias Abit.Counter
4951

5052
@keys [:atomics_ref, :signed, :wrap_around, :size, :counters_bit_size, :min, :max]
@@ -128,7 +130,7 @@ defmodule Abit.Counter do
128130

129131
atomics_value = :atomics.get(atomics_ref, atomics_index)
130132

131-
get_value(signed, counters_bit_size, bit_index, <<atomics_value::64>>)
133+
get_value(signed, counters_bit_size, bit_index, atomics_value)
132134
end
133135

134136
@doc """
@@ -179,8 +181,8 @@ defmodule Abit.Counter do
179181
bit_index,
180182
atomics_value
181183
) do
182-
{final_counter_value, <<next_atomics_value::64>>} =
183-
put_value(signed, counters_bit_size, bit_index, <<atomics_value::64>>, value)
184+
{final_counter_value, next_atomics_value} =
185+
put_value(signed, counters_bit_size, bit_index, atomics_value, value)
184186

185187
case :atomics.compare_exchange(
186188
atomics_ref,
@@ -231,7 +233,7 @@ defmodule Abit.Counter do
231233

232234
atomics_value = :atomics.get(atomics_ref, atomics_index)
233235

234-
current_value = get_value(signed, counters_bit_size, bit_index, <<atomics_value::64>>)
236+
current_value = get_value(signed, counters_bit_size, bit_index, atomics_value)
235237

236238
next_value = current_value + incr
237239

@@ -240,8 +242,8 @@ defmodule Abit.Counter do
240242
{:error, :value_out_of_bounds}
241243

242244
{_, _} ->
243-
{final_counter_value, <<next_atomics_value::64>>} =
244-
put_value(signed, counters_bit_size, bit_index, <<atomics_value::64>>, next_value)
245+
{final_counter_value, next_atomics_value} =
246+
put_value(signed, counters_bit_size, bit_index, atomics_value, next_value)
245247

246248
case :atomics.compare_exchange(
247249
atomics_ref,
@@ -409,71 +411,30 @@ defmodule Abit.Counter do
409411
end
410412
end
411413

412-
@bit_sizes
413-
|> Enum.each(fn counters_bit_size ->
414-
0..63
415-
|> Enum.filter(fn n -> rem(n, counters_bit_size) == 0 end)
416-
|> Enum.each(fn bit_index ->
417-
bit_left_start = bit_index + counters_bit_size
418-
left_bits = 64 - bit_left_start
419-
right_bits = bit_left_start - counters_bit_size
420-
421-
defp unquote(:get_value)(
422-
false,
423-
unquote(counters_bit_size),
424-
unquote(bit_index),
425-
<<_::unquote(left_bits), value::unquote(counters_bit_size), _::unquote(right_bits)>>
426-
) do
427-
value
428-
end
414+
defp get_value(signed, bit_size, bit_index, atomic) do
415+
value = atomic >>> bit_index &&& bit_mask(bit_size)
416+
decode_value(value, signed, bit_size)
417+
end
429418

430-
defp unquote(:get_value)(
431-
true,
432-
unquote(counters_bit_size),
433-
unquote(bit_index),
434-
<<_left::unquote(left_bits), value::unquote(counters_bit_size)-signed,
435-
_right::unquote(right_bits)>>
436-
) do
437-
value
438-
end
419+
defp put_value(signed, bit_size, bit_index, atomic, new_value) do
420+
mask = bit_mask(bit_size)
421+
encoded_value = new_value &&& mask
422+
shifted_mask = mask <<< bit_index
423+
next_atomic = (atomic &&& bnot(shifted_mask)) ||| encoded_value <<< bit_index
439424

440-
defp unquote(:put_value)(
441-
false,
442-
unquote(counters_bit_size),
443-
unquote(bit_index),
444-
<<left::unquote(left_bits), _current_value::unquote(counters_bit_size),
445-
right::unquote(right_bits)>>,
446-
new_value
447-
) do
448-
<<final_counter_value::unquote(counters_bit_size)>> =
449-
<<new_value::unquote(counters_bit_size)>>
450-
451-
{
452-
final_counter_value,
453-
<<left::unquote(left_bits), new_value::unquote(counters_bit_size),
454-
right::unquote(right_bits)>>
455-
}
456-
end
425+
{decode_value(encoded_value, signed, bit_size), next_atomic}
426+
end
457427

458-
defp unquote(:put_value)(
459-
true,
460-
unquote(counters_bit_size),
461-
unquote(bit_index),
462-
<<left::unquote(left_bits), _current_value::unquote(counters_bit_size)-signed,
463-
right::unquote(right_bits)>>,
464-
new_value
465-
) do
466-
<<final_counter_value::unquote(counters_bit_size)-signed>> =
467-
<<new_value::unquote(counters_bit_size)-signed>>
468-
469-
{
470-
final_counter_value,
471-
<<left::unquote(left_bits), new_value::unquote(counters_bit_size)-signed,
472-
right::unquote(right_bits)>>
473-
}
474-
end
475-
end)
476-
end)
428+
defp decode_value(value, false, _bit_size), do: value
429+
430+
defp decode_value(value, true, bit_size) do
431+
sign_bit = 1 <<< (bit_size - 1)
432+
if (value &&& sign_bit) == 0, do: value, else: value - (sign_bit <<< 1)
433+
end
434+
435+
for bit_size <- @bit_sizes do
436+
defp bit_mask(unquote(bit_size)), do: unquote((1 <<< bit_size) - 1)
437+
end
477438

478439
defp integer_to_counters(integer, signed, bit_size) do
479440
do_integer_to_counters(<<integer::64>>, signed, bit_size, [])
@@ -503,8 +464,6 @@ defmodule Abit.Counter do
503464

504465
# Returns the {min, max} counter range for the given signed flag and bit size.
505466
defp counter_range(signed, bit_size) do
506-
import Bitwise
507-
508467
case signed do
509468
false -> {0, (1 <<< bit_size) - 1}
510469
true -> {-(1 <<< (bit_size - 1)), (1 <<< (bit_size - 1)) - 1}

0 commit comments

Comments
 (0)