module Data.Dish.Murmur3(
murmur3,
murmur3Int,
murmur3IntegerX86,
murmur3IntegerX64,
murmur3Raw,
unsafeMurmur3Int,
unsafeMurmur3IntegerX86,
unsafeMurmur3IntegerX64,
MHV(..)
) where
import Foreign.C
import Foreign.Ptr
import Foreign
import qualified Data.List as L
import qualified Data.Bits as B
import qualified System.IO.Unsafe as US
data MHV = X86_32 | X86_128 | X64_128
murmur3 :: String
-> Int
-> MHV
-> IO [Int]
murmur3 v s ver = do m <- murmur3Raw v s ver; toArr m
where
toArr :: [CUInt] -> IO [Int]
toArr [] = return []
toArr l = return $ b l []
where b :: [CUInt] -> [Int] -> [Int]
b xs l2 = foldl (\ list x -> list ++ [w x] ) l2 xs
w :: CUInt -> Int
w = fromIntegral
murmur3Int :: String
-> Int
-> IO Int
murmur3Int val seed = do v <- murmur3Raw val seed X86_32;
return $ fromIntegral (L.head v)
murmur3IntegerX86 :: String
-> Int
-> IO Integer
murmur3IntegerX86 val seed = x128 val seed X86_128
murmur3IntegerX64 :: String
-> Int
-> IO Integer
murmur3IntegerX64 val seed = x128 val seed X64_128
foreign import ccall "MurmurHash3_x86_32" c_x86_32
:: CString -> CInt -> CUInt -> Ptr CUInt -> IO ()
foreign import ccall "MurmurHash3_x86_128" c_x86_128
:: CString -> CInt -> CUInt -> Ptr CUInt -> IO ()
foreign import ccall "MurmurHash3_x64_128" c_x64_128
:: CString -> CInt -> CUInt -> Ptr CUInt -> IO ()
murmur3Raw :: String -> Int -> MHV -> IO [CUInt]
murmur3Raw val seed ver = do
val' <- withCAStringLen val $ \x -> return x
let cstr = strFromCStr val'
let strLength = strLFromCStr val'
outPtr <- mallocArray arrSize
doHash ver cstr strLength (fromIntegral seed) outPtr
peekArray arrSize outPtr
where arrSize = 4
strFromCStr :: CStringLen -> CString
strFromCStr = fst
strLFromCStr :: CStringLen -> CInt
strLFromCStr i = fromIntegral $ snd i
doHash :: MHV -> CString -> CInt -> CUInt -> Ptr CUInt -> IO()
doHash X86_32 v s se o = c_x86_32 v s se o
doHash X86_128 v s se o = c_x86_128 v s se o
doHash X64_128 v s se o = c_x64_128 v s se o
unsafeMurmur3Int :: String -> Int -> Int
unsafeMurmur3Int val seed = US.unsafePerformIO $ murmur3Int val seed
unsafeMurmur3IntegerX86 :: String -> Int -> Integer
unsafeMurmur3IntegerX86 val seed = US.unsafePerformIO $ murmur3IntegerX86 val seed
unsafeMurmur3IntegerX64 :: String -> Int -> Integer
unsafeMurmur3IntegerX64 val seed = US.unsafePerformIO $ murmur3IntegerX64 val seed
x128 :: String -> Int -> MHV -> IO Integer
x128 val seed ver= do
v <- hash ver
return $ twiddle 0 v
where hash :: MHV -> IO [CUInt]
hash X86_128 = murmur3Raw val seed X86_128
hash X64_128 = murmur3Raw val seed X64_128
hash _ = return []
twiddle :: Integer -> [CUInt] -> Integer
twiddle i [] = i
twiddle i (0:xs) = twiddle i xs
twiddle i (x:xs) = twiddle (B.shift i (B.bitSize x) `B.xor` fromIntegral x) xs