large-hashable-0.1.3.0: src/Data/LargeHashable/Class.hs
-- | This module defines the central type class `LargeHashable` of this package.
{-# LANGUAGE BangPatterns #-}
{-# LANGUAGE CPP #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE DefaultSignatures #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeOperators #-}
module Data.LargeHashable.Class (
LargeHashable(..), largeHash, largeHashStable, LargeHashable'(..), genericUpdateHash,
updateHashList
) where
-- keep imports in alphabetic order (in Emacs, use "M-x sort-lines")
import Data.Bits
import Data.Char (ord)
import Data.Fixed
import Data.Foldable
import Data.Int
import Data.LargeHashable.Endianness
import Data.LargeHashable.Intern
import Data.Ratio
import Data.Time
import Data.Time.Clock.TAI
import Data.Void (Void)
import Data.Word
import Foreign.C.Types
import Foreign.Ptr
import GHC.Float (castDoubleToWord64, castFloatToWord32)
import GHC.Generics
import qualified Data.Aeson as J
#if MIN_VERSION_aeson(2,0,0)
import qualified Data.Aeson.Key as AesonKey
import qualified Data.Aeson.KeyMap as AesonKeyMap
#endif
import qualified Data.ByteString as B
import qualified Data.ByteString.Lazy as BL
import qualified Data.ByteString.Lazy.Internal as BLI
import qualified Data.ByteString.Short as BS
import qualified Data.Foldable as F
import qualified Data.HashMap.Lazy as HashMap
import qualified Data.HashSet as HashSet
import qualified Data.IntMap as IntMap
import qualified Data.IntSet as IntSet
import qualified Data.Map as M
import qualified Data.Scientific as Sci
import qualified Data.Sequence as Seq
import qualified Data.Set as S
import qualified Data.Strict.Tuple as Tuple
import qualified Data.Text as T
import qualified Data.Text.Encoding as TE
import qualified Data.Text.Foreign as TF
import qualified Data.Text.Internal.Lazy as TLI
import qualified Data.Text.Lazy as TL
import qualified Data.Vector as V
import Data.Kind (Type)
-- | A type class for computing hashes (i.e. MD5, SHA256, ...) from
-- haskell values.
--
-- The laws of this typeclass are the following:
--
-- (1) If two values are equal
-- according to '==', then the finally computed hashes must also be equal
-- according to '=='. However it is not required that the hashes of inequal
-- values have to be inequal. Also note that an instance of 'LargeHashable'
-- does not require a instance of 'Eq'. Using any sane algorithm the chance
-- of a collision should be 1 / n where n is the number of different hashes
-- possible.
--
-- (2) If two values are inequal
-- according to '==', then the probability of a hash collision is 1/n,
-- where n is the number of possible hashes produced by the
-- underlying hash algorithm.
--
-- A rule of thumb: hash all information that you would also need for
-- serializing/deserializing values of your datatype. For instance, when
-- hashing lists, you would not only hash the list elements but also the
-- length of the list. Consider the following datatype
--
-- > data Foo = Foo [Int] [Int]
--
-- We now write an instance for LargeHashable like this
--
-- > instance LargeHashable Foo where
-- > updateHash (Foo l1 l2) = updateHash l1 >> updateHash l2
--
-- If we did not hash the length of a list, then the following two values
-- of @Foo@ would produce identical hashes:
--
-- > Foo [1,2,3] []
-- > Foo [1] [2,3]
--
class LargeHashable a where
updateHash :: a -> LH ()
default updateHash :: (GenericLargeHashable (Rep a), Generic a) => a -> LH ()
updateHash = genericUpdateHash
updateHashStable :: a -> LH ()
default updateHashStable :: (GenericLargeHashable (Rep a), Generic a) => a -> LH ()
updateHashStable = genericUpdateHashStable
class LargeHashable' t where
updateHash' :: LargeHashable a => t a -> LH ()
updateHashStable' :: LargeHashable a => t a -> LH ()
-- | 'largeHash' is the central function of this package.
-- For a given value it computes a 'Hash' using the given
-- 'HashAlgorithm'. The library tries to keep the
-- hash values for @LargeHashable@ instances provided by
-- library stable across releases, but there is no guarantee.
-- See @largeHashStable&
largeHash :: LargeHashable a => HashAlgorithm h -> a -> h
largeHash algo x = runLH algo (updateHash x)
-- | 'largeHashStable' is similar to @largeHash@, but the hash
-- value is guaranteed to remain stable across releases,
-- even if this causes performance to degrade.
largeHashStable :: LargeHashable a => HashAlgorithm h -> a -> h
largeHashStable algo x = runLH algo (updateHashStable x)
{-# INLINE updateHashTextData #-}
updateHashTextData :: T.Text -> LH ()
updateHashTextData !t = do
updates <- hashUpdates
ioInLH $ do
#if MIN_VERSION_text(2,0,0)
TF.useAsPtr t $ \(valPtr :: Ptr Word8) (units :: TF.I8) ->
hu_updatePtr updates (castPtr valPtr) (fromIntegral units)
#else
-- UTF-16 encoding
TF.useAsPtr t $ \(valPtr :: Ptr Word16) (units :: TF.I16) ->
hu_updatePtr updates (castPtr valPtr) (fromIntegral (2 * units))
#endif
return ()
{-# INLINE updateHashText #-}
updateHashText :: T.Text -> LH ()
updateHashText !t = do
updateHashTextData t
updates <- hashUpdates
ioInLH $ hu_updateULong updates (fromIntegral (T.length t))
{-# INLINE updateHashStableTextData #-}
updateHashStableTextData :: T.Text -> LH ()
updateHashStableTextData t = do
let bs =
case systemEndianness of
LittleEndian -> TE.encodeUtf16LE t
BigEndian -> TE.encodeUtf16BE t
updateHashByteStringData bs
{-# INLINE updateHashStableText #-}
updateHashStableText :: T.Text -> LH ()
updateHashStableText t = do
updateHashStableTextData t
updates <- hashUpdates
ioInLH $ hu_updateULong updates (fromIntegral (T.length t))
instance LargeHashable T.Text where
updateHash = updateHashText
updateHashStable = updateHashStableText
{-# INLINE updateHashLazyText #-}
updateHashLazyText :: Int -> TL.Text -> LH ()
updateHashLazyText !len (TLI.Chunk !t !next) = do
updateHashTextData t
updateHashLazyText (len + T.length t) next
updateHashLazyText !len TLI.Empty = updateHash len
{-# INLINE updateHashStableLazyText #-}
updateHashStableLazyText :: Int -> TL.Text -> LH ()
updateHashStableLazyText !len (TLI.Chunk !t !next) = do
updateHashStableTextData t
updateHashStableLazyText (len + T.length t) next
updateHashStableLazyText !len TLI.Empty = updateHash len
instance LargeHashable TL.Text where
updateHash = updateHashLazyText 0
updateHashStable = updateHashStableLazyText 0
{-# INLINE updateHashByteStringData #-}
updateHashByteStringData :: B.ByteString -> LH ()
updateHashByteStringData !b = do
updates <- hashUpdates
ioInLH $ do
ptr <- B.useAsCString b return
hu_updatePtr updates (castPtr ptr) (B.length b)
{-# INLINE updateHashByteString #-}
updateHashByteString :: B.ByteString -> LH ()
updateHashByteString !b = do
updateHashByteStringData b
updates <- hashUpdates
ioInLH $ hu_updateULong updates (fromIntegral (B.length b))
instance LargeHashable B.ByteString where
updateHash = updateHashByteString
updateHashStable = updateHash
{-# INLINE updateHashLazyByteString #-}
updateHashLazyByteString :: Int -> BL.ByteString -> LH ()
updateHashLazyByteString !len (BLI.Chunk !bs !next) = do
updateHashByteStringData bs
updateHashLazyByteString (len + B.length bs) next
updateHashLazyByteString !len BLI.Empty = updateHash len
instance LargeHashable BL.ByteString where
updateHash = updateHashLazyByteString 0
updateHashStable = updateHash
instance LargeHashable BS.ShortByteString where
updateHash = updateHash . BS.fromShort
updateHashStable = updateHash
{-# INLINE updateHashWithFun #-}
updateHashWithFun :: (HashUpdates -> a -> IO ()) -> a -> LH ()
updateHashWithFun f x =
do updates <- hashUpdates
ioInLH $ f updates x
instance LargeHashable Int where
updateHash = updateHashWithFun hu_updateULong . fromIntegral
updateHashStable = updateHash
instance LargeHashable Int8 where
updateHash = updateHashWithFun hu_updateUChar . fromIntegral
updateHashStable = updateHash
instance LargeHashable Int16 where
updateHash = updateHashWithFun hu_updateUShort . fromIntegral
updateHashStable = updateHash
instance LargeHashable Int32 where
updateHash = updateHashWithFun hu_updateUInt . fromIntegral
updateHashStable = updateHash
instance LargeHashable Int64 where
updateHash = updateHashWithFun hu_updateULong . fromIntegral
updateHashStable = updateHash
instance LargeHashable Word where
updateHash = updateHashWithFun hu_updateULong . fromIntegral
updateHashStable = updateHash
instance LargeHashable Word8 where
updateHash = updateHashWithFun hu_updateUChar
updateHashStable = updateHash
instance LargeHashable Word16 where
updateHash = updateHashWithFun hu_updateUShort
updateHashStable = updateHash
instance LargeHashable Word32 where
updateHash = updateHashWithFun hu_updateUInt
updateHashStable = updateHash
instance LargeHashable Word64 where
updateHash = updateHashWithFun hu_updateULong . fromIntegral
updateHashStable = updateHash
instance LargeHashable CChar where
updateHash (CChar i) = updateHashWithFun hu_updateUChar (fromIntegral i)
updateHashStable = updateHash
instance LargeHashable CShort where
updateHash (CShort i) = updateHashWithFun hu_updateUShort (fromIntegral i)
updateHashStable = updateHash
instance LargeHashable CInt where
updateHash (CInt i) = updateHashWithFun hu_updateUInt (fromIntegral i)
updateHashStable = updateHash
instance LargeHashable CLong where
updateHash (CLong i) = updateHashWithFun hu_updateULong (fromIntegral i)
updateHashStable = updateHash
instance LargeHashable CUChar where
updateHash (CUChar w) = updateHashWithFun hu_updateUChar w
updateHashStable = updateHash
instance LargeHashable CUShort where
updateHash (CUShort w) = updateHashWithFun hu_updateUShort w
updateHashStable = updateHash
instance LargeHashable CUInt where
updateHash (CUInt w) = updateHashWithFun hu_updateUInt w
updateHashStable = updateHash
instance LargeHashable CULong where
updateHash (CULong w) = updateHashWithFun hu_updateULong (fromIntegral w)
updateHashStable = updateHash
instance LargeHashable Char where
updateHash = updateHashWithFun hu_updateUInt . c2w
updateHashStable = updateHash
c2w :: Char -> Word32
{-# INLINE c2w #-}
c2w c = toEnum (ord c :: Int)
{-# INLINE updateHashInteger #-}
updateHashInteger :: Integer -> LH ()
updateHashInteger !i
| i == 0 = updateHash (0 :: CUChar)
| i > 0 = do
updateHash (fromIntegral (i .&. 0xffffffffffffffff) :: CULong)
updateHashInteger (shift i (-64))
| otherwise = do
updateHash (0 :: CUChar) -- prepend 0 to show it is negative
updateHashInteger (abs i)
instance LargeHashable Integer where
updateHash = updateHashInteger
updateHashStable = updateHash
instance LargeHashable Double where
updateHash = updateHash . castDoubleToWord64
updateHashStable = updateHash
instance LargeHashable Float where
updateHash = updateHash . castFloatToWord32
updateHashStable = updateHash
{-# INLINE updateHashFixed #-}
updateHashFixed :: HasResolution a => Fixed a -> LH ()
updateHashFixed f = updateHash (truncate . (* f) . fromInteger $ resolution f :: Integer)
instance HasResolution a => LargeHashable (Fixed a) where
updateHash = updateHashFixed
updateHashStable = updateHash
{-# INLINE updateHashBool #-}
updateHashBool :: Bool -> LH ()
updateHashBool True = updateHash (1 :: CUChar)
updateHashBool False = updateHash (0 :: CUChar)
instance LargeHashable Bool where
updateHash = updateHashBool
updateHashStable = updateHash
{-# INLINE updateHashList #-}
updateHashList :: forall a. (a -> LH ()) -> [a] -> LH ()
updateHashList f = loop 0
where
loop :: Int -> [a] -> LH ()
loop !i [] =
updateHash i
loop !i (x:xs) = do
f x
loop (i + 1) xs
instance LargeHashable a => LargeHashable [a] where
updateHash = updateHashList updateHash
updateHashStable = updateHashList updateHashStable
{-# INLINE setFoldFun #-}
setFoldFun :: LargeHashable a => (a -> LH ()) -> LH () -> a -> LH ()
setFoldFun f action value = action >> f value
{-# INLINE updateHashSet #-}
updateHashSet :: LargeHashable a => (a -> LH ()) -> S.Set a -> LH ()
updateHashSet !f !set = do
foldl' (setFoldFun f) (return ()) set -- Note: foldl' for sets traverses the elements in asc order
updateHash (S.size set)
instance LargeHashable a => LargeHashable (S.Set a) where
updateHash = updateHashSet updateHash
updateHashStable = updateHashSet updateHashStable
{-# INLINE updateHashIntSet #-}
updateHashIntSet :: IntSet.IntSet -> LH ()
updateHashIntSet !set = do
IntSet.foldl' (setFoldFun updateHash) (return ()) set
updateHash (IntSet.size set)
-- Lazy and Strict IntSet share the same definition
instance LargeHashable IntSet.IntSet where
updateHash = updateHashIntSet
updateHashStable = updateHash
{-# INLINE updateHashHashSet #-}
updateHashHashSet :: LargeHashable a => (a -> LH ()) -> HashSet.HashSet a -> LH ()
updateHashHashSet !f !set =
-- The ordering of elements in a set does not matter. A HashSet does not
-- offer an efficient way of exctracting its elements in some specific
-- ordering. So we use the auxiliary function 'hashListModuloOrdering'.
hashListModuloOrdering f (HashSet.size set) (HashSet.toList set)
-- | Hashes a list of values such the two permutations of the same list
-- yields the same hash.
hashListModuloOrdering :: LargeHashable a => (a -> LH ()) -> Int -> [a] -> LH ()
hashListModuloOrdering f len list =
do updateXorHash (map f list)
updateHash len
-- Lazy and Strict HashSet share the same definition
instance LargeHashable a => LargeHashable (HashSet.HashSet a) where
updateHash = updateHashHashSet updateHash
updateHashStable = updateHashHashSet updateHashStable
{-# INLINE mapFoldFun #-}
mapFoldFun :: (LargeHashable k, LargeHashable a) =>
(k -> LH ()) -> (a -> LH ()) -> LH () -> k -> a -> LH ()
mapFoldFun kf vf action key value = action >> kf key >> vf value
{-# INLINE updateHashMap #-}
updateHashMap :: (LargeHashable k, LargeHashable a) =>
(k -> LH ()) -> (a -> LH ()) -> M.Map k a -> LH ()
updateHashMap !kf !vf !m = do
M.foldlWithKey' (mapFoldFun kf vf) (return ()) m
updateHash (M.size m)
-- Lazy and Strict Map share the same definition
instance (LargeHashable k, LargeHashable a) => LargeHashable (M.Map k a) where
updateHash = updateHashMap updateHash updateHash
updateHashStable = updateHashMap updateHashStable updateHashStable
{-# INLINE updateHashIntMap #-}
updateHashIntMap :: LargeHashable a => (a -> LH ()) -> IntMap.IntMap a -> LH ()
updateHashIntMap !f !m = do
IntMap.foldlWithKey' (mapFoldFun updateHash f) (return ()) m
updateHash (IntMap.size m)
-- Lazy and Strict IntMap share the same definition
instance LargeHashable a => LargeHashable (IntMap.IntMap a) where
updateHash = updateHashIntMap updateHash
updateHashStable = updateHashIntMap updateHashStable
updateHashHashMap :: (LargeHashable k, LargeHashable v) =>
((k, v) -> LH ()) -> HashMap.HashMap k v -> LH ()
updateHashHashMap !f !m =
-- The ordering of elements in a map do not matter. A HashMap does not
-- offer an efficient way of exctracting its elements in some specific
-- ordering. So we use the auxiliary function 'hashListModuloOrdering'.
hashListModuloOrdering f (HashMap.size m) (HashMap.toList m)
-- Lazy and Strict HashMap share the same definition
instance (LargeHashable k, LargeHashable v) => LargeHashable (HashMap.HashMap k v) where
updateHash = updateHashHashMap updateHash
updateHashStable = updateHashHashMap updateHashStable
instance (LargeHashable a, LargeHashable b) => LargeHashable (a, b) where
updateHash (!a, !b) = updateHash a >> updateHash b
updateHashStable (!a, !b) = updateHashStable a >> updateHashStable b
instance (LargeHashable a, LargeHashable b, LargeHashable c) => LargeHashable (a, b, c) where
updateHash (a, b, c) = updateHash a >> updateHash b >> updateHash c
updateHashStable (a, b, c) = updateHashStable a >> updateHashStable b >> updateHashStable c
instance (LargeHashable a, LargeHashable b, LargeHashable c, LargeHashable d) => LargeHashable (a, b, c, d) where
updateHash (a, b, c, d) = updateHash a >> updateHash b >> updateHash c >> updateHash d
updateHashStable (a, b, c, d) =
updateHashStable a >> updateHashStable b >> updateHashStable c >> updateHashStable d
instance (LargeHashable a, LargeHashable b, LargeHashable c, LargeHashable d, LargeHashable e) => LargeHashable (a, b, c, d, e) where
updateHash (a, b, c, d, e) =
updateHash a >> updateHash b >> updateHash c >> updateHash d >> updateHash e
updateHashStable (a, b, c, d, e) =
updateHashStable a >> updateHashStable b >> updateHashStable c >> updateHashStable d >> updateHashStable e
instance LargeHashable a => LargeHashable (Maybe a) where
updateHash Nothing = updateHash (0 :: CULong)
updateHash (Just !x) = updateHash (1 :: CULong) >> updateHash x
updateHashStable Nothing = updateHash (0 :: CULong)
updateHashStable (Just !x) = updateHash (1 :: CULong) >> updateHashStable x
instance (LargeHashable a, LargeHashable b) => LargeHashable (Either a b) where
updateHash (Left !l) = updateHash (0 :: CULong) >> updateHash l
updateHash (Right !r) = updateHash (1 :: CULong) >> updateHash r
updateHashStable (Left !l) = updateHash (0 :: CULong) >> updateHashStable l
updateHashStable (Right !r) = updateHash (1 :: CULong) >> updateHashStable r
instance LargeHashable () where
updateHash () = return ()
updateHashStable () = return ()
instance LargeHashable Ordering where
updateHash EQ = updateHash (0 :: CULong)
updateHash GT = updateHash (-1 :: CULong)
updateHash LT = updateHash (1 :: CULong)
updateHashStable = updateHash
instance (Integral a, LargeHashable a) => LargeHashable (Ratio a) where
updateHash !i = do
updateHash $ numerator i
updateHash $ denominator i
updateHashStable = updateHash
instance LargeHashable AbsoluteTime where
updateHash t = updateHash $ diffAbsoluteTime t taiEpoch
updateHashStable = updateHash
instance LargeHashable DiffTime where
-- could be replaced by diffTimeToPicoseconds as soon as
-- time 1.6 becomes more common
updateHash = updateHash . (fromRational . toRational :: DiffTime -> Pico)
updateHashStable = updateHash
instance LargeHashable NominalDiffTime where
updateHash = updateHash . (fromRational . toRational :: NominalDiffTime -> Pico)
updateHashStable = updateHash
instance LargeHashable LocalTime where
updateHash (LocalTime d tod) = updateHash d >> updateHash tod
updateHashStable = updateHash
instance LargeHashable ZonedTime where
updateHash (ZonedTime lt tz) = updateHash lt >> updateHash tz
updateHashStable = updateHash
instance LargeHashable TimeOfDay where
updateHash (TimeOfDay h m s) = updateHash h >> updateHash m >> updateHash s
updateHashStable = updateHash
instance LargeHashable TimeZone where
updateHash (TimeZone mintz summerOnly name) =
updateHash mintz >> updateHash summerOnly >> updateHash name
updateHashStable (TimeZone mintz summerOnly name) =
updateHashStable mintz >> updateHashStable summerOnly >> updateHashStable name
instance LargeHashable UTCTime where
updateHash (UTCTime d dt) = updateHash d >> updateHash dt
updateHashStable = updateHash
instance LargeHashable Day where
updateHash (ModifiedJulianDay d) = updateHash d
updateHashStable = updateHash
instance LargeHashable UniversalTime where
updateHash (ModJulianDate d) = updateHash d
updateHashStable = updateHash
instance LargeHashable a => LargeHashable (V.Vector a) where
updateHash = updateHash . V.toList
updateHashStable = updateHashStable . V.toList
instance (LargeHashable a, LargeHashable b) => LargeHashable (Tuple.Pair a b) where
updateHash (x Tuple.:!: y) =
do updateHash x
updateHash y
updateHashStable (x Tuple.:!: y) =
do updateHashStable x
updateHashStable y
instance LargeHashable Sci.Scientific where
updateHash notNormalized =
do let n = Sci.normalize notNormalized
updateHash (Sci.coefficient n)
updateHash (Sci.base10Exponent n)
updateHashStable = updateHash
updateHashJson :: (forall a . LargeHashable a => a -> LH ()) -> J.Value -> LH ()
updateHashJson f v =
case v of
J.Object obj ->
do updateHash (0::Int)
f obj
J.Array arr ->
do updateHash (1::Int)
f arr
J.String t ->
do updateHash (2::Int)
f t
J.Number n ->
do updateHash (3::Int)
f n
J.Bool b ->
do updateHash (4::Int)
f b
J.Null ->
updateHash (5::Int)
instance LargeHashable J.Value where
updateHash = updateHashJson updateHash
updateHashStable = updateHashJson updateHashStable
#if MIN_VERSION_aeson(2,0,0)
instance LargeHashable J.Key where
updateHash = updateHash . AesonKey.toText
updateHashStable = updateHashStable . AesonKey.toText
instance LargeHashable v => LargeHashable (AesonKeyMap.KeyMap v) where
updateHash v = updateHash (AesonKeyMap.toHashMap v)
updateHashStable v = updateHashStable (AesonKeyMap.toHashMap v)
#endif
instance LargeHashable Void where
updateHash _ = error "I'm void"
instance LargeHashable a => LargeHashable (Seq.Seq a) where
updateHash = updateHash . F.toList
updateHashStable = updateHashStable . F.toList
genericUpdateHash :: (Generic a, GenericLargeHashable (Rep a)) => a -> LH ()
genericUpdateHash = updateHashGeneric . from
{-# INLINE genericUpdateHash #-}
genericUpdateHashStable :: (Generic a, GenericLargeHashable (Rep a)) => a -> LH ()
genericUpdateHashStable = updateHashStableGeneric . from
{-# INLINE genericUpdateHashStable #-}
-- | Support for generically deriving 'LargeHashable' instances.
-- Any instance of the type class 'GHC.Generics.Generic' can be made
-- an instance of 'LargeHashable' by an empty instance declaration.
class GenericLargeHashable f where
updateHashGeneric :: f p -> LH ()
updateHashStableGeneric :: f p -> LH ()
instance GenericLargeHashable V1 where
{-# INLINE updateHashGeneric #-}
updateHashGeneric = undefined
updateHashStableGeneric = undefined
instance GenericLargeHashable U1 where
{-# INLINE updateHashGeneric #-}
updateHashGeneric U1 = updateHash ()
updateHashStableGeneric U1 = updateHashStable ()
instance (GenericLargeHashable f, GenericLargeHashable g) => GenericLargeHashable (f :*: g) where
{-# INLINE updateHashGeneric #-}
updateHashGeneric (x :*: y) = updateHashGeneric x >> updateHashGeneric y
updateHashStableGeneric (x :*: y) = updateHashStableGeneric x >> updateHashStableGeneric y
instance (GenericLargeHashable f, GenericLargeHashableSum g) => GenericLargeHashable (f :+: g) where
{-# INLINE updateHashGeneric #-}
updateHashGeneric x = updateHashGenericSum x 0
updateHashStableGeneric x = updateHashStableGenericSum x 0
instance LargeHashable c => GenericLargeHashable (K1 i c) where
{-# INLINE updateHashGeneric #-}
updateHashGeneric x = updateHash (unK1 x)
updateHashStableGeneric x = updateHashStable (unK1 x)
-- ignore meta-info (for now)
instance (GenericLargeHashable f) => GenericLargeHashable (M1 i t f) where
{-# INLINE updateHashGeneric #-}
updateHashGeneric x = updateHashGeneric (unM1 x)
updateHashStableGeneric x = updateHashStableGeneric (unM1 x)
class GenericLargeHashableSum (f :: Type -> Type) where
updateHashGenericSum :: f p -> Int -> LH ()
updateHashStableGenericSum :: f p -> Int -> LH ()
instance (GenericLargeHashable f, GenericLargeHashableSum g)
=> GenericLargeHashableSum (f :+: g) where
{-# INLINE updateHashGenericSum #-}
updateHashGenericSum (L1 x) !p = do
updateHash p
updateHashGeneric x
updateHashGenericSum (R1 x) !p = updateHashGenericSum x (p+1)
updateHashStableGenericSum (L1 x) !p = do
updateHashStable p
updateHashStableGeneric x
updateHashStableGenericSum (R1 x) !p = updateHashStableGenericSum x (p+1)
instance (GenericLargeHashable f) => GenericLargeHashableSum (M1 i t f) where
{-# INLINE updateHashGenericSum #-}
updateHashGenericSum x !p = do
updateHash p
updateHashGeneric (unM1 x)
updateHashStableGenericSum x !p = do
updateHashStable p
updateHashStableGeneric (unM1 x)