Packages

32 bit variant of the Murmur3 non-cryptographic hash function

Current section

Files

Jump to
murmur3a src murmur3a.erl
Raw

src/murmur3a.erl

-module(murmur3a).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/murmur3a.gleam").
-export([int_digest/1, bit_array_digest/1, hex_digest/1, hash_string/2, hash_ints/2]).
-export_type([hash/0]).
-if(?OTP_RELEASE >= 27).
-define(MODULEDOC(Str), -moduledoc(Str)).
-define(DOC(Str), -doc(Str)).
-else.
-define(MODULEDOC(Str), -compile([])).
-define(DOC(Str), -compile([])).
-endif.
-opaque hash() :: {hash, integer(), integer(), integer()}.
-file("src/murmur3a.gleam", 124).
?DOC(
" Returns the 32 bit _signed_ integer digest of the hash.\n"
"\n"
" Keep in mind that these values may return negative numbers!\n"
"\n"
" ## Examples\n"
"\n"
" ```gleam\n"
" hash_ints([1, 2, 3], 0)\n"
" |> int_digest\n"
" // -> -2133732860\n"
" ```\n"
).
-spec int_digest(hash()) -> integer().
int_digest(Hash) ->
erlang:element(4, Hash).
-file("src/murmur3a.gleam", 137).
?DOC(
" Returns 32 bit digest of the hash as a BitArray.\n"
"\n"
" ## Examples\n"
"\n"
" ```gleam\n"
" hash_string(\"murmur3a\", 0)\n"
" |> bit_array_digest\n"
" // -> <<232, 177, 21, 28>>\n"
" ```\n"
).
-spec bit_array_digest(hash()) -> bitstring().
bit_array_digest(Hash) ->
<<(int_digest(Hash)):32>>.
-file("src/murmur3a.gleam", 150).
?DOC(
" Returns a hexadecimal digest of the hash.\n"
"\n"
" ## Examples\n"
"\n"
" ```gleam\n"
" hash_string(\"murmur3a\", 0)\n"
" |> hex_digest\n"
" // -> \"E8B1151C\"\n"
" ```\n"
).
-spec hex_digest(hash()) -> binary().
hex_digest(Hash) ->
_pipe = Hash,
_pipe@1 = bit_array_digest(_pipe),
gleam_stdlib:base16_encode(_pipe@1).
-file("src/murmur3a.gleam", 176).
-spec rotate_left(integer(), integer()) -> integer().
rotate_left(N, Shift) ->
N@1 = erlang:'band'(N, 16#ffffffff),
_pipe = erlang:'bsl'(N@1, Shift),
_pipe@1 = erlang:'band'(_pipe, 16#ffffffff),
erlang:'bor'(_pipe@1, erlang:'bsr'(N@1, 32 - Shift)).
-file("src/murmur3a.gleam", 167).
-spec signed_multiply(integer(), integer()) -> integer().
signed_multiply(M, N) ->
Result = erlang:'band'(M * N, 16#ffffffff),
case Result > 16#7fffffff of
true ->
Result - 16#100000000;
false ->
Result
end.
-file("src/murmur3a.gleam", 70).
-spec mix(integer(), integer()) -> integer().
mix(State, Seed) ->
_pipe = State,
_pipe@1 = signed_multiply(_pipe, 16#cc9e2d51),
_pipe@2 = rotate_left(_pipe@1, 15),
_pipe@3 = signed_multiply(_pipe@2, 16#1b873593),
_pipe@4 = erlang:'bxor'(_pipe@3, Seed),
_pipe@5 = rotate_left(_pipe@4, 13),
_pipe@6 = signed_multiply(_pipe@5, 5),
gleam@int:add(_pipe@6, 16#e6546b64).
-file("src/murmur3a.gleam", 57).
-spec hash_chunk(hash(), integer()) -> hash().
hash_chunk(Hash, Chunk) ->
State = begin
_pipe = Chunk,
_pipe@1 = erlang:'band'(_pipe, 16#ff),
_pipe@2 = erlang:'bsl'(_pipe@1, erlang:element(3, Hash)),
erlang:'bor'(_pipe@2, erlang:element(4, Hash))
end,
case erlang:element(3, Hash) of
24 ->
{hash, mix(State, erlang:element(2, Hash)), 0, 0};
_ ->
{hash, erlang:element(2, Hash), erlang:element(3, Hash) + 8, State}
end.
-file("src/murmur3a.gleam", 81).
-spec finalize({hash(), integer()}) -> hash().
finalize(Input) ->
{Hash, Length} = Input,
State = begin
_pipe@5 = case erlang:element(4, Hash) of
0 ->
erlang:element(2, Hash);
_ ->
_pipe = erlang:element(4, Hash),
_pipe@1 = signed_multiply(_pipe, 16#cc9e2d51),
_pipe@2 = rotate_left(_pipe@1, 15),
_pipe@3 = signed_multiply(_pipe@2, 16#1b873593),
_pipe@4 = erlang:'bxor'(_pipe@3, erlang:element(2, Hash)),
erlang:'band'(_pipe@4, 16#ffffffff)
end,
erlang:'bxor'(_pipe@5, Length)
end,
State@1 = begin
_pipe@6 = erlang:'bsr'(State, 16),
_pipe@7 = erlang:'bxor'(_pipe@6, State),
_pipe@8 = signed_multiply(_pipe@7, 16#85ebca6b),
erlang:'band'(_pipe@8, 16#ffffffff)
end,
State@2 = begin
_pipe@9 = erlang:'bsr'(State@1, 13),
_pipe@10 = erlang:'bxor'(_pipe@9, State@1),
signed_multiply(_pipe@10, 16#c2b2ae35)
end,
{hash,
erlang:element(2, Hash),
erlang:element(3, Hash),
begin
_pipe@11 = erlang:'bsr'(State@2, 16),
_pipe@12 = erlang:'band'(_pipe@11, 16#ffff),
erlang:'bxor'(_pipe@12, State@2)
end}.
-file("src/murmur3a.gleam", 184).
-spec make_fold(fun((LMW) -> integer())) -> fun(({hash(), integer()}, LMW) -> {hash(),
integer()}).
make_fold(Transform) ->
fun(Acc, A) ->
{Hash, Length} = Acc,
{hash_chunk(Hash, Transform(A)), Length + 1}
end.
-file("src/murmur3a.gleam", 33).
?DOC(
" Computes a 32 bit Murmur3 hash of the input string.\n"
"\n"
" ## Examples\n"
"\n"
" ```gleam\n"
" hash_string(\"murmur3a\", 0)\n"
" // -> Hash(3521997819, 0, -391047908)\n"
" ```\n"
).
-spec hash_string(binary(), integer()) -> hash().
hash_string(Key, Seed) ->
_pipe = Key,
_pipe@1 = gleam@string:to_utf_codepoints(_pipe),
_pipe@2 = gleam@list:fold(
_pipe@1,
{{hash,
Seed,
erlang:element(3, {hash, 0, 0, 0}),
erlang:element(4, {hash, 0, 0, 0})},
0},
make_fold(fun gleam_stdlib:identity/1)
),
finalize(_pipe@2).
-file("src/murmur3a.gleam", 51).
?DOC(
" Computes a 32 bit Murmur3 hash of the supplied list of integers.\n"
"\n"
" ## Examples\n"
"\n"
" ```gleam\n"
" hash_ints([1, 2, 3], 0)\n"
" // -> Hash(0, 24, -2133732860)\n"
" ```\n"
).
-spec hash_ints(list(integer()), integer()) -> hash().
hash_ints(Key, Seed) ->
_pipe = Key,
_pipe@1 = gleam@list:fold(
_pipe,
{{hash,
Seed,
erlang:element(3, {hash, 0, 0, 0}),
erlang:element(4, {hash, 0, 0, 0})},
0},
make_fold(fun gleam@function:identity/1)
),
finalize(_pipe@1).