BitwiseIp.Blocks.member-question-mark

You're seeing just the function 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