hashable 1.1.1.0 → 1.1.2.0
raw patch · 3 files changed
+109/−49 lines, 3 filesdep +QuickCheckdep +hashabledep +randomdep ~textPVP ok
version bump matches the API change (PVP)
Dependencies added: QuickCheck, hashable, random, test-framework, test-framework-quickcheck2
Dependency ranges changed: text
API changes (from Hackage documentation)
+ Data.Hashable: instance (Integral a, Hashable a) => Hashable (Ratio a)
+ Data.Hashable: instance Hashable (StableName a)
+ Data.Hashable: instance Hashable Double
+ Data.Hashable: instance Hashable Float
+ Data.Hashable: instance Hashable Integer
Files
- CHANGES +6/−0
- Data/Hashable.hs +90/−35
- hashable.cabal +13/−14
CHANGES view
@@ -1,5 +1,11 @@ Version 1.1.1.0 +* Improved instances for tuples and lists.++* Added instances for StableName, Float, Double, Integer, and Ratio.++Version 1.1.1.0+ * Added hashWithSalt, which allows the user to create different hash values for the same input by providing different seeds. This is useful for application like Cuckoo hashing which need a family of
Data/Hashable.hs view
@@ -37,10 +37,12 @@ , combine ) where +import Control.Exception (assert) import Data.Bits (bitSize, shiftL, shiftR, xor) import Data.Int (Int8, Int16, Int32, Int64) import Data.Word (Word, Word8, Word16, Word32, Word64) import Data.List (foldl')+import Data.Ratio (Ratio, denominator, numerator) import qualified Data.ByteString as B import qualified Data.ByteString.Internal as B import qualified Data.ByteString.Unsafe as B@@ -51,7 +53,10 @@ import qualified Data.Text.Internal as T import qualified Data.Text.Lazy as LT import Foreign.C (CLong, CString)+import Foreign.Marshal.Utils (with) import Foreign.Ptr (Ptr, castPtr)+import Foreign.Storable (alignment, peek, sizeOf)+import System.IO.Unsafe (unsafePerformIO) #if defined(__GLASGOW_HASKELL__) import Foreign.C.Types (CInt)@@ -62,6 +67,14 @@ import Control.Concurrent (ThreadId) #endif +#if defined(__GLASGOW_HASKELL__) || defined(__HUGS__)+import System.Mem.StableName+#endif++#include "MachDeps.h"++infixl 0 `combine`, `hashWithSalt`+ ------------------------------------------------------------------------ -- * Computing hash values @@ -132,55 +145,105 @@ | bitSize (undefined :: Int) == 64 = fromIntegral n | otherwise = fromIntegral (n `xor` (n `shiftR` 32)) +instance Hashable Integer where+ hash = foldl' hashWithSalt 0 . 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++instance (Integral a, Hashable a) => Hashable (Ratio a) where+ {-# SPECIALIZE instance Hashable (Ratio Integer) #-}+ 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)++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)+ instance Hashable Char where hash = fromEnum instance Hashable a => Hashable (Maybe a) where hash Nothing = 0- hash (Just a) = 1 `combine` hash a+ hash (Just a) = 1 `hashWithSalt` a+ hashWithSalt s Nothing = s `combine` 0+ hashWithSalt s (Just a) = s `combine` 1 `hashWithSalt` a instance (Hashable a, Hashable b) => Hashable (Either a b) where- hash (Left a) = 0 `combine` hash a- hash (Right b) = 1 `combine` hash b+ hash (Left a) = 0 `hashWithSalt` a+ hash (Right b) = 1 `hashWithSalt` b+ hashWithSalt s (Left a) = s `combine` 0 `hashWithSalt` a+ hashWithSalt s (Right b) = s `combine` 1 `hashWithSalt` b instance (Hashable a1, Hashable a2) => Hashable (a1, a2) where- hash (a1, a2) = defaultSalt `combine` hash a1 `combine` hash a2+ hash (a1, a2) = hash a1 `hashWithSalt` a2+ hashWithSalt s (a1, a2) = s `hashWithSalt` a1 `hashWithSalt` a2 instance (Hashable a1, Hashable a2, Hashable a3) => Hashable (a1, a2, a3) where- hash (a1, a2, a3) = defaultSalt `combine` hash a1 `combine` hash a2- `combine` hash a3+ hash (a1, a2, a3) = hash a1 `hashWithSalt` a2 `hashWithSalt` a3+ hashWithSalt s (a1, a2, a3) = s `hashWithSalt` a1 `hashWithSalt` a2+ `hashWithSalt` a3 instance (Hashable a1, Hashable a2, Hashable a3, Hashable a4) => Hashable (a1, a2, a3, a4) where- hash (a1, a2, a3, a4) = defaultSalt `combine` hash a1 `combine` hash a2- `combine` hash a3 `combine` hash a4+ hash (a1, a2, a3, a4) = hash a1 `hashWithSalt` a2+ `hashWithSalt` a3 `hashWithSalt` a4+ hashWithSalt s (a1, a2, a3, a4) = s `hashWithSalt` a1 `hashWithSalt` a2+ `hashWithSalt` a3 `hashWithSalt` 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) =- defaultSalt `combine` hash a1 `combine` hash a2 `combine` hash a3- `combine` hash a4 `combine` hash 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 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) =- defaultSalt `combine` hash a1 `combine` hash a2 `combine` hash a3- `combine` hash a4 `combine` hash a5 `combine` hash 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 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) =- defaultSalt `combine` hash a1 `combine` hash a2 `combine` hash a3- `combine` hash a4 `combine` hash a5 `combine` hash a6 `combine` hash 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 +#if defined(__GLASGOW_HASKELL__) || defined(__HUGS__)+instance Hashable (StableName a) where+ hash = hashStableName+#endif+ -- | Default salt for hashing string like types. stringSalt :: Int stringSalt = 5381 instance Hashable a => Hashable [a] where {-# SPECIALIZE instance Hashable [Char] #-}- hash = foldl' hashAndCombine stringSalt- hashWithSalt = foldl' hashAndCombine+ hashWithSalt = foldl' hashWithSalt -- | Compute the hash of a ThreadId. For GHC, we happen to know a -- trick to make this fast.@@ -197,32 +260,24 @@ hash = hashThreadId {-# INLINE hash #-} -hashAndCombine :: Hashable h => Int -> h -> Int-hashAndCombine acc h = acc `combine` hash h- instance Hashable B.ByteString where- hash bs = B.inlinePerformIO $- B.unsafeUseAsCStringLen bs $ \(p, len) ->- hashPtr p (fromIntegral len)-+ hash = hashWithSalt stringSalt hashWithSalt salt bs = B.inlinePerformIO $ B.unsafeUseAsCStringLen bs $ \(p, len) -> hashPtrWithSalt p (fromIntegral len) salt instance Hashable BL.ByteString where- hash = BL.foldlChunks hashWithSalt stringSalt+ hash = hashWithSalt stringSalt hashWithSalt = BL.foldlChunks hashWithSalt instance Hashable T.Text where- hash (T.Text arr off len) = hashByteArray (TA.aBA arr)- (off `shiftL` 1) (len `shiftL` 1)-+ hash = hashWithSalt stringSalt hashWithSalt salt (T.Text arr off len) = hashByteArrayWithSalt (TA.aBA arr) (off `shiftL` 1) (len `shiftL` 1) salt instance Hashable LT.Text where- hash = LT.foldlChunks hashWithSalt stringSalt+ hash = hashWithSalt stringSalt hashWithSalt = LT.foldlChunks hashWithSalt ------------------------------------------------------------------------@@ -231,9 +286,9 @@ -- $blocks -- -- The functions below can be used when creating new instances of--- 'Hashable'. For example, the 'hash' method for many string-like--- types can be defined in terms of either 'hashPtr' or--- 'hashByteArray'. Here's how you could implement an instance for+-- 'Hashable'. For example, the 'hashWithSalt' method for many string-like+-- types can be defined in terms of either 'hashPtrWithSalt' or+-- 'hashByteArrayWithSalt'. Here's how you could implement an instance for -- the 'B.ByteString' data type, from the @bytestring@ package: -- -- > import qualified Data.ByteString as B@@ -243,16 +298,16 @@ -- > import Foreign.Ptr (castPtr) -- > -- > instance Hashable B.ByteString where--- > hash bs = B.inlinePerformIO $--- > B.unsafeUseAsCStringLen bs $ \ (p, len) ->--- > hashPtr p (fromIntegral len)+-- > hashWithSalt salt bs = B.inlinePerformIO $+-- > B.unsafeUseAsCStringLen bs $ \(p, len) ->+-- > hashPtrWithSalt p (fromIntegral len) salt -- -- The 'combine' function can be used to implement 'Hashable' -- instances for data types with more than one field, using this -- recipe: -- -- > instance (Hashable a, Hashable b) => Hashable (Foo a b) where--- > hash (Foo a b) = 17 `combine` hash a `combine` hash b+-- > hashWithSalt s (Foo a b) = s `hashWithSalt` a `hashWithSalt` b -- -- A nonzero seed is used so the hash value will be affected by -- initial fields whose hash value is zero. If no seed was provided,
hashable.cabal view
@@ -1,5 +1,5 @@ Name: hashable-Version: 1.1.1.0+Version: 1.1.2.0 Synopsis: A class for types that can be converted to a hash value Description: This package defines a class, 'Hashable', for types that can be converted to a hash value. This class@@ -35,20 +35,19 @@ if impl(ghc >= 6.8) Ghc-options: -fwarn-tabs --- -- Commented out until cabal-install release.--- Test-suite tests--- Type: exitcode-stdio-1.0--- Hs-source-dirs: tests--- Main-is: Properties.hs--- Build-depends: base >= 4.0 && < 5,--- hashable,--- test-framework >= 0.3.3 && < 0.4,--- test-framework-quickcheck2 >= 0.2.9 && < 0.3,--- QuickCheck >= 2.4.0.1,--- random == 1.0.*,--- text >= 0.11.0.5+Test-suite tests+ Type: exitcode-stdio-1.0+ Hs-source-dirs: tests+ Main-is: Properties.hs+ Build-depends: base >= 4.0 && < 5,+ hashable,+ test-framework >= 0.3.3 && < 0.4,+ test-framework-quickcheck2 >= 0.2.9 && < 0.3,+ QuickCheck >= 2.4.0.1,+ random == 1.0.*,+ text >= 0.11.0.5 --- Ghc-options: -Wall+ Ghc-options: -Wall source-repository head type: git