File: Generic.hs

package info (click to toggle)
haskell-hashable 1.2.1.0-5
  • links: PTS, VCS
  • area: main
  • in suites: jessie, jessie-kfreebsd
  • size: 196 kB
  • ctags: 39
  • sloc: haskell: 975; ansic: 456; makefile: 3
file content (74 lines) | stat: -rw-r--r-- 2,396 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
{-# LANGUAGE BangPatterns, FlexibleInstances, KindSignatures,
             ScopedTypeVariables, TypeOperators #-}
{-# OPTIONS_GHC -fno-warn-orphans #-}

------------------------------------------------------------------------
-- |
-- Module      :  Data.Hashable.Generic
-- Copyright   :  (c) Bryan O'Sullivan 2012
-- License     :  BSD-style
-- Maintainer  :  bos@serpentine.com
-- Stability   :  provisional
-- Portability :  GHC >= 7.2
--
-- Hashable support for GHC generics.

module Data.Hashable.Generic
    (
    ) where

import Data.Bits (Bits, shiftR)
import Data.Hashable.Class
import GHC.Generics

-- Type without constructors
instance GHashable V1 where
    ghashWithSalt salt _ = hashWithSalt salt ()

-- Constructor without arguments
instance GHashable U1 where
    ghashWithSalt salt U1 = hashWithSalt salt ()

instance (GHashable a, GHashable b) => GHashable (a :*: b) where
    ghashWithSalt salt (x :*: y) = salt `ghashWithSalt` x `ghashWithSalt` y

-- Metadata (constructor name, etc)
instance GHashable a => GHashable (M1 i c a) where
    ghashWithSalt salt = ghashWithSalt salt . unM1

-- Constants, additional parameters, and rank-1 recursion
instance Hashable a => GHashable (K1 i a) where
    ghashWithSalt = hashUsing unK1

class GSum f where
    hashSum :: Int -> Int -> Int -> f a -> Int

instance (GSum a, GSum b, GHashable a, GHashable b,
          SumSize a, SumSize b) => GHashable (a :+: b) where
    ghashWithSalt salt = hashSum salt 0 size
        where size = unTagged (sumSize :: Tagged (a :+: b))

instance (GSum a, GSum b, GHashable a, GHashable b) => GSum (a :+: b) where
    hashSum !salt !code !size s = case s of
                                    L1 x -> hashSum salt code           sizeL x
                                    R1 x -> hashSum salt (code + sizeL) sizeR x
        where
          sizeL = size `shiftR` 1
          sizeR = size - sizeL
    {-# INLINE hashSum #-}

instance GHashable a => GSum (C1 c a) where
    hashSum !salt !code _ x = salt `hashWithSalt` code `ghashWithSalt` x
    {-# INLINE hashSum #-}

class SumSize f where
    sumSize :: Tagged f

newtype Tagged (s :: * -> *) = Tagged {unTagged :: Int}

instance (SumSize a, SumSize b) => SumSize (a :+: b) where
    sumSize = Tagged $ unTagged (sumSize :: Tagged a) +
                       unTagged (sumSize :: Tagged b)

instance SumSize (C1 c a) where
    sumSize = Tagged 1