BitwiseIp.Blocks.member-question-mark
member-question-mark
, go back to BitwiseIp.Blocks module for more information.
Specs
member?(t(), BitwiseIp.t()) :: boolean()
member?(t(), :inet.ip_address()) :: boolean()
Efficiently checks if an IP address is a member of any of the blocks.
Libraries will generally handle IP addresses encoded as :inet
-style tuples
of integers. Therefore, in order to use BitwiseIp.Block.member?/2
, you'll
first need to use BitwiseIp.encode/1
to convert the tuple into an
integer-encoded struct.
A common mistake when handling a list of blocks is to do the bitwise IP encoding repeatedly within a loop:
# This is a mistake!
ip = {127, 0, 0, 1}
Enum.any?(blocks, &BitwiseIp.Block.member?(&1, BitwiseIp.encode(ip)))
The problem with the above is that the return value of BitwiseIp.encode(ip)
doesn't change as we iterate through the list. The cost of redundantly
encoding the same IP address over & over is often enough to outweigh any
performance gains from using the bitwise membership checks.
This function helps enforce a pattern where the encoding is only done once (essentially performing loop-invariant code motion). That is, it's akin to saying:
ip = {127, 0, 0, 1}
encoded = BitwiseIp.encode(ip) # this is only done once
Enum.any?(blocks, &BitwiseIp.Block.member?(&1, encoded))
This function also accepts an already-encoded BitwiseIp
struct as an
argument, in which case no extra encoding needs to be performed. This is
useful for cases where you need to perform even more loop-invariant code
motion, such as when you're handling two separate lists. In such a case, you
should use a pattern like:
# make sure to only encode the IP once
ip = {127, 0, 0, 1}
encoded = BitwiseIp.encode(ip)
BitwiseIp.Blocks.member?(blocks1, encoded) # check the first list
BitwiseIp.Blocks.member?(blocks2, encoded) # check the second list
Examples
iex> ["1.2.0.0/16", "3.4.0.0/16", "5.6.0.0/16"]
...> |> Enum.map(&BitwiseIp.Block.parse!/1)
...> |> BitwiseIp.Blocks.member?({1, 2, 3, 4})
true
iex> ["1.2.0.0/16", "3.4.0.0/16", "5.6.0.0/16"]
...> |> Enum.map(&BitwiseIp.Block.parse!/1)
...> |> BitwiseIp.Blocks.member?({7, 8, 9, 10})
false
iex> ["1.2.0.0/16", "3.4.0.0/16", "5.6.0.0/16"]
...> |> Enum.map(&BitwiseIp.Block.parse!/1)
...> |> BitwiseIp.Blocks.member?(BitwiseIp.encode({1, 2, 3, 4}))
true
iex> ["1.2.0.0/16", "3.4.0.0/16", "5.6.0.0/16"]
...> |> Enum.map(&BitwiseIp.Block.parse!/1)
...> |> BitwiseIp.Blocks.member?(BitwiseIp.encode({7, 8, 9, 10}))
false