Experimental browser for the Atmosphere
{ "uri": "at://did:plc:bnqkww7bjxaacajzvu5gswdf/link.pastesphere.snippet/3ldgv2d3kbs27", "cid": "bafyreiage7yur32nxq7rvs3v35ioi63dneptizxy7vrlqoruqd5bscd3yy", "value": { "body": "defmodule BloomFilter do\n\n @moduledoc \"\"\"\n A small Bloom Filter in Elixir\n \"\"\"\n\n @default_hash_fns [:sha256, :sha512, :blake2b]\n\n defstruct bits: <<0::size(64)>>, hash_fns: @default_hash_fns\n\n @type hashfn :: :crypto.hash_algorithm() | :phash2 | function()\n @type hashfns :: [hashfn()]\n\n @type t :: %BloomFilter{\n bits: bitstring(),\n hash_fns: hashfns()\n }\n\n\n @spec new(pos_integer(), hashfns()) :: t()\n def new(size \\\\ 64, hash_fns \\\\ @default_hash_fns) do\n %BloomFilter{bits: <<0::size(size)>>, hash_fns: hash_fns}\n end\n\n @spec default_hash_fns() :: hashfns()\n def default_hash_fns, do: @default_hash_fns\n\n @spec hash(hashfn(), term()) :: binary()\n defp hash(:phash2, key), do: <<:erlang.phash2(key)>>\n\n defp hash(hash_fn, key) when is_function(hash_fn), do: hash_fn.(key)\n\n defp hash(hash_fn, key) when is_atom(hash_fn), do: :crypto.hash(hash_fn, key)\n\n @spec hashes(t(), term()) :: [non_neg_integer()]\n defp hashes(%{hash_fns: hash_fns, bits: bits}, key) do\n for hash_fn <- hash_fns do\n hash_fn\n |> hash(key)\n |> :binary.decode_unsigned\n |> rem(bit_size(bits))\n end\n end\n\n @spec bit_at(bitstring(), non_neg_integer()) :: 0 | 1\n defp bit_at(bits, i) do\n <<slice::bitstring-size(i), _rest::bitstring>> = bits\n <<_::size(i - 1), bit::1>> = slice\n bit\n end\n\n @spec set_bit(bitstring(), non_neg_integer(), 0 | 1) :: bitstring()\n defp set_bit(bits, i, value) do\n <<slice::bitstring-size(i), rest::bitstring>> = bits\n <<a::bitstring-size(i - 1), _::1>> = slice\n <<a::bitstring, value::1, rest::bitstring>>\n end\n\n @spec add(t(), term()) :: t()\n def add(%BloomFilter{bits: bits} = bf, key) do\n Enum.reduce(hashes(bf, key), bits, fn i, bit_string ->\n set_bit(bit_string, i, 1)\n end)\n |> then(fn bits -> %BloomFilter{bf | bits: bits} end)\n end\n\n @spec contains?(t(), term()) :: boolean()\n def contains?(%BloomFilter{} = bf, key) do\n Enum.all?(hashes(bf, key), fn i ->\n bit_at(bf.bits, i) == 1\n end)\n end\n\n defimpl String.Chars, for: __MODULE__ do\n def to_string(bloom_filter) do\n \"#BloomFilter\\n\\tbits: \" <> (bloom_filter.bits\n |> print_bits) <> \"\\n\\thash_fns: \" <> inspect(bloom_filter.hash_fns)\n end\n\n def print_bits(bitstring) when is_bitstring(bitstring) do\n print_bits(bitstring, 0, \"\")\n end\n\n defp print_bits(<<bit::size(1), rest::bitstring>>, index, result) do\n print_bits(rest, index + 1, \"#{result}#{bit}\")\n end\n\n defp print_bits(<<>>, _index, result) do\n result\n end\n end\n\n defimpl Inspect, for: __MODULE__ do\n def inspect(bloom_filter, _opts) do\n bloom_filter\n |> String.Chars.to_string\n end\n end\nend", "type": "Elixir", "$type": "link.pastesphere.snippet", "title": "bloomfilter.ex", "createdAt": "2024-12-16T17:45:54.379Z", "description": "A small Bloom Filter implementation in Elixir" } }