{-# 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 :: Salt
defaultSalt = Salt
defaultSalt'
#endif
{-# INLINE defaultSalt #-}
defaultSalt' :: Salt
#if WORD_SIZE_IN_BITS == 64
defaultSalt' :: Salt
defaultSalt' = -Salt
3750763034362895579
#else
defaultSalt' = -2128831035
#endif
{-# INLINE defaultSalt' #-}
hashInt :: Salt -> Int -> Salt
hashInt :: Salt -> Salt -> Salt
hashInt Salt
s Salt
x = Salt
s forall {a}. (Bits a, Num a) => a -> a -> a
`rnd` Salt
x1 forall {a}. (Bits a, Num a) => a -> a -> a
`rnd` Salt
x2 forall {a}. (Bits a, Num a) => a -> a -> a
`rnd` Salt
x3 forall {a}. (Bits a, Num a) => a -> a -> a
`rnd` Salt
x4
where
{-# INLINE rnd #-}
{-# INLINE x1 #-}
{-# INLINE x2 #-}
{-# INLINE x3 #-}
{-# INLINE x4 #-}
#if WORD_SIZE_IN_BITS == 64
rnd :: a -> a -> a
rnd a
a a
b = (a
a forall a. Num a => a -> a -> a
* a
1099511628211) forall a. Bits a => a -> a -> a
`xor` a
b
x1 :: Salt
x1 = forall a. Bits a => a -> Salt -> a
shiftR Salt
x Salt
48 forall a. Bits a => a -> a -> a
.&. Salt
0xffff
x2 :: Salt
x2 = forall a. Bits a => a -> Salt -> a
shiftR Salt
x Salt
32 forall a. Bits a => a -> a -> a
.&. Salt
0xffff
x3 :: Salt
x3 = forall a. Bits a => a -> Salt -> a
shiftR Salt
x Salt
16 forall a. Bits a => a -> a -> a
.&. Salt
0xffff
x4 :: Salt
x4 = Salt
x forall a. Bits a => a -> a -> a
.&. Salt
0xffff
#else
rnd a b = (a * 16777619) `xor` b
x1 = shiftR x 24 .&. 0xff
x2 = shiftR x 16 .&. 0xff
x3 = shiftR x 8 .&. 0xff
x4 = x .&. 0xff
#endif
hashInt64 :: Salt -> Int64 -> Salt
hashWord64 :: Salt -> Word64 -> Salt
#if WORD_SIZE_IN_BITS == 64
hashInt64 :: Salt -> Int64 -> Salt
hashInt64 Salt
s Int64
x = Salt -> Salt -> Salt
hashInt Salt
s (forall a b. (Integral a, Num b) => a -> b
fromIntegral Int64
x)
hashWord64 :: Salt -> Word64 -> Salt
hashWord64 Salt
s Word64
x = Salt -> Salt -> Salt
hashInt Salt
s (forall a b. (Integral a, Num b) => a -> b
fromIntegral Word64
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 :: forall a. Ptr a -> Salt -> Salt -> IO Salt
hashPtrWithSalt Ptr a
p Salt
len Salt
salt =
forall a b. (Integral a, Num b) => a -> b
fromIntegral forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
`fmap` CString -> Int64 -> Int64 -> IO Word64
c_hashCString (forall a b. Ptr a -> Ptr b
castPtr Ptr a
p) (forall a b. (Integral a, Num b) => a -> b
fromIntegral Salt
len)
(forall a b. (Integral a, Num b) => a -> b
fromIntegral Salt
salt)
hashByteArrayWithSalt
:: ByteArray#
-> Int
-> Int
-> Salt
-> Salt
hashByteArrayWithSalt :: ByteArray# -> Salt -> Salt -> Salt -> Salt
hashByteArrayWithSalt ByteArray#
ba !Salt
off !Salt
len !Salt
h =
forall a b. (Integral a, Num b) => a -> b
fromIntegral forall a b. (a -> b) -> a -> b
$ ByteArray# -> Int64 -> Int64 -> Int64 -> Word64
c_hashByteArray ByteArray#
ba (forall a b. (Integral a, Num b) => a -> b
fromIntegral Salt
off) (forall a b. (Integral a, Num b) => a -> b
fromIntegral Salt
len)
(forall a b. (Integral a, Num b) => a -> b
fromIntegral Salt
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