Skip to content

Commit 634f494

Browse files
committed
Rework the Generic hashable for sums
1 parent a31d95b commit 634f494

File tree

2 files changed

+44
-15
lines changed

2 files changed

+44
-15
lines changed

Data/Hashable/Generic.hs

+10-13
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@ import Data.Bits (shiftR)
2222
import Data.Hashable.Class
2323
import GHC.Generics
2424

25-
2625
-- Type without constructors
2726
instance GHashable arity V1 where
2827
ghashWithSalt _ salt _ = hashWithSalt salt ()
@@ -52,25 +51,23 @@ instance Hashable1 f => GHashable One (Rec1 f) where
5251
instance (Hashable1 f, GHashable One g) => GHashable One (f :.: g) where
5352
ghashWithSalt targs salt = liftHashWithSalt (ghashWithSalt targs) salt . unComp1
5453

55-
class GSum arity f where
56-
hashSum :: HashArgs arity a -> Int -> Int -> Int -> f a -> Int
54+
class SumSize f => GSum arity f where
55+
hashSum :: HashArgs arity a -> Int -> Int -> f a -> Int
56+
-- hashSum args salt offset value = ...
5757

58-
instance (GSum arity a, GSum arity b, SumSize a, SumSize b) => GHashable arity (a :+: b) where
59-
ghashWithSalt toHash salt = hashSum toHash salt 0 size
60-
where size = unTagged (sumSize :: Tagged (a :+: b))
58+
instance (GSum arity a, GSum arity b) => GHashable arity (a :+: b) where
59+
ghashWithSalt toHash salt = hashSum toHash salt 0
6160

6261
instance (GSum arity a, GSum arity b) => GSum arity (a :+: b) where
63-
hashSum toHash !salt !code !size s = case s of
64-
L1 x -> hashSum toHash salt code sizeL x
65-
R1 x -> hashSum toHash salt (code + sizeL) sizeR x
62+
hashSum toHash !salt !offset s = case s of
63+
L1 x -> hashSum toHash salt offset x
64+
R1 x -> hashSum toHash salt (offset + sizeL) x
6665
where
67-
sizeL = size `shiftR` 1
68-
sizeR = size - sizeL
66+
sizeL = unTagged (sumSize :: Tagged a)
6967
{-# INLINE hashSum #-}
7068

7169
instance GHashable arity a => GSum arity (C1 c a) where
72-
-- hashSum toHash !salt !code _ (M1 x) = ghashWithSalt toHash (hashWithSalt salt code) x
73-
hashSum toHash !salt !code _ (M1 x) = hashWithSalt salt (ghashWithSalt toHash code x)
70+
hashSum toHash !salt !offset (M1 x) = ghashWithSalt toHash (hashWithSalt salt offset) x
7471
{-# INLINE hashSum #-}
7572

7673
class SumSize f where

tests/Regress.hs

+34-2
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,47 @@
11
{-# LANGUAGE CPP #-}
2+
{-# LANGUAGE DeriveGeneric #-}
23

34
module Regress (regressions) where
45

56
import qualified Test.Framework as F
7+
import Test.Framework.Providers.HUnit (testCase)
8+
import Test.HUnit ((@=?))
9+
import GHC.Generics (Generic)
10+
import Data.List (nub)
611

712
#ifdef HAVE_MMAP
813
import qualified Regress.Mmap as Mmap
914
#endif
1015

16+
import Data.Hashable
17+
1118
regressions :: [F.Test]
12-
regressions = []
19+
regressions = [] ++
1320
#ifdef HAVE_MMAP
14-
++ Mmap.regressions
21+
Mmap.regressions ++
1522
#endif
23+
[ F.testGroup "Generic: sum of nullary constructors"
24+
[ testCase "0" $ nullaryCase 0 S0
25+
, testCase "1" $ nullaryCase 1 S1
26+
, testCase "2" $ nullaryCase 2 S2
27+
, testCase "3" $ nullaryCase 3 S3
28+
, testCase "4" $ nullaryCase 4 S4
29+
]
30+
, testCase "Generic: Peano https://github.com/tibbe/hashable/issues/135" $ do
31+
let ns = take 20 $ iterate S Z
32+
let hs = map hash ns
33+
hs @=? nub hs
34+
]
35+
where
36+
nullaryCase :: Int -> SumOfNullary -> IO ()
37+
nullaryCase n s = do
38+
let salt = 42
39+
let expected = salt `hashWithSalt` n `hashWithSalt` ()
40+
let actual = hashWithSalt salt s
41+
expected @=? actual
42+
43+
data SumOfNullary = S0 | S1 | S2 | S3 | S4 deriving (Generic)
44+
instance Hashable SumOfNullary
45+
46+
data Nat = Z | S Nat deriving (Generic)
47+
instance Hashable Nat

0 commit comments

Comments
 (0)