#ifdef GENERICS
#endif
module Data.Hashable.Class
(
Hashable(..)
, Hashable1(..)
, Hashable2(..)
#ifdef GENERICS
, GHashable(..)
, HashArgs(..)
, Zero
, One
#endif
, hashUsing
, hashPtr
, hashPtrWithSalt
, hashByteArray
, hashByteArrayWithSalt
, defaultHashWithSalt
, hashWithSalt1
, hashWithSalt2
, defaultLiftHashWithSalt
, Hashed
, hashed
, unhashed
, mapHashed
, traverseHashed
) where
import Control.Applicative (Const(..))
import Control.Exception (assert)
import Data.Bits (shiftL, shiftR, xor)
import qualified Data.ByteString as B
import qualified Data.ByteString.Internal as B
import qualified Data.ByteString.Lazy as BL
import qualified Data.ByteString.Unsafe as B
import Data.Int (Int8, Int16, Int32, Int64)
import Data.List (foldl')
import Data.Ratio (Ratio, denominator, numerator)
import qualified Data.Text as T
import qualified Data.Text.Array as TA
import qualified Data.Text.Internal as T
import qualified Data.Text.Lazy as TL
import Data.Typeable (Typeable, TypeRep)
import Data.Version (Version(..))
import Data.Word (Word8, Word16, Word32, Word64)
import Foreign.C (CString)
import Foreign.Marshal.Utils (with)
import Foreign.Ptr (Ptr, FunPtr, IntPtr, WordPtr, castPtr, castFunPtrToPtr, ptrToIntPtr)
import Foreign.Storable (alignment, peek, sizeOf)
import GHC.Base (ByteArray#)
import GHC.Conc (ThreadId(..))
import GHC.Prim (ThreadId#)
import System.IO.Unsafe (unsafePerformIO)
import System.Mem.StableName
import Data.Unique (Unique, hashUnique)
import qualified Data.Foldable as F
#if MIN_VERSION_base(4,7,0)
import Data.Proxy (Proxy)
#endif
#if MIN_VERSION_base(4,7,0)
import Data.Fixed (Fixed(..))
#endif
#if MIN_VERSION_base(4,8,0)
import Data.Functor.Identity (Identity(..))
#endif
#ifdef GENERICS
import GHC.Generics
#endif
#if __GLASGOW_HASKELL__ >= 710
import Data.Typeable (typeRepFingerprint)
import GHC.Fingerprint.Type(Fingerprint(..))
#elif __GLASGOW_HASKELL__ >= 702
import Data.Typeable.Internal (TypeRep (..))
import GHC.Fingerprint.Type(Fingerprint(..))
#elif __GLASGOW_HASKELL__ >= 606
import Data.Typeable (typeRepKey)
#endif
#if __GLASGOW_HASKELL__ >= 703
import Foreign.C (CLong(..))
import Foreign.C.Types (CInt(..))
#else
import Foreign.C (CLong)
import Foreign.C.Types (CInt)
#endif
#if !(MIN_VERSION_base(4,8,0))
import Data.Word (Word)
#endif
#if MIN_VERSION_base(4,7,0)
import Data.Bits (finiteBitSize)
#else
import Data.Bits (bitSize)
#endif
#if !(MIN_VERSION_bytestring(0,10,0))
import qualified Data.ByteString.Lazy.Internal as BL
#endif
#if MIN_VERSION_bytestring(0,10,4)
import qualified Data.ByteString.Short.Internal as BSI
#endif
#ifdef VERSION_integer_gmp
# if MIN_VERSION_integer_gmp(1,0,0)
# define MIN_VERSION_integer_gmp_1_0_0
# endif
import GHC.Exts (Int(..))
import GHC.Integer.GMP.Internals (Integer(..))
# if defined(MIN_VERSION_integer_gmp_1_0_0)
import GHC.Exts (sizeofByteArray#)
import GHC.Integer.GMP.Internals (BigNat(BN#))
# endif
#endif
#if MIN_VERSION_base(4,8,0)
import Data.Void (Void, absurd)
import GHC.Natural (Natural(..))
import GHC.Exts (Word(..))
#endif
#if MIN_VERSION_base(4,9,0)
import qualified Data.List.NonEmpty as NE
import Data.Semigroup
import Data.Functor.Classes (Eq1(..),Ord1(..),Show1(..),showsUnaryWith)
import Data.Functor.Compose (Compose(..))
import qualified Data.Functor.Product as FP
import qualified Data.Functor.Sum as FS
#endif
import Data.String (IsString(..))
#include "MachDeps.h"
infixl 0 `hashWithSalt`
defaultSalt :: Int
#if WORD_SIZE_IN_BITS == 64
defaultSalt = 2578643520546668380
#else
defaultSalt = 0x087fc72c
#endif
class Hashable a where
hashWithSalt :: Int -> a -> Int
hash :: a -> Int
hash = hashWithSalt defaultSalt
#ifdef GENERICS
default hashWithSalt :: (Generic a, GHashable Zero (Rep a)) => Int -> a -> Int
hashWithSalt salt = ghashWithSalt HashArgs0 salt . from
data Zero
data One
data HashArgs arity a where
HashArgs0 :: HashArgs Zero a
HashArgs1 :: (Int -> a -> Int) -> HashArgs One a
class GHashable arity f where
ghashWithSalt :: HashArgs arity a -> Int -> f a -> Int
#endif
class Hashable1 t where
liftHashWithSalt :: (Int -> a -> Int) -> Int -> t a -> Int
#ifdef GENERICS
default liftHashWithSalt :: (Generic1 t, GHashable One (Rep1 t)) => (Int -> a -> Int) -> Int -> t a -> Int
liftHashWithSalt h salt = ghashWithSalt (HashArgs1 h) salt . from1
#endif
class Hashable2 t where
liftHashWithSalt2 :: (Int -> a -> Int) -> (Int -> b -> Int) -> Int -> t a b -> Int
hashWithSalt1 :: (Hashable1 f, Hashable a) => Int -> f a -> Int
hashWithSalt1 = liftHashWithSalt hashWithSalt
hashWithSalt2 :: (Hashable2 f, Hashable a, Hashable b) => Int -> f a b -> Int
hashWithSalt2 = liftHashWithSalt2 hashWithSalt hashWithSalt
defaultLiftHashWithSalt :: (Hashable2 f, Hashable a) => (Int -> b -> Int) -> Int -> f a b -> Int
defaultLiftHashWithSalt h = liftHashWithSalt2 hashWithSalt h
defaultHashWithSalt :: Hashable a => Int -> a -> Int
defaultHashWithSalt salt x = salt `combine` hash x
hashUsing :: (Hashable b) =>
(a -> b)
-> Int
-> a
-> Int
hashUsing f salt x = hashWithSalt salt (f x)
instance Hashable Int where
hash = id
hashWithSalt = defaultHashWithSalt
instance Hashable Int8 where
hash = fromIntegral
hashWithSalt = defaultHashWithSalt
instance Hashable Int16 where
hash = fromIntegral
hashWithSalt = defaultHashWithSalt
instance Hashable Int32 where
hash = fromIntegral
hashWithSalt = defaultHashWithSalt
instance Hashable Int64 where
hash n
#if MIN_VERSION_base(4,7,0)
| finiteBitSize (undefined :: Int) == 64 = fromIntegral n
#else
| bitSize (undefined :: Int) == 64 = fromIntegral n
#endif
| otherwise = fromIntegral (fromIntegral n `xor`
(fromIntegral n `shiftR` 32 :: Word64))
hashWithSalt = defaultHashWithSalt
instance Hashable Word where
hash = fromIntegral
hashWithSalt = defaultHashWithSalt
instance Hashable Word8 where
hash = fromIntegral
hashWithSalt = defaultHashWithSalt
instance Hashable Word16 where
hash = fromIntegral
hashWithSalt = defaultHashWithSalt
instance Hashable Word32 where
hash = fromIntegral
hashWithSalt = defaultHashWithSalt
instance Hashable Word64 where
hash n
#if MIN_VERSION_base(4,7,0)
| finiteBitSize (undefined :: Int) == 64 = fromIntegral n
#else
| bitSize (undefined :: Int) == 64 = fromIntegral n
#endif
| otherwise = fromIntegral (n `xor` (n `shiftR` 32))
hashWithSalt = defaultHashWithSalt
instance Hashable () where
hash = fromEnum
hashWithSalt = defaultHashWithSalt
instance Hashable Bool where
hash = fromEnum
hashWithSalt = defaultHashWithSalt
instance Hashable Ordering where
hash = fromEnum
hashWithSalt = defaultHashWithSalt
instance Hashable Char where
hash = fromEnum
hashWithSalt = defaultHashWithSalt
#if defined(MIN_VERSION_integer_gmp_1_0_0)
instance Hashable BigNat where
hashWithSalt salt (BN# ba) = hashByteArrayWithSalt ba 0 numBytes salt
`hashWithSalt` size
where
size = numBytes `quot` SIZEOF_HSWORD
numBytes = I# (sizeofByteArray# ba)
#endif
#if MIN_VERSION_base(4,8,0)
instance Hashable Natural where
# if defined(MIN_VERSION_integer_gmp_1_0_0)
hash (NatS# n) = hash (W# n)
hash (NatJ# bn) = hash bn
hashWithSalt salt (NatS# n) = hashWithSalt salt (W# n)
hashWithSalt salt (NatJ# bn) = hashWithSalt salt bn
# else
hash (Natural n) = hash n
hashWithSalt salt (Natural n) = hashWithSalt salt n
# endif
#endif
instance Hashable Integer where
#if defined(VERSION_integer_gmp)
# if defined(MIN_VERSION_integer_gmp_1_0_0)
hash (S# n) = (I# n)
hash (Jp# bn) = hash bn
hash (Jn# bn) = negate (hash bn)
hashWithSalt salt (S# n) = hashWithSalt salt (I# n)
hashWithSalt salt (Jp# bn) = hashWithSalt salt bn
hashWithSalt salt (Jn# bn) = negate (hashWithSalt salt bn)
# else
hash (S# int) = I# int
hash n@(J# size# byteArray)
| n >= minInt && n <= maxInt = fromInteger n :: Int
| otherwise = let size = I# size#
numBytes = SIZEOF_HSWORD * abs size
in hashByteArrayWithSalt byteArray 0 numBytes defaultSalt
`hashWithSalt` size
where minInt = fromIntegral (minBound :: Int)
maxInt = fromIntegral (maxBound :: Int)
hashWithSalt salt (S# n) = hashWithSalt salt (I# n)
hashWithSalt salt n@(J# size# byteArray)
| n >= minInt && n <= maxInt = hashWithSalt salt (fromInteger n :: Int)
| otherwise = let size = I# size#
numBytes = SIZEOF_HSWORD * abs size
in hashByteArrayWithSalt byteArray 0 numBytes salt
`hashWithSalt` size
where minInt = fromIntegral (minBound :: Int)
maxInt = fromIntegral (maxBound :: Int)
# endif
#else
hashWithSalt salt = foldl' hashWithSalt salt . go
where
go n | inBounds n = [fromIntegral n :: Int]
| otherwise = fromIntegral n : go (n `shiftR` WORD_SIZE_IN_BITS)
maxInt = fromIntegral (maxBound :: Int)
inBounds x = x >= fromIntegral (minBound :: Int) && x <= maxInt
#endif
#if MIN_VERSION_base(4,9,0)
instance Hashable a => Hashable (Ratio a) where
#else
instance (Integral a, Hashable a) => Hashable (Ratio a) where
#endif
hash a = hash (numerator a) `hashWithSalt` denominator a
hashWithSalt s a = s `hashWithSalt` numerator a `hashWithSalt` denominator a
instance Hashable Float where
hash x
| isIEEE x =
assert (sizeOf x >= sizeOf (0::Word32) &&
alignment x >= alignment (0::Word32)) $
hash ((unsafePerformIO $ with x $ peek . castPtr) :: Word32)
| otherwise = hash (show x)
hashWithSalt = defaultHashWithSalt
instance Hashable Double where
hash x
| isIEEE x =
assert (sizeOf x >= sizeOf (0::Word64) &&
alignment x >= alignment (0::Word64)) $
hash ((unsafePerformIO $ with x $ peek . castPtr) :: Word64)
| otherwise = hash (show x)
hashWithSalt = defaultHashWithSalt
distinguisher :: Int
distinguisher = fromIntegral $ (maxBound :: Word) `quot` 3
instance Hashable a => Hashable (Maybe a) where
hash Nothing = 0
hash (Just a) = distinguisher `hashWithSalt` a
hashWithSalt = hashWithSalt1
instance Hashable1 Maybe where
liftHashWithSalt _ s Nothing = s `combine` 0
liftHashWithSalt h s (Just a) = s `combine` distinguisher `h` a
instance (Hashable a, Hashable b) => Hashable (Either a b) where
hash (Left a) = 0 `hashWithSalt` a
hash (Right b) = distinguisher `hashWithSalt` b
hashWithSalt = hashWithSalt1
instance Hashable a => Hashable1 (Either a) where
liftHashWithSalt = defaultLiftHashWithSalt
instance Hashable2 Either where
liftHashWithSalt2 h _ s (Left a) = s `combine` 0 `h` a
liftHashWithSalt2 _ h s (Right b) = s `combine` distinguisher `h` b
instance (Hashable a1, Hashable a2) => Hashable (a1, a2) where
hash (a1, a2) = hash a1 `hashWithSalt` a2
hashWithSalt = hashWithSalt1
instance Hashable a1 => Hashable1 ((,) a1) where
liftHashWithSalt = defaultLiftHashWithSalt
instance Hashable2 (,) where
liftHashWithSalt2 h1 h2 s (a1, a2) = s `h1` a1 `h2` a2
instance (Hashable a1, Hashable a2, Hashable a3) => Hashable (a1, a2, a3) where
hash (a1, a2, a3) = hash a1 `hashWithSalt` a2 `hashWithSalt` a3
hashWithSalt = hashWithSalt1
instance (Hashable a1, Hashable a2) => Hashable1 ((,,) a1 a2) where
liftHashWithSalt = defaultLiftHashWithSalt
instance Hashable a1 => Hashable2 ((,,) a1) where
liftHashWithSalt2 h1 h2 s (a1, a2, a3) =
(s `hashWithSalt` a1) `h1` a2 `h2` a3
instance (Hashable a1, Hashable a2, Hashable a3, Hashable a4) =>
Hashable (a1, a2, a3, a4) where
hash (a1, a2, a3, a4) = hash a1 `hashWithSalt` a2
`hashWithSalt` a3 `hashWithSalt` a4
hashWithSalt = hashWithSalt1
instance (Hashable a1, Hashable a2, Hashable a3) => Hashable1 ((,,,) a1 a2 a3) where
liftHashWithSalt = defaultLiftHashWithSalt
instance (Hashable a1, Hashable a2) => Hashable2 ((,,,) a1 a2) where
liftHashWithSalt2 h1 h2 s (a1, a2, a3, a4) =
(s `hashWithSalt` a1 `hashWithSalt` a2) `h1` a3 `h2` a4
instance (Hashable a1, Hashable a2, Hashable a3, Hashable a4, Hashable a5)
=> Hashable (a1, a2, a3, a4, a5) where
hash (a1, a2, a3, a4, a5) =
hash a1 `hashWithSalt` a2 `hashWithSalt` a3
`hashWithSalt` a4 `hashWithSalt` a5
hashWithSalt = hashWithSalt1
instance (Hashable a1, Hashable a2, Hashable a3,
Hashable a4) => Hashable1 ((,,,,) a1 a2 a3 a4) where
liftHashWithSalt = defaultLiftHashWithSalt
instance (Hashable a1, Hashable a2, Hashable a3)
=> Hashable2 ((,,,,) a1 a2 a3) where
liftHashWithSalt2 h1 h2 s (a1, a2, a3, a4, a5) =
(s `hashWithSalt` a1 `hashWithSalt` a2
`hashWithSalt` a3) `h1` a4 `h2` a5
instance (Hashable a1, Hashable a2, Hashable a3, Hashable a4, Hashable a5,
Hashable a6) => Hashable (a1, a2, a3, a4, a5, a6) where
hash (a1, a2, a3, a4, a5, a6) =
hash a1 `hashWithSalt` a2 `hashWithSalt` a3
`hashWithSalt` a4 `hashWithSalt` a5 `hashWithSalt` a6
hashWithSalt = hashWithSalt1
instance (Hashable a1, Hashable a2, Hashable a3, Hashable a4,
Hashable a5) => Hashable1 ((,,,,,) a1 a2 a3 a4 a5) where
liftHashWithSalt = defaultLiftHashWithSalt
instance (Hashable a1, Hashable a2, Hashable a3,
Hashable a4) => Hashable2 ((,,,,,) a1 a2 a3 a4) where
liftHashWithSalt2 h1 h2 s (a1, a2, a3, a4, a5, a6) =
(s `hashWithSalt` a1 `hashWithSalt` a2 `hashWithSalt` a3
`hashWithSalt` a4) `h1` a5 `h2` a6
instance (Hashable a1, Hashable a2, Hashable a3, Hashable a4, Hashable a5,
Hashable a6, Hashable a7) =>
Hashable (a1, a2, a3, a4, a5, a6, a7) where
hash (a1, a2, a3, a4, a5, a6, a7) =
hash a1 `hashWithSalt` a2 `hashWithSalt` a3
`hashWithSalt` a4 `hashWithSalt` a5 `hashWithSalt` a6 `hashWithSalt` a7
hashWithSalt s (a1, a2, a3, a4, a5, a6, a7) =
s `hashWithSalt` a1 `hashWithSalt` a2 `hashWithSalt` a3
`hashWithSalt` a4 `hashWithSalt` a5 `hashWithSalt` a6 `hashWithSalt` a7
instance (Hashable a1, Hashable a2, Hashable a3, Hashable a4, Hashable a5, Hashable a6) => Hashable1 ((,,,,,,) a1 a2 a3 a4 a5 a6) where
liftHashWithSalt = defaultLiftHashWithSalt
instance (Hashable a1, Hashable a2, Hashable a3, Hashable a4,
Hashable a5) => Hashable2 ((,,,,,,) a1 a2 a3 a4 a5) where
liftHashWithSalt2 h1 h2 s (a1, a2, a3, a4, a5, a6, a7) =
(s `hashWithSalt` a1 `hashWithSalt` a2 `hashWithSalt` a3
`hashWithSalt` a4 `hashWithSalt` a5) `h1` a6 `h2` a7
instance Hashable (StableName a) where
hash = hashStableName
hashWithSalt = defaultHashWithSalt
data SPInt = SP !Int !Int
instance Hashable a => Hashable [a] where
hashWithSalt = hashWithSalt1
instance Hashable1 [] where
liftHashWithSalt h salt arr = finalise (foldl' step (SP salt 0) arr)
where
finalise (SP s l) = hashWithSalt s l
step (SP s l) x = SP (h s x) (l + 1)
instance Hashable B.ByteString where
hashWithSalt salt bs = B.inlinePerformIO $
B.unsafeUseAsCStringLen bs $ \(p, len) ->
hashPtrWithSalt p (fromIntegral len) salt
instance Hashable BL.ByteString where
hashWithSalt = BL.foldlChunks hashWithSalt
#if MIN_VERSION_bytestring(0,10,4)
instance Hashable BSI.ShortByteString where
#if MIN_VERSION_base(4,3,0)
hashWithSalt salt sbs@(BSI.SBS ba) =
#else
hashWithSalt salt sbs@(BSI.SBS ba _) =
#endif
hashByteArrayWithSalt ba 0 (BSI.length sbs) salt
#endif
instance Hashable T.Text where
hashWithSalt salt (T.Text arr off len) =
hashByteArrayWithSalt (TA.aBA arr) (off `shiftL` 1) (len `shiftL` 1)
salt
instance Hashable TL.Text where
hashWithSalt = TL.foldlChunks hashWithSalt
hashThreadId :: ThreadId -> Int
hashThreadId (ThreadId t) = hash (fromIntegral (getThreadId t) :: Int)
foreign import ccall unsafe "rts_getThreadId" getThreadId
:: ThreadId# -> CInt
instance Hashable ThreadId where
hash = hashThreadId
hashWithSalt = defaultHashWithSalt
instance Hashable (Ptr a) where
hashWithSalt salt p = hashWithSalt salt $ ptrToIntPtr p
instance Hashable (FunPtr a) where
hashWithSalt salt p = hashWithSalt salt $ castFunPtrToPtr p
instance Hashable IntPtr where
hash n = fromIntegral n
hashWithSalt = defaultHashWithSalt
instance Hashable WordPtr where
hash n = fromIntegral n
hashWithSalt = defaultHashWithSalt
hashTypeRep :: TypeRep -> Int
#if __GLASGOW_HASKELL__ >= 710
hashTypeRep tr = let Fingerprint x _ = typeRepFingerprint tr in fromIntegral x
#elif __GLASGOW_HASKELL__ >= 702
hashTypeRep (TypeRep (Fingerprint x _) _ _) = fromIntegral x
#elif __GLASGOW_HASKELL__ >= 606
hashTypeRep = B.inlinePerformIO . typeRepKey
#else
hashTypeRep = hash . show
#endif
instance Hashable TypeRep where
hash = hashTypeRep
hashWithSalt = defaultHashWithSalt
#if MIN_VERSION_base(4,8,0)
instance Hashable Void where
hashWithSalt _ = absurd
#endif
hashPtr :: Ptr a
-> Int
-> IO Int
hashPtr p len = hashPtrWithSalt p len defaultSalt
hashPtrWithSalt :: Ptr a
-> Int
-> Int
-> IO Int
hashPtrWithSalt p len salt =
fromIntegral `fmap` c_hashCString (castPtr p) (fromIntegral len)
(fromIntegral salt)
foreign import ccall unsafe "hashable_fnv_hash" c_hashCString
:: CString -> CLong -> CLong -> IO CLong
hashByteArray :: ByteArray#
-> Int
-> Int
-> Int
hashByteArray ba0 off len = hashByteArrayWithSalt ba0 off len defaultSalt
hashByteArrayWithSalt
:: ByteArray#
-> Int
-> Int
-> Int
-> Int
hashByteArrayWithSalt ba !off !len !h =
fromIntegral $ c_hashByteArray ba (fromIntegral off) (fromIntegral len)
(fromIntegral h)
foreign import ccall unsafe "hashable_fnv_hash_offset" c_hashByteArray
:: ByteArray# -> CLong -> CLong -> CLong -> CLong
combine :: Int -> Int -> Int
combine h1 h2 = (h1 * 16777619) `xor` h2
instance Hashable Unique where
hash = hashUnique
hashWithSalt = defaultHashWithSalt
instance Hashable Version where
hashWithSalt salt (Version branch tags) =
salt `hashWithSalt` branch `hashWithSalt` tags
#if MIN_VERSION_base(4,7,0)
instance Hashable (Fixed a) where
hashWithSalt salt (MkFixed i) = hashWithSalt salt i
instance Hashable1 Fixed where
liftHashWithSalt _ salt (MkFixed i) = hashWithSalt salt i
#endif
#if MIN_VERSION_base(4,8,0)
instance Hashable a => Hashable (Identity a) where
hashWithSalt = hashWithSalt1
instance Hashable1 Identity where
liftHashWithSalt h salt (Identity x) = h salt x
#endif
instance Hashable a => Hashable (Const a b) where
hashWithSalt salt (Const x) = hashWithSalt salt x
instance Hashable a => Hashable1 (Const a) where
liftHashWithSalt = defaultLiftHashWithSalt
instance Hashable2 Const where
liftHashWithSalt2 f _ salt (Const x) = f salt x
#if MIN_VERSION_base(4,7,0)
instance Hashable (Proxy a) where
hash _ = 0
hashWithSalt s _ = s
instance Hashable1 Proxy where
liftHashWithSalt _ s _ = s
#endif
#if MIN_VERSION_base(4,9,0)
instance Hashable a => Hashable (NE.NonEmpty a) where
hashWithSalt p (a NE.:| as) = p `hashWithSalt` a `hashWithSalt` as
instance Hashable a => Hashable (Min a) where
hashWithSalt p (Min a) = hashWithSalt p a
instance Hashable a => Hashable (Max a) where
hashWithSalt p (Max a) = hashWithSalt p a
instance (Hashable a, Hashable b) => Hashable (Arg a b) where
hashWithSalt p (Arg a b) = hashWithSalt p a `hashWithSalt` b
instance Hashable a => Hashable (First a) where
hashWithSalt p (First a) = hashWithSalt p a
instance Hashable a => Hashable (Last a) where
hashWithSalt p (Last a) = hashWithSalt p a
instance Hashable a => Hashable (WrappedMonoid a) where
hashWithSalt p (WrapMonoid a) = hashWithSalt p a
instance Hashable a => Hashable (Option a) where
hashWithSalt p (Option a) = hashWithSalt p a
#endif
#if MIN_VERSION_base(4,9,0)
instance (Hashable1 f, Hashable1 g, Hashable a) => Hashable (Compose f g a) where
hashWithSalt = hashWithSalt1
instance (Hashable1 f, Hashable1 g) => Hashable1 (Compose f g) where
liftHashWithSalt h s = liftHashWithSalt (liftHashWithSalt h) s . getCompose
instance (Hashable1 f, Hashable1 g) => Hashable1 (FP.Product f g) where
liftHashWithSalt h s (FP.Pair a b) = liftHashWithSalt h (liftHashWithSalt h s a) b
instance (Hashable1 f, Hashable1 g, Hashable a) => Hashable (FP.Product f g a) where
hashWithSalt = hashWithSalt1
instance (Hashable1 f, Hashable1 g) => Hashable1 (FS.Sum f g) where
liftHashWithSalt h s (FS.InL a) = liftHashWithSalt h (s `combine` 0) a
liftHashWithSalt h s (FS.InR a) = liftHashWithSalt h (s `combine` distinguisher) a
instance (Hashable1 f, Hashable1 g, Hashable a) => Hashable (FS.Sum f g a) where
hashWithSalt = hashWithSalt1
#endif
data Hashed a = Hashed a !Int
deriving (Typeable)
hashed :: Hashable a => a -> Hashed a
hashed a = Hashed a (hash a)
unhashed :: Hashed a -> a
unhashed (Hashed a _) = a
instance Eq a => Eq (Hashed a) where
Hashed a ha == Hashed b hb = ha == hb && a == b
instance Ord a => Ord (Hashed a) where
Hashed a _ `compare` Hashed b _ = a `compare` b
instance Show a => Show (Hashed a) where
showsPrec d (Hashed a _) = showParen (d > 10) $
showString "hashed" . showChar ' ' . showsPrec 11 a
instance Hashable (Hashed a) where
hashWithSalt = defaultHashWithSalt
hash (Hashed _ h) = h
instance Hashable1 Hashed where
liftHashWithSalt _ s (Hashed _ h) = defaultHashWithSalt s h
instance (IsString a, Hashable a) => IsString (Hashed a) where
fromString s = let r = fromString s in Hashed r (hash r)
instance F.Foldable Hashed where
foldr f acc (Hashed a _) = f a acc
mapHashed :: Hashable b => (a -> b) -> Hashed a -> Hashed b
mapHashed f (Hashed a _) = hashed (f a)
traverseHashed :: (Hashable b, Functor f) => (a -> f b) -> Hashed a -> f (Hashed b)
traverseHashed f (Hashed a _) = fmap hashed (f a)
#if MIN_VERSION_base(4,9,0)
instance Eq1 Hashed where
liftEq f (Hashed a ha) (Hashed b hb) = ha == hb && f a b
instance Ord1 Hashed where
liftCompare f (Hashed a _) (Hashed b _) = f a b
instance Show1 Hashed where
liftShowsPrec sp _ d (Hashed a _) = showsUnaryWith sp "hashed" d a
#endif