module Data.Hash.Instances ( Hashable(..), hashFoldable )

where

import Data.Hash.Base

import Data.Word
import Data.Int
import Data.Ratio
import Data.Foldable

class Hashable a where
    hash :: a -> Hash

hashFoldable :: (Foldable t, Hashable a) => t a -> Hash
hashFoldable :: forall (t :: * -> *) a. (Foldable t, Hashable a) => t a -> Hash
hashFoldable = (Hash -> a -> Hash) -> Hash -> t a -> Hash
forall (t :: * -> *) b a.
Foldable t =>
(b -> a -> b) -> b -> t a -> b
foldl' (\Hash
h a
a -> Hash
h Hash -> Hash -> Hash
`combine` a -> Hash
forall a. Hashable a => a -> Hash
hash a
a) Hash
h0


instance Hashable Word8 where
    hash :: Word8 -> Hash
hash = Word8 -> Hash
hashWord8

instance Hashable Word16 where
    hash :: Word16 -> Hash
hash = Word16 -> Hash
hashWord16

instance Hashable Word32 where
    hash :: Word32 -> Hash
hash = Word32 -> Hash
hashWord32

instance Hashable Word64 where
    hash :: Word64 -> Hash
hash = Word64 -> Hash
hashWord64

instance Hashable Word where
    hash :: Word -> Hash
hash Word
w = Int -> Hash
forall a. Hashable a => a -> Hash
hash (Word -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral Word
w :: Int)

instance Hashable Int8 where
    hash :: Int8 -> Hash
hash Int8
i = Word8 -> Hash
forall a. Hashable a => a -> Hash
hash (Int8 -> Word8
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int8
i :: Word8)

instance Hashable Int16 where
    hash :: Int16 -> Hash
hash Int16
i = Word16 -> Hash
forall a. Hashable a => a -> Hash
hash (Int16 -> Word16
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int16
i :: Word16)

instance Hashable Int32 where
    hash :: Int32 -> Hash
hash Int32
i = Word32 -> Hash
forall a. Hashable a => a -> Hash
hash (Int32 -> Word32
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int32
i :: Word32)

instance Hashable Int64 where
    hash :: Int64 -> Hash
hash Int64
i = Word64 -> Hash
forall a. Hashable a => a -> Hash
hash (Int64 -> Word64
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int64
i :: Word64)

instance Hashable Int where
    hash :: Int -> Hash
hash = Int -> Hash
hashInt

instance Hashable Integer where
    -- a very inefficient instance, but i don't have time to mess
    -- with internal representations now...
    hash :: Integer -> Hash
hash = String -> Hash
forall a. Hashable a => a -> Hash
hash (String -> Hash) -> (Integer -> String) -> Integer -> Hash
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Integer -> String
forall a. Show a => a -> String
show

instance Hashable Float where
    hash :: Float -> Hash
hash = Float -> Hash
forall a. Storable a => a -> Hash
hashStorable

instance Hashable Double where
    hash :: Double -> Hash
hash = Double -> Hash
forall a. Storable a => a -> Hash
hashStorable

instance (Integral a, Hashable a) => Hashable (Ratio a) where
    hash :: Ratio a -> Hash
hash Ratio a
r = (a -> Hash
forall a. Hashable a => a -> Hash
hash (a -> Hash) -> a -> Hash
forall a b. (a -> b) -> a -> b
$ Ratio a -> a
forall a. Ratio a -> a
numerator Ratio a
r) Hash -> Hash -> Hash
`combine` (a -> Hash
forall a. Hashable a => a -> Hash
hash (a -> Hash) -> a -> Hash
forall a b. (a -> b) -> a -> b
$ Ratio a -> a
forall a. Ratio a -> a
denominator Ratio a
r)

instance Hashable Char where
    hash :: Char -> Hash
hash = Int -> Hash
forall a. Hashable a => a -> Hash
hash (Int -> Hash) -> (Char -> Int) -> Char -> Hash
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Char -> Int
forall a. Enum a => a -> Int
fromEnum

instance Hashable a => Hashable [a] where
    hash :: [a] -> Hash
hash = [a] -> Hash
forall (t :: * -> *) a. (Foldable t, Hashable a) => t a -> Hash
hashFoldable

instance Hashable Bool where
    hash :: Bool -> Hash
hash = Int -> Hash
forall a. Hashable a => a -> Hash
hash (Int -> Hash) -> (Bool -> Int) -> Bool -> Hash
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Bool -> Int
forall a. Enum a => a -> Int
fromEnum

instance Hashable () where
    hash :: () -> Hash
hash () = Hash
h0

instance (Hashable a, Hashable b) => Hashable (a,b) where
    hash :: (a, b) -> Hash
hash (a
a,b
b) = a -> Hash
forall a. Hashable a => a -> Hash
hash a
a Hash -> Hash -> Hash
`combine` b -> Hash
forall a. Hashable a => a -> Hash
hash b
b

instance (Hashable a, Hashable b, Hashable c) => Hashable (a,b,c) where
    hash :: (a, b, c) -> Hash
hash (a
a,b
b,c
c) = a -> Hash
forall a. Hashable a => a -> Hash
hash a
a Hash -> Hash -> Hash
`combine` b -> Hash
forall a. Hashable a => a -> Hash
hash b
b Hash -> Hash -> Hash
`combine` c -> Hash
forall a. Hashable a => a -> Hash
hash c
c

instance (Hashable a, Hashable b, Hashable c, Hashable d) => Hashable (a,b,c,d)
  where
    hash :: (a, b, c, d) -> Hash
hash (a
a,b
b,c
c,d
d) = a -> Hash
forall a. Hashable a => a -> Hash
hash a
a Hash -> Hash -> Hash
`combine` b -> Hash
forall a. Hashable a => a -> Hash
hash b
b Hash -> Hash -> Hash
`combine` c -> Hash
forall a. Hashable a => a -> Hash
hash c
c Hash -> Hash -> Hash
`combine` d -> Hash
forall a. Hashable a => a -> Hash
hash d
d

instance Hashable a => Hashable (Maybe a) where
    hash :: Maybe a -> Hash
hash = Hash -> (a -> Hash) -> Maybe a -> Hash
forall b a. b -> (a -> b) -> Maybe a -> b
maybe Hash
hF (\a
a -> a -> Hash
forall a. Hashable a => a -> Hash
hash a
a Hash -> Hash -> Hash
`combine` Hash
hT)

instance (Hashable a, Hashable b) => Hashable (Either a b) where
    hash :: Either a b -> Hash
hash (Left  a
a) = a -> Hash
forall a. Hashable a => a -> Hash
hash a
a Hash -> Hash -> Hash
`combine` Hash
hT
    hash (Right b
b) = b -> Hash
forall a. Hashable a => a -> Hash
hash b
b Hash -> Hash -> Hash
`combine` Hash
hF