defmodule XXHash do use Bitwise defmodule Int32 do def prime_1, do: 2654435761 def prime_2, do: 2246822519 def prime_3, do: 3266489917 def prime_4, do: 668265263 def prime_5, do: 374761393 def add(a, b), do: a + b |> mask def sub(a, b), do: a - b |> mask def mul(a, b), do: a * b |> mask def lshift(a, b), do: a <<< b |> mask def rshift(a, b), do: a >>> b def xor(a, b), do: a ^^^ b |> mask def rotl(a, b), do: lshift(a, b) ||| rshift(a, 32 - b) def rshift_xor(a, b), do: a |> xor(rshift(a, b)) def read(<>) when <<1::32-little>> != <<1::32-native>>, do: a def read(<>), do: byteswap(a) defp mask(a), do: a &&& 0xFFFFFFFF defp byteswap(a) do <> = <>; b end end defmodule Int64 do def prime_1, do: 11400714785074694791 def prime_2, do: 14029467366897019727 def prime_3, do: 1609587929392839161 def prime_4, do: 9650029242287828579 def prime_5, do: 2870177450012600261 def add(a, b), do: a + b |> mask def sub(a, b), do: a - b |> mask def mul(a, b), do: a * b |> mask def lshift(a, b), do: a <<< b |> mask def rshift(a, b), do: a >>> b def xor(a, b), do: a ^^^ b |> mask def rotl(a, b), do: lshift(a, b) ||| rshift(a, 64 - b) def rshift_xor(a, b), do: a |> xor(rshift(a, b)) def read(<>) when <<1::64-little>> != <<1::64-native>>, do: a def read(<>), do: byteswap(a) defp mask(a), do: a &&& 0xFFFFFFFFFFFFFFFF defp byteswap(a) do <> = <>; b end end @spec xxh32(binary | term, non_neg_integer, non_neg_integer) :: non_neg_integer def xxh32(input), do: xxh32(input, String.length(input), 0) @spec xxh32(binary | term, non_neg_integer) :: non_neg_integer def xxh32(input, seed), do: xxh32(input, String.length(input), seed) @spec xxh32(binary | term, non_neg_integer, non_neg_integer) :: non_neg_integer def xxh32(<<>>, _length, _seed), do: 0 @spec xxh32(binary | term, non_neg_integer, non_neg_integer) :: non_neg_integer def xxh32(input, length, seed) do if length >= 16 do {h32, buffer} = do_xxh32(0, seed, input) else {h32, buffer} = {Int32.add(seed, Int32.prime_5), input} end h32 |> Int32.add(length) |> do_xxh32(seed, buffer) |> Int32.rshift_xor(15) |> Int32.mul(Int32.prime_2) |> Int32.rshift_xor(13) |> Int32.mul(Int32.prime_3) |> Int32.rshift_xor(16) end @spec do_xxh32(non_neg_integer, non_neg_integer, binary | term) :: non_neg_integer defp do_xxh32(h, seed, <<_a::32, _b::32, _c::32, _d::32, _rest::binary>> = all) do v1 = Int32.add(seed, Int32.prime_1) |> Int32.add(Int32.prime_2) v2 = Int32.add(seed, Int32.prime_2) v3 = Int32.add(seed, 0) v4 = Int32.sub(seed, Int32.prime_1) do_xxh32(h, seed, all, {v1, v2, v3, v4}) end @spec do_xxh32(non_neg_integer, non_neg_integer, binary | term) :: non_neg_integer defp do_xxh32(h, _seed, <<>>), do: h @spec do_xxh32(non_neg_integer, non_neg_integer, binary | term) :: non_neg_integer defp do_xxh32(h, seed, <>) do Int32.read(<>) |> Int32.mul(Int32.prime_3) |> Int32.add(h) |> Int32.rotl(17) |> Int32.mul(Int32.prime_4) |> do_xxh32(seed, rest) end @spec do_xxh32(non_neg_integer, non_neg_integer, binary | term) :: non_neg_integer defp do_xxh32(h, seed, <>) do Int32.mul(p, Int32.prime_5) |> Int32.add(h) |> Int32.rotl(11) |> Int32.mul(Int32.prime_1) |> do_xxh32(seed, rest) end @spec do_xxh32(non_neg_integer, non_neg_integer, binary | term, tuple) :: non_neg_integer defp do_xxh32(h, seed, <>, {v1, v2, v3, v4}) do cv = &(Int32.read(&1) |> Int32.mul(Int32.prime_2) |> Int32.add(&2) |> Int32.rotl(13) |> Int32.mul(Int32.prime_1)) do_xxh32(h, seed, rest, {cv.(<>, v1), cv.(<>, v2), cv.(<>, v3), cv.(<>, v4)}) end @spec do_xxh32(non_neg_integer, non_neg_integer, binary | term, tuple) :: non_neg_integer defp do_xxh32(_h, _seed, rest, {v1, v2, v3, v4}) do {Int32.rotl(v1, 1) + Int32.rotl(v2, 7) + Int32.rotl(v3, 12) + Int32.rotl(v4, 18), rest} end end