Packages

Aerospike driver for Elixir with an OTP-native cluster runtime

Current section

Files

Jump to
aerospike_driver lib aerospike exp bit.ex
Raw

lib/aerospike/exp/bit.ex

defmodule Aerospike.Exp.Bit do
@moduledoc """
Bit expression helpers for blob expressions.
"""
alias Aerospike.Exp
alias Aerospike.Exp.Module
alias Aerospike.PolicyInteger
@typedoc "Opaque server-side expression."
@type t :: Exp.t()
@typedoc """
Bit expression modify options.
Supported keys:
* `:flags` - bit-operation write flags. Defaults to `:default`.
* `:overflow_action` - overflow behavior for `add/5` and `subtract/5`.
* `:signed` - when true, adds the signed flag to `:overflow_action`.
"""
@type opts :: [
flags: atom() | [atom()] | non_neg_integer() | {:raw, non_neg_integer()},
overflow_action: atom() | non_neg_integer() | {:raw, non_neg_integer()},
signed: boolean()
]
@resize 0
@insert 1
@remove 2
@set 3
@bw_or 4
@bw_xor 5
@bw_and 6
@bw_not 7
@lshift 8
@rshift 9
@add 10
@subtract 11
@set_int 12
@get 50
@count 51
@lscan 52
@rscan 53
@get_int 54
@doc "Resizes the blob expression to `byte_size` bytes using `resize_flags`."
@spec resize(
Exp.t(),
Exp.t(),
atom() | [atom()] | non_neg_integer() | {:raw, non_neg_integer()},
opts()
) :: t()
def resize(%Exp{} = bin, %Exp{} = byte_size, resize_flags \\ :default, opts \\ []) do
modify(bin, @resize, [byte_size, flags(opts), PolicyInteger.bit_resize_flags(resize_flags)])
end
@doc "Inserts a byte-string expression at `byte_offset`."
@spec insert(Exp.t(), Exp.t(), Exp.t(), opts()) :: t()
def insert(%Exp{} = bin, %Exp{} = byte_offset, %Exp{} = value, opts \\ []) do
modify(bin, @insert, [byte_offset, value, flags(opts)])
end
@doc "Removes `byte_size` bytes starting at `byte_offset`."
@spec remove(Exp.t(), Exp.t(), Exp.t(), opts()) :: t()
def remove(%Exp{} = bin, %Exp{} = byte_offset, %Exp{} = byte_size, opts \\ []) do
modify(bin, @remove, [byte_offset, byte_size, flags(opts)])
end
@doc "Overwrites a bit range with bits from `value`."
@spec set(Exp.t(), Exp.t(), Exp.t(), Exp.t(), opts()) :: t()
def set(%Exp{} = bin, %Exp{} = bit_offset, %Exp{} = bit_size, %Exp{} = value, opts \\ []) do
modify(bin, @set, [bit_offset, bit_size, value, flags(opts)])
end
@doc "Applies bitwise OR of `value` into the selected bit range."
@spec bw_or(Exp.t(), Exp.t(), Exp.t(), Exp.t(), opts()) :: t()
def bw_or(%Exp{} = bin, %Exp{} = bit_offset, %Exp{} = bit_size, %Exp{} = value, opts \\ []) do
modify(bin, @bw_or, [bit_offset, bit_size, value, flags(opts)])
end
@doc "Applies bitwise XOR of `value` into the selected bit range."
@spec bw_xor(Exp.t(), Exp.t(), Exp.t(), Exp.t(), opts()) :: t()
def bw_xor(%Exp{} = bin, %Exp{} = bit_offset, %Exp{} = bit_size, %Exp{} = value, opts \\ []) do
modify(bin, @bw_xor, [bit_offset, bit_size, value, flags(opts)])
end
@doc "Applies bitwise AND of `value` into the selected bit range."
@spec bw_and(Exp.t(), Exp.t(), Exp.t(), Exp.t(), opts()) :: t()
def bw_and(%Exp{} = bin, %Exp{} = bit_offset, %Exp{} = bit_size, %Exp{} = value, opts \\ []) do
modify(bin, @bw_and, [bit_offset, bit_size, value, flags(opts)])
end
@doc "Inverts the selected bit range."
@spec bw_not(Exp.t(), Exp.t(), Exp.t(), opts()) :: t()
def bw_not(%Exp{} = bin, %Exp{} = bit_offset, %Exp{} = bit_size, opts \\ []) do
modify(bin, @bw_not, [bit_offset, bit_size, flags(opts)])
end
@doc "Left shifts the selected bit range by `shift` bits."
@spec lshift(Exp.t(), Exp.t(), Exp.t(), Exp.t(), opts()) :: t()
def lshift(%Exp{} = bin, %Exp{} = bit_offset, %Exp{} = bit_size, %Exp{} = shift, opts \\ []) do
modify(bin, @lshift, [bit_offset, bit_size, shift, flags(opts)])
end
@doc "Right shifts the selected bit range by `shift` bits."
@spec rshift(Exp.t(), Exp.t(), Exp.t(), Exp.t(), opts()) :: t()
def rshift(%Exp{} = bin, %Exp{} = bit_offset, %Exp{} = bit_size, %Exp{} = shift, opts \\ []) do
modify(bin, @rshift, [bit_offset, bit_size, shift, flags(opts)])
end
@doc """
Adds `value` to a sub-integer in the bitmap.
Supports `flags:`, `overflow_action:`, and `signed:`.
"""
@spec add(Exp.t(), Exp.t(), Exp.t(), Exp.t(), opts()) :: t()
def add(%Exp{} = bin, %Exp{} = bit_offset, %Exp{} = bit_size, %Exp{} = value, opts \\ []) do
modify(bin, @add, [bit_offset, bit_size, value, flags(opts), overflow_action(opts)])
end
@doc """
Subtracts `value` from a sub-integer in the bitmap.
Supports `flags:`, `overflow_action:`, and `signed:`.
"""
@spec subtract(Exp.t(), Exp.t(), Exp.t(), Exp.t(), opts()) :: t()
def subtract(%Exp{} = bin, %Exp{} = bit_offset, %Exp{} = bit_size, %Exp{} = value, opts \\ []) do
modify(bin, @subtract, [bit_offset, bit_size, value, flags(opts), overflow_action(opts)])
end
@doc "Writes integer `value` into the selected bit range."
@spec set_int(Exp.t(), Exp.t(), Exp.t(), Exp.t(), opts()) :: t()
def set_int(%Exp{} = bin, %Exp{} = bit_offset, %Exp{} = bit_size, %Exp{} = value, opts \\ []) do
modify(bin, @set_int, [bit_offset, bit_size, value, flags(opts)])
end
@doc "Returns the selected bits as a blob expression."
@spec get(Exp.t(), Exp.t(), Exp.t()) :: t()
def get(%Exp{} = bin, %Exp{} = bit_offset, %Exp{} = bit_size) do
read(bin, :blob, @get, [bit_offset, bit_size])
end
@doc "Returns the count of bits set to `1` in the selected range."
@spec count(Exp.t(), Exp.t(), Exp.t()) :: t()
def count(%Exp{} = bin, %Exp{} = bit_offset, %Exp{} = bit_size) do
read(bin, :int, @count, [bit_offset, bit_size])
end
@doc "Returns the offset of the first matching bit when scanning left to right."
@spec lscan(Exp.t(), Exp.t(), Exp.t(), Exp.t()) :: t()
def lscan(%Exp{} = bin, %Exp{} = bit_offset, %Exp{} = bit_size, %Exp{} = value) do
read(bin, :int, @lscan, [bit_offset, bit_size, value])
end
@doc "Returns the offset of the first matching bit when scanning right to left."
@spec rscan(Exp.t(), Exp.t(), Exp.t(), Exp.t()) :: t()
def rscan(%Exp{} = bin, %Exp{} = bit_offset, %Exp{} = bit_size, %Exp{} = value) do
read(bin, :int, @rscan, [bit_offset, bit_size, value])
end
@doc "Reads an integer from the selected bit range, optionally as signed."
@spec get_int(Exp.t(), Exp.t(), Exp.t(), boolean()) :: t()
def get_int(%Exp{} = bin, %Exp{} = bit_offset, %Exp{} = bit_size, signed \\ false) do
args =
if signed do
[bit_offset, bit_size, PolicyInteger.bit_signed_flag()]
else
[bit_offset, bit_size]
end
read(bin, :int, @get_int, args)
end
defp read(bin, type, op_code, args), do: Module.bit_read(bin, type, op_code, args)
defp modify(bin, op_code, args), do: Module.bit_modify(bin, op_code, args)
defp flags(opts), do: opts |> Keyword.get(:flags, :default) |> PolicyInteger.bit_write_flags()
defp overflow_action(opts),
do:
PolicyInteger.bit_overflow_action(
Keyword.get(opts, :overflow_action, :default),
signed?(opts)
)
defp signed?(opts), do: Keyword.get(opts, :signed, false) == true
end