{-# LANGUAGE CPP           #-}
{-# LANGUAGE MagicHash     #-}
{-# LANGUAGE Trustworthy   #-}
{-# LANGUAGE UnboxedTuples #-}
module Data.Hashable.Mix (
    Salt,
    mixHash,
) where

#include "MachDeps.h"

import Data.Bits (unsafeShiftR, xor)
import GHC.Exts  (Word (..), byteSwap#, timesWord2#, xor#)

type Salt = Int

mulFold :: Word -> Word -> Word
mulFold :: Word -> Word -> Word
mulFold (W# Word#
x) (W# Word#
y) = case Word# -> Word# -> (# Word#, Word# #)
timesWord2# Word#
x Word#
y of
    (# Word#
hi, Word#
lo #) -> Word# -> Word
W# (Word# -> Word# -> Word#
xor# Word#
hi Word#
lo)

byteSwap :: Word -> Word
byteSwap :: Word -> Word
byteSwap (W# Word#
w) = Word# -> Word
W# (Word# -> Word#
byteSwap# Word#
w)

avalanche :: Word -> Word
avalanche :: Word -> Word
avalanche Word
z0 =
#if WORD_SIZE_IN_BITS == 64
   -- MurmurHash3Mixer
    let z1 :: Word
z1 = Int -> Word -> Word -> Word
shiftXorMultiply Int
33 Word
0xff51afd7ed558ccd Word
z0
        z2 :: Word
z2 = Int -> Word -> Word -> Word
shiftXorMultiply Int
33 Word
0xc4ceb9fe1a85ec53 Word
z1
        z3 :: Word
z3 = Int -> Word -> Word
shiftXor Int
33 Word
z2
    in Word
z3
#else
   -- MurmurHash3Mixer 32bit
    let z1 = shiftXorMultiply 16 0x85ebca6b z0
        z2 = shiftXorMultiply 13 0xc2b2ae35 z1
        z3 = shiftXor 16 z2
    in z3
#endif

shiftXor :: Int -> Word -> Word
shiftXor :: Int -> Word -> Word
shiftXor Int
n Word
w = Word
w Word -> Word -> Word
forall a. Bits a => a -> a -> a
`xor` (Word
w Word -> Int -> Word
forall a. Bits a => a -> Int -> a
`unsafeShiftR` Int
n)

shiftXorMultiply :: Int -> Word -> Word -> Word
shiftXorMultiply :: Int -> Word -> Word -> Word
shiftXorMultiply Int
n Word
k Word
w = Int -> Word -> Word
shiftXor Int
n Word
w Word -> Word -> Word
forall a. Num a => a -> a -> a
* Word
k

-- | Mix hash is inspired by how xxh3 works on small (<=16byte) inputs.
mixHash :: Word -> Word -> Word
mixHash :: Word -> Word -> Word
mixHash Word
hi Word
lo = Word -> Word
avalanche (Word -> Word
byteSwap Word
lo Word -> Word -> Word
forall a. Num a => a -> a -> a
+ Word
hi Word -> Word -> Word
forall a. Num a => a -> a -> a
+ Word -> Word -> Word
mulFold Word
hi Word
lo)