{-# LANGUAGE ForeignFunctionInterface #-} -- | -- Module : Data.Digest.CityHash -- Copyright : (c) Austin Seipp 2011-2012 -- License : MIT -- -- Maintainer : mad.one@gmail.com -- Stability : experimental -- Portability : portable (FFI) -- -- This module implements a binding to the CityHash family of hashing -- functions. You can find more information here: -- . It implements both the 64-bit -- and 128-bit interfaces, with seed functionality. -- module Data.Digest.CityHash ( -- * 64-bit hashes cityHash64 -- :: ByteString -> Word64 , cityHash64WithSeed -- :: ByteString -> Word64 -> Word64 , cityHash64WithSeeds -- :: ByteString -> Word64 -> Word64 -> Word64 -- * 128-bit hashes , cityHash128 -- :: ByteString -> Word128 , cityHash128WithSeed -- :: ByteString -> Word128 -> Word128 ) where import Foreign import Foreign.C import Control.Monad (liftM) import System.IO.Unsafe as U (unsafePerformIO) import Data.LargeWord import qualified Data.ByteString as S import qualified Data.ByteString.Unsafe as U -- | Hash function for a byte array. cityHash64 :: S.ByteString -> Word64 cityHash64 bs = unsafeUseBS bs $ \(cstr, clen) -> do return $ c_CityHash64 cstr clen {-# INLINEABLE cityHash64 #-} -- | Hash function for a byte array. For convenience, a 64-bit seed is also -- hashed into the result. cityHash64WithSeed :: S.ByteString -> Word64 -> Word64 cityHash64WithSeed bs seed = unsafeUseBS bs $ \(cstr, clen) -> do return $ c_CityHash64WithSeed cstr clen seed {-# INLINEABLE cityHash64WithSeed #-} -- | Hash function for a byte array. For convenience, two seeds are also -- hashed into the result. cityHash64WithSeeds :: S.ByteString -> Word64 -> Word64 -> Word64 cityHash64WithSeeds bs seed0 seed1 = unsafeUseBS bs $ \(cstr, clen) -> do return $ c_CityHash64WithSeeds cstr clen seed0 seed1 {-# INLINEABLE cityHash64WithSeeds #-} -- | Hash function for a byte array. cityHash128 :: S.ByteString -> Word128 cityHash128 bs = unsafeUseBS bs $ \(cstr,clen) -> allocaBytes w64s $ \lo -> allocaBytes w64s $ \hi -> do c_CityHash128 cstr clen lo hi lo' <- (fromIntegral `liftM` peek lo) :: IO Word128 hi' <- (fromIntegral `liftM` peek hi) :: IO Word128 return $ (hi' `shiftL` 64) .|. lo' where w64s = sizeOf (undefined :: Word64) {-# INLINEABLE cityHash128 #-} -- | Hash function for a byte array. For convenience, a 128-bit seed is also -- hashed into the result. cityHash128WithSeed :: S.ByteString -> Word128 -> Word128 cityHash128WithSeed bs seed = unsafeUseBS bs $ \(cstr,clen) -> allocaBytes w64s $ \lo -> allocaBytes w64s $ \hi -> do c_CityHash128WithSeed cstr clen (loHalf seed) (hiHalf seed) lo hi lo' <- (fromIntegral `liftM` peek lo) :: IO Word128 hi' <- (fromIntegral `liftM` peek hi) :: IO Word128 return $ (hi' `shiftL` 64) .|. lo' where w64s = sizeOf (undefined :: Word64) {-# INLINEABLE cityHash128WithSeed #-} -- -- Utils -- unsafeUseBS :: S.ByteString -> ((CString, Int) -> IO a) -> a unsafeUseBS bs = U.unsafePerformIO . U.unsafeUseAsCStringLen bs -- -- FFI bindings -- foreign import ccall unsafe "hs_city.h hs_CityHash64" c_CityHash64 :: CString -> Int -> Word64 foreign import ccall unsafe "hs_city.h hs_CityHash64WithSeed" c_CityHash64WithSeed :: CString -> Int -> Word64 -> Word64 foreign import ccall unsafe "hs_city.h hs_CityHash64WithSeeds" c_CityHash64WithSeeds :: CString -> Int -> Word64 -> Word64 -> Word64 foreign import ccall unsafe "hs_city.h hs_CityHash128" c_CityHash128 :: CString -> Int -> Ptr Word64 -> Ptr Word64 -> IO () foreign import ccall unsafe "hs_city.h hs_CityHash128WithSeed" c_CityHash128WithSeed :: CString -> Int -> Word64 -> Word64 -> Ptr Word64 -> Ptr Word64 -> IO ()