{-# LANGUAGE CPP, BangPatterns, MagicHash, CApiFFI, UnliftedFFITypes #-}
{-# LANGUAGE Trustworthy #-}
module Data.Hashable.LowLevel (
Salt,
defaultSalt,
hashInt,
hashInt64,
hashWord64,
hashPtrWithSalt,
hashByteArrayWithSalt,
) where
#include "MachDeps.h"
import Foreign.C (CString)
import Foreign.Ptr (Ptr, castPtr)
import GHC.Base (ByteArray#)
#ifdef HASHABLE_RANDOM_SEED
import System.IO.Unsafe (unsafePerformIO)
#endif
import Data.Hashable.Imports
type Salt = Int
#ifdef HASHABLE_RANDOM_SEED
initialSeed :: Word64
initialSeed = unsafePerformIO initialSeedC
{-# NOINLINE initialSeed #-}
foreign import capi "HsHashable.h hs_hashable_init" initialSeedC :: IO Word64
#endif
defaultSalt :: Salt
#ifdef HASHABLE_RANDOM_SEED
defaultSalt = hashInt defaultSalt' (fromIntegral initialSeed)
#else
defaultSalt = defaultSalt'
#endif
{-# INLINE defaultSalt #-}
defaultSalt' :: Salt
#if WORD_SIZE_IN_BITS == 64
defaultSalt' = -3750763034362895579
#else
defaultSalt' = -2128831035
#endif
{-# INLINE defaultSalt' #-}
hashInt :: Salt -> Int -> Salt
#if WORD_SIZE_IN_BITS == 64
hashInt s x = (s * 1099511628211) `xor` x
#else
hashInt s x = (s * 16777619) `xor` x
#endif
hashInt64 :: Salt -> Int64 -> Salt
hashWord64 :: Salt -> Word64 -> Salt
#if WORD_SIZE_IN_BITS == 64
hashInt64 s x = hashInt s (fromIntegral x)
hashWord64 s x = hashInt s (fromIntegral x)
#else
hashInt64 s x = hashInt (hashInt s (fromIntegral x)) (fromIntegral (x `shiftR` 32))
hashWord64 s x = hashInt (hashInt s (fromIntegral x)) (fromIntegral (x `shiftR` 32))
#endif
hashPtrWithSalt :: Ptr a
-> Int
-> Salt
-> IO Salt
hashPtrWithSalt p len salt =
fromIntegral `fmap` c_hashCString (castPtr p) (fromIntegral len)
(fromIntegral salt)
hashByteArrayWithSalt
:: ByteArray#
-> Int
-> Int
-> Salt
-> Salt
hashByteArrayWithSalt ba !off !len !h =
fromIntegral $ c_hashByteArray ba (fromIntegral off) (fromIntegral len)
(fromIntegral h)
foreign import capi unsafe "HsHashable.h hashable_fnv_hash" c_hashCString
#if WORD_SIZE_IN_BITS == 64
:: CString -> Int64 -> Int64 -> IO Word64
#else
:: CString -> Int32 -> Int32 -> IO Word32
#endif
#if __GLASGOW_HASKELL__ >= 802
foreign import capi unsafe "HsHashable.h hashable_fnv_hash_offset" c_hashByteArray
#else
foreign import ccall unsafe "hashable_fnv_hash_offset" c_hashByteArray
#endif
#if WORD_SIZE_IN_BITS == 64
:: ByteArray# -> Int64 -> Int64 -> Int64 -> Word64
#else
:: ByteArray# -> Int32 -> Int32 -> Int32 -> Word32
#endif