    {-# 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)