packages feed

hashable 1.4.2.0 → 1.4.3.0

raw patch · 7 files changed

+74/−27 lines, 7 filesdep ~basedep ~bytestringdep ~deepseqPVP ok

version bump matches the API change (PVP)

Dependency ranges changed: base, bytestring, deepseq, text

API changes (from Hackage documentation)

+ Data.Hashable: defaultHash :: Hashable a => a -> Int
+ Data.Hashable: defaultHashWithSalt :: Hashable a => Int -> a -> Int

Files

CHANGES.md view
@@ -1,5 +1,11 @@ See also https://pvp.haskell.org/faq +## Version 1.4.3.0++ * Export `defaultHashWithSalt` and `defaultHash`.+ * Fix issue of tuples with 0 first component causing all-zero state.+ * Change `hashInt` to mix bits more.+ ## Version 1.4.2.0   * Fix the foreign signature of `getThreadId`
hashable.cabal view
@@ -1,6 +1,6 @@ cabal-version:      1.12 name:               hashable-version:            1.4.2.0+version:            1.4.3.0 synopsis:           A class for types that can be converted to a hash value description:   This package defines a class, 'Hashable', for types that@@ -8,6 +8,8 @@   exists for the benefit of hashing-based data   structures.  The package provides instances for   basic types and a way to combine hash values.+  .+  The 'Hashable' 'hash' values are not guaranteed to be stable across library versions, operating systems or architectures. For stable hashing use named hashes: SHA256, CRC32 etc.  homepage:           http://github.com/haskell-unordered-containers/hashable @@ -36,6 +38,7 @@    || ==9.0.2    || ==9.2.5    || ==9.4.4+   || ==9.6.1  extra-source-files:   CHANGES.md@@ -75,7 +78,7 @@   include-dirs:     include   hs-source-dirs:   src   build-depends:-      base        >=4.10.1.0 && <4.18+      base        >=4.10.1.0 && <4.19     , bytestring  >=0.10.8.2 && <0.12     , containers  >=0.5.10.2 && <0.7     , deepseq     >=1.4.3.0  && <1.5@@ -84,7 +87,7 @@     , text        >=1.2.3.0  && <1.3  || >=2.0 && <2.1    if !impl(ghc >=9.2)-    build-depends: base-orphans >=0.8.6 && <0.9+    build-depends: base-orphans >=0.8.6 && <0.10    if !impl(ghc >=9.4)     build-depends: data-array-byte >=0.1.0.1 && <0.2
src/Data/Hashable.hs view
@@ -60,6 +60,9 @@     , hashByteArray     , hashByteArrayWithSalt +    , defaultHashWithSalt+    , defaultHash+     -- * Caching hashes     , Hashed     , hashed
src/Data/Hashable/Class.hs view
@@ -50,6 +50,7 @@     , hashByteArray     , hashByteArrayWithSalt     , defaultHashWithSalt+    , defaultHash       -- * Higher Rank Functions     , hashWithSalt1     , hashWithSalt2@@ -228,7 +229,7 @@     -- Instances might want to implement this method to provide a more     -- efficient implementation than the default implementation.     hash :: a -> Int-    hash = hashWithSalt defaultSalt+    hash = defaultHash      default hashWithSalt :: (Generic a, GHashable Zero (Rep a)) => Int -> a -> Int     hashWithSalt = genericHashWithSalt@@ -293,9 +294,19 @@ -- cannot also provide a default implementation for that method for -- the non-generic instance use case. Instead we provide -- 'defaultHashWith'.+--+-- @since 1.4.3.0+-- defaultHashWithSalt :: Hashable a => Int -> a -> Int defaultHashWithSalt salt x = salt `hashInt` hash x +-- | Default implementation of 'hash' based on 'hashWithSalt'.+--+-- @since 1.4.3.0+--+defaultHash :: Hashable a => a -> Int+defaultHash = hashWithSalt defaultSalt+ -- | Transform a value into a 'Hashable' value, then hash the -- transformed value using the given salt. --@@ -533,7 +544,6 @@     liftHashWithSalt2 _ h s (Right b) = s `hashInt` 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@@ -543,7 +553,6 @@     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@@ -555,8 +564,6 @@  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@@ -568,9 +575,6 @@  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 s (a1, a2, a3, a4, a5) =         s `hashWithSalt` a1 `hashWithSalt` a2 `hashWithSalt` a3         `hashWithSalt` a4 `hashWithSalt` a5@@ -589,9 +593,6 @@  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 s (a1, a2, a3, a4, a5, a6) =         s `hashWithSalt` a1 `hashWithSalt` a2 `hashWithSalt` a3         `hashWithSalt` a4 `hashWithSalt` a5 `hashWithSalt` a6@@ -611,9 +612,6 @@ 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
src/Data/Hashable/Imports.hs view
@@ -5,9 +5,10 @@     Int64, Int32,     Word64, Word32,     xor, shiftR, shiftL,+    (.&.), ) where  import Prelude () import Data.Int (Int64, Int32) import Data.Word (Word64, Word32)-import Data.Bits (xor, shiftR, shiftL)+import Data.Bits (xor, shiftR, shiftL, (.&.))
src/Data/Hashable/LowLevel.hs view
@@ -61,11 +61,31 @@ -- | Hash 'Int'. First argument is a salt, second argument is an 'Int'. -- The result is new salt / hash value. hashInt :: Salt -> Int -> Salt+hashInt s x = s `rnd` x1 `rnd` x2 `rnd` x3 `rnd` x4+  where+    {-# INLINE rnd #-}+    {-# INLINE x1 #-}+    {-# INLINE x2 #-}+    {-# INLINE x3 #-}+    {-# INLINE x4 #-} #if WORD_SIZE_IN_BITS == 64-hashInt s x = (s * 1099511628211) `xor` x+    -- See https://github.com/haskell-unordered-containers/hashable/issues/270+    -- FNV-1 is defined to hash byte at the time.+    -- We used to hash whole Int at once, which provided very bad mixing.+    -- Current is a performance-quality compromise, we do four rounds per Int (instead of 8 for FNV-1 or 1 for previous hashable).+    rnd a b = (a * 1099511628211) `xor` b+    x1 = shiftR x 48 .&. 0xffff+    x2 = shiftR x 32 .&. 0xffff+    x3 = shiftR x 16 .&. 0xffff+    x4 =           x .&. 0xffff #else-hashInt s x = (s * 16777619) `xor` x+    rnd a b = (a * 16777619) `xor` b+    x1 = shiftR x 24 .&. 0xff+    x2 = shiftR x 16 .&. 0xff+    x3 = shiftR x  8 .&. 0xff+    x4 =           x .&. 0xff #endif+ -- Note: FNV-1 hash takes a byte of data at once, here we take an 'Int', -- which is 4 or 8 bytes. Whether that's bad or not, I don't know. 
tests/Regress.hs view
@@ -7,7 +7,8 @@ import qualified Test.Framework as F import Control.Monad (when) import Test.Framework.Providers.HUnit (testCase)-import Test.HUnit (assertFailure, (@=?))+import Test.HUnit (Assertion, assertFailure, (@?=))+import Test.Framework.Providers.QuickCheck2 (testProperty) import GHC.Generics (Generic) import Data.List (nub) import Data.Fixed (Pico)@@ -27,12 +28,17 @@  #include "MachDeps.h" +assertInequal :: Eq a => String -> a -> a -> Assertion+assertInequal msg x y+    | x == y    = assertFailure msg+    | otherwise = return ()+ regressions :: [F.Test] regressions = [] ++ #ifdef HAVE_MMAP     Mmap.regressions ++     [ testCase "Fixed" $ do-        (hash (1 :: Pico) == hash (2 :: Pico)) @=? False+        (hash (1 :: Pico) == hash (2 :: Pico)) @?= False     ] ++ #endif     [ F.testGroup "Generic: sum of nullary constructors"@@ -42,17 +48,27 @@         , testCase "3" $ nullaryCase 3 S3         , testCase "4" $ nullaryCase 4 S4         ]++    , testCase "Zero tuples: issue 271" $ do+        assertInequal "Hash of (0,0) != 0" (hash (0 :: Int, 0 :: Int)) 0+        assertInequal "Hash of (0,0,0) != 0" (hash (0 :: Int, 0 :: Int, 0 :: Int)) 0++    , testProperty "odd, odd: issue 271" $ \x' y' ->+        let x = if odd x' then x' else x' + 1 :: Int+            y = if odd y' then y' else y' + 1 :: Int+        in hash (x, y) /= hash (negate x, negate y)+     , testCase "Generic: Peano https://github.com/tibbe/hashable/issues/135" $ do         let ns = take 20 $ iterate S Z         let hs = map hash ns-        hs @=? nub hs+        hs @?= nub hs #if WORD_SIZE_IN_BITS == 64     , testCase "64 bit Text" $ do-        hash ("hello world" :: Text) @=?+        hash ("hello world" :: Text) @?= #if MIN_VERSION_text(2,0,0)-            4078614214911247440+            2589482369471999198 #else-            -3875242662334356092+            -1955893671357159554 #endif #endif     , F.testGroup "concatenation"@@ -103,7 +119,7 @@         let salt = 42         let expected = salt `hashWithSalt` n `hashWithSalt` ()         let actual = hashWithSalt salt s-        expected @=? actual+        actual @?= expected  data SumOfNullary = S0 | S1 | S2 | S3 | S4 deriving (Eq, Generic) instance Hashable SumOfNullary