-- | -- Module : Data.Memory.Hash.FNV -- License : BSD-style -- Maintainer : Vincent Hanquez -- Stability : experimental -- Portability : good -- -- Fowler Noll Vo Hash (1 and 1a / 32 / 64 bits versions) -- -- {-# LANGUAGE GeneralizedNewtypeDeriving #-} {-# LANGUAGE MagicHash #-} {-# LANGUAGE UnboxedTuples #-} {-# LANGUAGE BangPatterns #-} module Data.Memory.Hash.FNV ( -- * types FnvHash32(..) , FnvHash64(..) -- * methods , fnv1 , fnv1a , fnv1_64 , fnv1a_64 ) where import Data.Memory.Internal.Compat () import Data.Memory.Internal.CompatPrim import Data.Memory.Internal.CompatPrim64 import Data.Memory.Internal.Imports import GHC.Word import GHC.Prim hiding (Word64#, Int64#) import GHC.Types import GHC.Ptr -- | FNV1(a) hash (32 bit variants) newtype FnvHash32 = FnvHash32 Word32 deriving (Show,Eq,Ord,NFData) -- | FNV1(a) hash (64 bit variants) newtype FnvHash64 = FnvHash64 Word64 deriving (Show,Eq,Ord,NFData) -- | compute FNV1 (32 bit variant) of a raw piece of memory fnv1 :: Ptr Word8 -> Int -> IO FnvHash32 fnv1 (Ptr addr) (I# n) = IO $ \s -> loop 0x811c9dc5## 0# s where loop :: Word# -> Int# -> State# s -> (# State# s, FnvHash32 #) loop !acc i s | booleanPrim (i ==# n) = (# s, FnvHash32 $ W32# (narrow32Word# acc) #) | otherwise = case readWord8OffAddr# addr i s of (# s2, v #) -> let !nacc = (0x01000193## `timesWord#` acc) `xor#` v in loop nacc (i +# 1#) s2 -- | compute FNV1a (32 bit variant) of a raw piece of memory fnv1a :: Ptr Word8 -> Int -> IO FnvHash32 fnv1a (Ptr addr) (I# n) = IO $ \s -> loop 0x811c9dc5## 0# s where loop :: Word# -> Int# -> State# s -> (# State# s, FnvHash32 #) loop !acc i s | booleanPrim (i ==# n) = (# s, FnvHash32 $ W32# (narrow32Word# acc) #) | otherwise = case readWord8OffAddr# addr i s of (# s2, v #) -> let !nacc = 0x01000193## `timesWord#` (acc `xor#` v) in loop nacc (i +# 1#) s2 -- | compute FNV1 (64 bit variant) of a raw piece of memory fnv1_64 :: Ptr Word8 -> Int -> IO FnvHash64 fnv1_64 (Ptr addr) (I# n) = IO $ \s -> loop fnv64Const 0# s where loop :: Word64# -> Int# -> State# s -> (# State# s, FnvHash64 #) loop !acc i s | booleanPrim (i ==# n) = (# s, FnvHash64 $ W64# acc #) | otherwise = case readWord8OffAddr# addr i s of (# s2, v #) -> let !nacc = (fnv64Prime `timesWord64#` acc) `xor64#` (wordToWord64# v) in loop nacc (i +# 1#) s2 fnv64Const :: Word64# !fnv64Const = w64# 0xcbf29ce484222325## 0xcbf29ce4## 0x84222325## fnv64Prime :: Word64# !fnv64Prime = w64# 0x100000001b3## 0x100## 0x000001b3## -- | compute FNV1a (64 bit variant) of a raw piece of memory fnv1a_64 :: Ptr Word8 -> Int -> IO FnvHash64 fnv1a_64 (Ptr addr) (I# n) = IO $ \s -> loop fnv64Const 0# s where loop :: Word64# -> Int# -> State# s -> (# State# s, FnvHash64 #) loop !acc i s | booleanPrim (i ==# n) = (# s, FnvHash64 $ W64# acc #) | otherwise = case readWord8OffAddr# addr i s of (# s2, v #) -> let !nacc = fnv64Prime `timesWord64#` (acc `xor64#` wordToWord64# v) in loop nacc (i +# 1#) s2 fnv64Const :: Word64# !fnv64Const = w64# 0xcbf29ce484222325## 0xcbf29ce4## 0x84222325## fnv64Prime :: Word64# !fnv64Prime = w64# 0x100000001b3## 0x100## 0x000001b3##