203 lines
3.7 KiB
Elixir
203 lines
3.7 KiB
Elixir
defmodule Bitwise do
|
|
@moduledoc """
|
|
This module provides macro-based operators that perform calculations
|
|
on (sets of) bits. These macros can be used in guards. In general,
|
|
you should `use` the Bitwise module as a whole:
|
|
|
|
iex> use Bitwise
|
|
iex> bnot 1
|
|
-2
|
|
iex> 1 &&& 1
|
|
1
|
|
|
|
Alternatively, you can include or skip selected operators:
|
|
|
|
iex> use Bitwise, only_operators: true
|
|
iex> 1 &&& 1
|
|
1
|
|
|
|
"""
|
|
|
|
@doc """
|
|
Allows a developer to `use` this module in their programs with
|
|
the following options:
|
|
|
|
* `:only_operators` - include only operators
|
|
* `:skip_operators` - skip operators
|
|
|
|
"""
|
|
defmacro __using__(options) do
|
|
except = cond do
|
|
Keyword.get(options, :only_operators) ->
|
|
[bnot: 1, band: 2, bor: 2, bxor: 2, bsl: 2, bsr: 2]
|
|
Keyword.get(options, :skip_operators) ->
|
|
[~~~: 1, &&&: 2, |||: 2, ^^^: 2, <<<: 2, >>>: 2]
|
|
true -> []
|
|
end
|
|
|
|
quote do
|
|
import Bitwise, except: unquote(except)
|
|
end
|
|
end
|
|
|
|
@doc """
|
|
Calculates the bitwise NOT of its argument.
|
|
|
|
iex> bnot(2)
|
|
-3
|
|
iex> bnot(2) &&& 3
|
|
1
|
|
|
|
"""
|
|
defmacro bnot(expr) do
|
|
quote do: :erlang.bnot(unquote(expr))
|
|
end
|
|
|
|
@doc """
|
|
Prefix (unary) operator; calculates the bitwise NOT of its argument.
|
|
|
|
iex> ~~~2
|
|
-3
|
|
iex> ~~~2 &&& 3
|
|
1
|
|
|
|
"""
|
|
defmacro ~~~expr do
|
|
quote do: :erlang.bnot(unquote(expr))
|
|
end
|
|
|
|
@doc """
|
|
Calculates the bitwise AND of its arguments.
|
|
|
|
iex> band(9, 3)
|
|
1
|
|
|
|
"""
|
|
defmacro band(left, right) do
|
|
quote do: :erlang.band(unquote(left), unquote(right))
|
|
end
|
|
|
|
@doc """
|
|
Infix operator; calculates the bitwise AND of its arguments.
|
|
|
|
iex> 9 &&& 3
|
|
1
|
|
|
|
"""
|
|
defmacro left &&& right do
|
|
quote do: :erlang.band(unquote(left), unquote(right))
|
|
end
|
|
|
|
@doc """
|
|
Calculates the bitwise OR of its arguments.
|
|
|
|
iex> bor(9, 3)
|
|
11
|
|
|
|
"""
|
|
defmacro bor(left, right) do
|
|
quote do: :erlang.bor(unquote(left), unquote(right))
|
|
end
|
|
|
|
@doc """
|
|
Infix operator; calculates the bitwise OR of its arguments.
|
|
|
|
iex> 9 ||| 3
|
|
11
|
|
|
|
"""
|
|
defmacro left ||| right do
|
|
quote do: :erlang.bor(unquote(left), unquote(right))
|
|
end
|
|
|
|
@doc """
|
|
Calculates the bitwise XOR of its arguments.
|
|
|
|
iex> bxor(9, 3)
|
|
10
|
|
|
|
"""
|
|
defmacro bxor(left, right) do
|
|
quote do: :erlang.bxor(unquote(left), unquote(right))
|
|
end
|
|
|
|
@doc """
|
|
Infix operator; calculates the bitwise XOR of its arguments.
|
|
|
|
iex> 9 ^^^ 3
|
|
10
|
|
|
|
"""
|
|
defmacro left ^^^ right do
|
|
quote do: :erlang.bxor(unquote(left), unquote(right))
|
|
end
|
|
|
|
@doc """
|
|
Calculates the result of an arithmetic left bitshift.
|
|
|
|
iex> bsl(1, 2)
|
|
4
|
|
iex> bsl(1, -2)
|
|
0
|
|
iex> bsl(-1, 2)
|
|
-4
|
|
iex> bsl(-1, -2)
|
|
-1
|
|
|
|
"""
|
|
defmacro bsl(left, right) do
|
|
quote do: :erlang.bsl(unquote(left), unquote(right))
|
|
end
|
|
|
|
@doc """
|
|
Infix operator; calculates the result of an arithmetic left bitshift.
|
|
|
|
iex> 1 <<< 2
|
|
4
|
|
iex> 1 <<< -2
|
|
0
|
|
iex> -1 <<< 2
|
|
-4
|
|
iex> -1 <<< -2
|
|
-1
|
|
|
|
"""
|
|
defmacro left <<< right do
|
|
quote do: :erlang.bsl(unquote(left), unquote(right))
|
|
end
|
|
|
|
@doc """
|
|
Calculates the result of an arithmetic right bitshift.
|
|
|
|
iex> bsr(1, 2)
|
|
0
|
|
iex> bsr(1, -2)
|
|
4
|
|
iex> bsr(-1, 2)
|
|
-1
|
|
iex> bsr(-1, -2)
|
|
-4
|
|
|
|
"""
|
|
defmacro bsr(left, right) do
|
|
quote do: :erlang.bsr(unquote(left), unquote(right))
|
|
end
|
|
|
|
@doc """
|
|
Infix operator; calculates the result of an arithmetic left bitshift.
|
|
|
|
iex> 1 >>> 2
|
|
0
|
|
iex> 1 >>> -2
|
|
4
|
|
iex> -1 >>> 2
|
|
-1
|
|
iex> -1 >>> -2
|
|
-4
|
|
|
|
"""
|
|
defmacro left >>> right do
|
|
quote do: :erlang.bsr(unquote(left), unquote(right))
|
|
end
|
|
end
|