module Foundation.Hashing.FNV
(
FNV1Hash32(..)
, FNV1Hash64(..)
, FNV1_32
, FNV1a_32
, FNV1_64
, FNV1a_64
) where
import Basement.Compat.Base
import qualified Basement.UArray as A
import Basement.Types.OffsetSize
import Basement.PrimType
import Basement.IntegralConv
import Foundation.Numerical
import Foundation.Hashing.Hasher
import Data.Bits
import GHC.Prim
import GHC.ST
newtype FNV1Hash32 = FNV1Hash32 Word32
deriving (Show,Eq,Ord)
newtype FNV1Hash64 = FNV1Hash64 Word64
deriving (Show,Eq,Ord)
xor32 :: Word -> Word8 -> Word
xor32 !a !b = a `xor` integralUpsize b
xor64 :: Word64 -> Word8 -> Word64
xor64 !a !b = a `xor` integralUpsize b
newtype FNV1_32 = FNV1_32 Word
newtype FNV1_64 = FNV1_64 Word64
newtype FNV1a_32 = FNV1a_32 Word
newtype FNV1a_64 = FNV1a_64 Word64
fnv1_32_Mix8 :: Word8 -> FNV1_32 -> FNV1_32
fnv1_32_Mix8 !w (FNV1_32 acc) = FNV1_32 (0x01000193 * acc `xor32` w)
fnv1a_32_Mix8 :: Word8 -> FNV1a_32 -> FNV1a_32
fnv1a_32_Mix8 !w (FNV1a_32 acc) = FNV1a_32 (0x01000193 * (acc `xor32` w))
fnv1_64_Mix8 :: Word8 -> FNV1_64 -> FNV1_64
fnv1_64_Mix8 !w (FNV1_64 acc) = FNV1_64 (0x100000001b3 * acc `xor64` w)
fnv1a_64_Mix8 :: Word8 -> FNV1a_64 -> FNV1a_64
fnv1a_64_Mix8 !w (FNV1a_64 acc) = FNV1a_64 (0x100000001b3 * (acc `xor64` w))
instance Hasher FNV1_32 where
type HashResult FNV1_32 = FNV1Hash32
type HashInitParam FNV1_32 = Word
hashNew = FNV1_32 0
hashNewParam w = FNV1_32 w
hashEnd (FNV1_32 w) = FNV1Hash32 (integralDownsize w)
hashMix8 = fnv1_32_Mix8
hashMixBytes = fnv1_32_mixBa
instance Hasher FNV1a_32 where
type HashResult FNV1a_32 = FNV1Hash32
type HashInitParam FNV1a_32 = Word
hashNew = FNV1a_32 0
hashNewParam w = FNV1a_32 w
hashEnd (FNV1a_32 w) = FNV1Hash32 (integralDownsize w)
hashMix8 = fnv1a_32_Mix8
hashMixBytes = fnv1a_32_mixBa
instance Hasher FNV1_64 where
type HashResult FNV1_64 = FNV1Hash64
type HashInitParam FNV1_64 = Word64
hashNew = FNV1_64 0xcbf29ce484222325
hashNewParam w = FNV1_64 w
hashEnd (FNV1_64 w) = FNV1Hash64 w
hashMix8 = fnv1_64_Mix8
hashMixBytes = fnv1_64_mixBa
instance Hasher FNV1a_64 where
type HashResult FNV1a_64 = FNV1Hash64
type HashInitParam FNV1a_64 = Word64
hashNew = FNV1a_64 0xcbf29ce484222325
hashNewParam w = FNV1a_64 w
hashEnd (FNV1a_64 w) = FNV1Hash64 w
hashMix8 = fnv1a_64_Mix8
hashMixBytes = fnv1a_64_mixBa
fnv1_32_mixBa :: PrimType a => A.UArray a -> FNV1_32 -> FNV1_32
fnv1_32_mixBa baA !initialState = A.unsafeDewrap goVec goAddr ba
where
ba :: A.UArray Word8
ba = A.unsafeRecast baA
goVec :: ByteArray# -> Offset Word8 -> FNV1_32
goVec !ma !start = loop start initialState
where
!len = start `offsetPlusE` A.length ba
loop !idx !acc
| idx >= len = acc
| otherwise = loop (idx + Offset 1) (hashMix8 (primBaIndex ma idx) acc)
goAddr :: Ptr Word8 -> Offset Word8 -> ST s FNV1_32
goAddr (Ptr ptr) !start = return $ loop start initialState
where
!len = start `offsetPlusE` A.length ba
loop !idx !acc
| idx >= len = acc
| otherwise = loop (idx + Offset 1) (hashMix8 (primAddrIndex ptr idx) acc)
fnv1a_32_mixBa :: PrimType a => A.UArray a -> FNV1a_32 -> FNV1a_32
fnv1a_32_mixBa baA !initialState = A.unsafeDewrap goVec goAddr ba
where
ba :: A.UArray Word8
ba = A.unsafeRecast baA
goVec :: ByteArray# -> Offset Word8 -> FNV1a_32
goVec !ma !start = loop start initialState
where
!len = start `offsetPlusE` A.length ba
loop !idx !acc
| idx >= len = acc
| otherwise = loop (idx + Offset 1) (hashMix8 (primBaIndex ma idx) acc)
goAddr :: Ptr Word8 -> Offset Word8 -> ST s FNV1a_32
goAddr (Ptr ptr) !start = return $ loop start initialState
where
!len = start `offsetPlusE` A.length ba
loop !idx !acc
| idx >= len = acc
| otherwise = loop (idx + Offset 1) (hashMix8 (primAddrIndex ptr idx) acc)
fnv1_64_mixBa :: PrimType a => A.UArray a -> FNV1_64 -> FNV1_64
fnv1_64_mixBa baA !initialState = A.unsafeDewrap goVec goAddr ba
where
ba :: A.UArray Word8
ba = A.unsafeRecast baA
goVec :: ByteArray# -> Offset Word8 -> FNV1_64
goVec !ma !start = loop start initialState
where
!len = start `offsetPlusE` A.length ba
loop !idx !acc
| idx >= len = acc
| otherwise = loop (idx + Offset 1) (hashMix8 (primBaIndex ma idx) acc)
goAddr :: Ptr Word8 -> Offset Word8 -> ST s FNV1_64
goAddr (Ptr ptr) !start = return $ loop start initialState
where
!len = start `offsetPlusE` A.length ba
loop !idx !acc
| idx >= len = acc
| otherwise = loop (idx + Offset 1) (hashMix8 (primAddrIndex ptr idx) acc)
fnv1a_64_mixBa :: PrimType a => A.UArray a -> FNV1a_64 -> FNV1a_64
fnv1a_64_mixBa baA !initialState = A.unsafeDewrap goVec goAddr ba
where
ba :: A.UArray Word8
ba = A.unsafeRecast baA
goVec :: ByteArray# -> Offset Word8 -> FNV1a_64
goVec !ma !start = loop start initialState
where
!len = start `offsetPlusE` A.length ba
loop !idx !acc
| idx >= len = acc
| otherwise = loop (idx + Offset 1) (hashMix8 (primBaIndex ma idx) acc)
goAddr :: Ptr Word8 -> Offset Word8 -> ST s FNV1a_64
goAddr (Ptr ptr) !start = return $ loop start initialState
where
!len = start `offsetPlusE` A.length ba
loop !idx !acc
| idx >= len = acc
| otherwise = loop (idx + Offset 1) (hashMix8 (primAddrIndex ptr idx) acc)