cityhash-0.2.0.0: Data/Digest/CityHash.hs
{-# 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:
-- <http://code.google.com/p/cityhash/>. 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 ()