Skip to content

Commit

Permalink
Change Int to Word
Browse files Browse the repository at this point in the history
  • Loading branch information
phadej committed Jun 8, 2024
1 parent b402cfb commit 497060f
Show file tree
Hide file tree
Showing 5 changed files with 60 additions and 55 deletions.
90 changes: 45 additions & 45 deletions src/Data/Hashable/Class.hs
Original file line number Diff line number Diff line change
Expand Up @@ -240,23 +240,23 @@ class Eq a => Hashable a where
--
-- * 'hashWithSalt' may return negative 'Int' values.
--
hashWithSalt :: Int -> a -> Int
hashWithSalt :: Word -> a -> Word

-- | Like 'hashWithSalt', but no salt is used. The default
-- implementation uses 'hashWithSalt' with some default salt.
-- Instances might want to implement this method to provide a more
-- efficient implementation than the default implementation.
hash :: a -> Int
hash :: a -> Word
hash = defaultHash

default hashWithSalt :: (Generic a, GHashable Zero (Rep a)) => Int -> a -> Int
default hashWithSalt :: (Generic a, GHashable Zero (Rep a)) => Word -> a -> Word
hashWithSalt = genericHashWithSalt
{-# INLINE hashWithSalt #-}

-- | Generic 'hashWithSalt'.
--
-- @since 1.3.0.0
genericHashWithSalt :: (Generic a, GHashable Zero (Rep a)) => Int -> a -> Int
genericHashWithSalt :: (Generic a, GHashable Zero (Rep a)) => Word -> a -> Word
genericHashWithSalt = \salt -> ghashWithSalt HashArgs0 salt . from
{-# INLINE genericHashWithSalt #-}

Expand All @@ -265,47 +265,47 @@ data One

data family HashArgs arity a :: Type
data instance HashArgs Zero a = HashArgs0
newtype instance HashArgs One a = HashArgs1 (Int -> a -> Int)
newtype instance HashArgs One a = HashArgs1 (Word -> a -> Word)

-- | The class of types that can be generically hashed.
class GHashable arity f where
ghashWithSalt :: HashArgs arity a -> Int -> f a -> Int
ghashWithSalt :: HashArgs arity a -> Word -> f a -> Word

class Eq1 t => Hashable1 t where
-- | Lift a hashing function through the type constructor.
liftHashWithSalt :: (Int -> a -> Int) -> Int -> t a -> Int
liftHashWithSalt :: (Word -> a -> Word) -> Word -> t a -> Word

default liftHashWithSalt :: (Generic1 t, GHashable One (Rep1 t)) => (Int -> a -> Int) -> Int -> t a -> Int
default liftHashWithSalt :: (Generic1 t, GHashable One (Rep1 t)) => (Word -> a -> Word) -> Word -> t a -> Word
liftHashWithSalt = genericLiftHashWithSalt
{-# INLINE liftHashWithSalt #-}

-- | Generic 'liftHashWithSalt'.
--
-- @since 1.3.0.0
genericLiftHashWithSalt :: (Generic1 t, GHashable One (Rep1 t)) => (Int -> a -> Int) -> Int -> t a -> Int
genericLiftHashWithSalt :: (Generic1 t, GHashable One (Rep1 t)) => (Word -> a -> Word) -> Word -> t a -> Word
genericLiftHashWithSalt = \h salt -> ghashWithSalt (HashArgs1 h) salt . from1
{-# INLINE genericLiftHashWithSalt #-}

class Eq2 t => Hashable2 t where
-- | Lift a hashing function through the binary type constructor.
liftHashWithSalt2 :: (Int -> a -> Int) -> (Int -> b -> Int) -> Int -> t a b -> Int
liftHashWithSalt2 :: (Word -> a -> Word) -> (Word -> b -> Word) -> Word -> t a b -> Word

-- | Lift the 'hashWithSalt' function through the type constructor.
--
-- > hashWithSalt1 = liftHashWithSalt hashWithSalt
hashWithSalt1 :: (Hashable1 f, Hashable a) => Int -> f a -> Int
hashWithSalt1 :: (Hashable1 f, Hashable a) => Word -> f a -> Word
hashWithSalt1 = liftHashWithSalt hashWithSalt

-- | Lift the 'hashWithSalt' function through the type constructor.
--
-- > hashWithSalt2 = liftHashWithSalt2 hashWithSalt hashWithSalt
hashWithSalt2 :: (Hashable2 f, Hashable a, Hashable b) => Int -> f a b -> Int
hashWithSalt2 :: (Hashable2 f, Hashable a, Hashable b) => Word -> f a b -> Word
hashWithSalt2 = liftHashWithSalt2 hashWithSalt hashWithSalt

-- | Lift the 'hashWithSalt' function halfway through the type constructor.
-- This function makes a suitable default implementation of 'liftHashWithSalt',
-- given that the type constructor @t@ in question can unify with @f a@.
defaultLiftHashWithSalt :: (Hashable2 f, Hashable a) => (Int -> b -> Int) -> Int -> f a b -> Int
defaultLiftHashWithSalt :: (Hashable2 f, Hashable a) => (Word -> b -> Word) -> Word -> f a b -> Word
defaultLiftHashWithSalt h = liftHashWithSalt2 hashWithSalt h

-- | Since we support a generic implementation of 'hashWithSalt' we
Expand All @@ -315,14 +315,14 @@ defaultLiftHashWithSalt h = liftHashWithSalt2 hashWithSalt h
--
-- @since 1.4.3.0
--
defaultHashWithSalt :: Hashable a => Int -> a -> Int
defaultHashWithSalt salt x = salt `hashInt` hash x
defaultHashWithSalt :: Hashable a => Word -> a -> Word
defaultHashWithSalt salt x = salt `hashWord` hash x

-- | Default implementation of 'hash' based on 'hashWithSalt'.
--
-- @since 1.4.3.0
--
defaultHash :: Hashable a => a -> Int
defaultHash :: Hashable a => a -> Word
defaultHash = hashWithSalt defaultSalt

-- | Transform a value into a 'Hashable' value, then hash the
Expand All @@ -341,14 +341,14 @@ defaultHash = hashWithSalt defaultSalt
-- @since 1.2.0.0
hashUsing :: (Hashable b) =>
(a -> b) -- ^ Transformation function.
-> Int -- ^ Salt.
-> Word -- ^ Salt.
-> a -- ^ Value to transform.
-> Int
-> Word
hashUsing f salt x = hashWithSalt salt (f x)
{-# INLINE hashUsing #-}

instance Hashable Int where
hash = id
hash = fromIntegral
hashWithSalt = hashInt

instance Hashable Int8 where
Expand All @@ -368,8 +368,8 @@ instance Hashable Int64 where
hashWithSalt = hashInt64

instance Hashable Word where
hash = fromIntegral
hashWithSalt = defaultHashWithSalt
hash = id
hashWithSalt = hashWord

instance Hashable Word8 where
hash = fromIntegral
Expand All @@ -388,19 +388,19 @@ instance Hashable Word64 where
hashWithSalt = hashWord64

instance Hashable () where
hash = fromEnum
hash _ = 1
hashWithSalt = defaultHashWithSalt

instance Hashable Bool where
hash = fromEnum
hash = fromIntegral . fromEnum
hashWithSalt = defaultHashWithSalt

instance Hashable Ordering where
hash = fromEnum
hash = fromIntegral . fromEnum
hashWithSalt = defaultHashWithSalt

instance Hashable Char where
hash = fromEnum
hash = fromIntegral . fromEnum
hashWithSalt = defaultHashWithSalt

#if defined(VERSION_integer_gmp) || defined(VERSION_ghc_bignum)
Expand Down Expand Up @@ -429,15 +429,15 @@ instance Hashable Natural where

instance Hashable Integer where
#if defined(VERSION_ghc_bignum)
hash (IS n) = I# n
hash (IS n) = fromIntegral (I# n)
hash (IP bn) = hash (BN# bn)
hash (IN bn) = negate (hash (BN# bn))

hashWithSalt salt (IS n) = hashWithSalt salt (I# n)
hashWithSalt salt (IP bn) = hashWithSalt salt (BN# bn)
hashWithSalt salt (IN bn) = negate (hashWithSalt salt (BN# bn))
#elif defined(VERSION_integer_gmp)
hash (S# n) = (I# n)
hash (S# n) = fromIntegral (I# n)
hash (Jp# bn) = hash bn
hash (Jn# bn) = negate (hash bn)

Expand Down Expand Up @@ -496,10 +496,10 @@ instance Hashable Double where
| otherwise = hash (show x)
hashWithSalt = defaultHashWithSalt

-- | A value with bit pattern (01)* (or 5* in hexa), for any size of Int.
-- | A value with bit pattern (01)* (or 5* in hexa), for any size of IWord.
-- It is used as data constructor distinguisher. GHC computes its value during
-- compilation.
distinguisher :: Int
distinguisher :: Word
distinguisher = fromIntegral $ (maxBound :: Word) `quot` 3
{-# INLINE distinguisher #-}

Expand All @@ -509,8 +509,8 @@ instance Hashable a => Hashable (Maybe a) where
hashWithSalt = hashWithSalt1

instance Hashable1 Maybe where
liftHashWithSalt _ s Nothing = s `hashInt` 0
liftHashWithSalt h s (Just a) = s `hashInt` distinguisher `h` a
liftHashWithSalt _ s Nothing = s `hashWord` 0
liftHashWithSalt h s (Just a) = s `hashWord` distinguisher `h` a

instance (Hashable a, Hashable b) => Hashable (Either a b) where
hash (Left a) = 0 `hashWithSalt` a
Expand All @@ -521,8 +521,8 @@ instance Hashable a => Hashable1 (Either a) where
liftHashWithSalt = defaultLiftHashWithSalt

instance Hashable2 Either where
liftHashWithSalt2 h _ s (Left a) = s `hashInt` 0 `h` a
liftHashWithSalt2 _ h s (Right b) = s `hashInt` distinguisher `h` b
liftHashWithSalt2 h _ s (Left a) = s `hashWord` 0 `h` a
liftHashWithSalt2 _ h s (Right b) = s `hashWord` distinguisher `h` b

instance (Hashable a1, Hashable a2) => Hashable (a1, a2) where
hashWithSalt = hashWithSalt1
Expand Down Expand Up @@ -609,11 +609,11 @@ instance (Hashable a1, Hashable a2, Hashable a3, Hashable a4,
-}

instance Hashable (StableName a) where
hash = hashStableName
hash = fromIntegral . hashStableName
hashWithSalt = defaultHashWithSalt

-- Auxiliary type for Hashable [a] definition
data SPInt = SP !Int !Int
data SPInt = SP !Salt !Int

instance Hashable a => Hashable [a] where
{-# SPECIALIZE instance Hashable [Char] #-}
Expand Down Expand Up @@ -769,7 +769,7 @@ instance Hashable Fingerprint where
hashWithSalt = defaultHashWithSalt
{-# INLINE hash #-}

hashTypeRep :: Type.Reflection.TypeRep a -> Int
hashTypeRep :: Type.Reflection.TypeRep a -> Word
hashTypeRep tr =
let Fingerprint x _ = typeRepFingerprint tr in fromIntegral x

Expand All @@ -789,22 +789,22 @@ instance Hashable Void where
hashWithSalt _ = absurd

-- | Compute a hash value for the content of this pointer.
hashPtr :: Ptr a -- ^ pointer to the data to hash
-> Int -- ^ length, in bytes
-> IO Int -- ^ hash value
hashPtr :: Ptr a -- ^ pointer to the data to hash
-> Int -- ^ length, in bytes
-> IO Word -- ^ hash value
hashPtr p len = hashPtrWithSalt p len defaultSalt

-- | Compute a hash value for the content of this 'ByteArray#',
-- beginning at the specified offset, using specified number of bytes.
hashByteArray :: ByteArray# -- ^ data to hash
-> Int -- ^ offset, in bytes
-> Int -- ^ length, in bytes
-> Int -- ^ hash value
-> Word -- ^ hash value
hashByteArray ba0 off len = hashByteArrayWithSalt ba0 off len defaultSalt
{-# INLINE hashByteArray #-}

instance Hashable Unique where
hash = hashUnique
hash = fromIntegral . hashUnique
hashWithSalt = defaultHashWithSalt

instance Hashable Version where
Expand Down Expand Up @@ -911,8 +911,8 @@ instance (Hashable1 f, Hashable1 g, Hashable a) => Hashable (FP.Product f g a) w
hashWithSalt = hashWithSalt1

instance (Hashable1 f, Hashable1 g) => Hashable1 (FS.Sum f g) where
liftHashWithSalt h s (FS.InL a) = liftHashWithSalt h (s `hashInt` 0) a
liftHashWithSalt h s (FS.InR a) = liftHashWithSalt h (s `hashInt` distinguisher) a
liftHashWithSalt h s (FS.InL a) = liftHashWithSalt h (s `hashWord` 0) a
liftHashWithSalt h s (FS.InR a) = liftHashWithSalt h (s `hashWord` distinguisher) a

instance (Hashable1 f, Hashable1 g, Hashable a) => Hashable (FS.Sum f g a) where
hashWithSalt = hashWithSalt1
Expand All @@ -937,7 +937,7 @@ instance Hashable AB.ByteArray where
-------------------------------------------------------------------------------

-- | A hashable value along with the result of the 'hash' function.
data Hashed a = Hashed a {-# UNPACK #-} !Int
data Hashed a = Hashed a {-# UNPACK #-} !Word

-- | Wrap a hashable value, caching the 'hash' function result.
hashed :: Hashable a => a -> Hashed a
Expand All @@ -950,7 +950,7 @@ unhashed (Hashed a _) = a
-- | 'hash' has 'Eq' requirement.
--
-- @since 1.4.0.0
hashedHash :: Hashed a -> Int
hashedHash :: Hashed a -> Word
hashedHash (Hashed _ h) = h

-- | Uses precomputed hash to detect inequality faster
Expand Down
2 changes: 1 addition & 1 deletion src/Data/Hashable/Generic/Instances.hs
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ instance (Hashable1 f, GHashable One g) => GHashable One (f :.: g) where
ghashWithSalt targs salt = liftHashWithSalt (ghashWithSalt targs) salt . unComp1

class SumSize f => GSum arity f where
hashSum :: HashArgs arity a -> Int -> Int -> f a -> Int
hashSum :: HashArgs arity a -> Word -> Int -> f a -> Word
-- hashSum args salt index value = ...

-- [Note: Hashing a sum type]
Expand Down
10 changes: 7 additions & 3 deletions src/Data/Hashable/LowLevel.hs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ module Data.Hashable.LowLevel (
Salt,
defaultSalt,
hashInt,
hashWord,
hashInt64,
hashWord64,
hashPtrWithSalt,
Expand Down Expand Up @@ -48,9 +49,9 @@ defaultSalt = defaultSalt'

defaultSalt' :: Salt
#if WORD_SIZE_IN_BITS == 64
defaultSalt' = -3750763034362895579 -- 14695981039346656037 :: Int64
defaultSalt' = 14695981039346656037
#else
defaultSalt' = -2128831035 -- 2166136261 :: Int32
defaultSalt' = 2166136261
#endif
{-# INLINE defaultSalt' #-}

Expand All @@ -61,7 +62,10 @@ defaultSalt' = -2128831035 -- 2166136261 :: Int32
-- | 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 = fromIntegral (mixHash (fromIntegral s) (fromIntegral x))
hashInt !s !x = fromIntegral (mixHash s (fromIntegral x))

hashWord :: Salt -> Word -> Salt
hashWord = mixHash

hashInt64 :: Salt -> Int64 -> Salt
hashWord64 :: Salt -> Word64 -> Salt
Expand Down
5 changes: 3 additions & 2 deletions src/Data/Hashable/Mix.hs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
{-# LANGUAGE CPP #-}
{-# LANGUAGE BangPatterns #-}
{-# LANGUAGE MagicHash #-}
{-# LANGUAGE Trustworthy #-}
{-# LANGUAGE UnboxedTuples #-}
Expand All @@ -12,7 +13,7 @@ module Data.Hashable.Mix (
import Data.Bits (unsafeShiftR, xor)
import GHC.Exts (Word (..), byteSwap#, timesWord2#, xor#)

type Salt = Int
type Salt = Word

mulFold :: Word -> Word -> Word
mulFold (W# x) (W# y) = case timesWord2# x y of
Expand Down Expand Up @@ -45,4 +46,4 @@ shiftXorMultiply n k w = shiftXor n w * k

-- | Mix hash is inspired by how xxh3 works on small (<=16byte) inputs.
mixHash :: Word -> Word -> Word
mixHash hi lo = avalanche (byteSwap lo + hi + mulFold hi lo)
mixHash !hi !lo = avalanche (byteSwap lo + hi + mulFold hi lo)
8 changes: 4 additions & 4 deletions tests/Properties.hs
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ pTextRechunk t cs = TL.fromStrict t === rechunkText t cs
pTextLazyRechunked :: T.Text -> NonEmptyList ChunkSize -> NonEmptyList ChunkSize -> Property
pTextLazyRechunked t cs0 cs1 = hash (rechunkText t cs0) === hash (rechunkText t cs1)

pTextLazyRechunked' :: T.Text -> Int -> NonEmptyList ChunkSize -> NonEmptyList ChunkSize -> Property
pTextLazyRechunked' :: T.Text -> Word -> NonEmptyList ChunkSize -> NonEmptyList ChunkSize -> Property
pTextLazyRechunked' t salt cs0 cs1 = hashWithSalt salt (rechunkText t cs0) === hashWithSalt salt (rechunkText t cs1)

-- | Break up a string into chunks of different sizes.
Expand Down Expand Up @@ -137,7 +137,7 @@ pBSRechunk t cs = fromStrict t == rechunkBS t cs
pBSLazyRechunked :: B.ByteString -> NonEmptyList ChunkSize -> NonEmptyList ChunkSize -> Property
pBSLazyRechunked t cs1 cs2 = hash (rechunkBS t cs1) === hash (rechunkBS t cs2)

pBSLazyRechunked' :: B.ByteString -> Int -> NonEmptyList ChunkSize -> NonEmptyList ChunkSize -> Property
pBSLazyRechunked' :: B.ByteString -> Word -> NonEmptyList ChunkSize -> NonEmptyList ChunkSize -> Property
pBSLazyRechunked' t salt cs1 cs2 = hashWithSalt salt (rechunkBS t cs1) === hashWithSalt salt (rechunkBS t cs2)

-- This wrapper is required by 'runST'.
Expand Down Expand Up @@ -215,14 +215,14 @@ pSum3_differ x = nub hs == hs
, hash (S3b x :: Sum3 Int Int Int)
, hash (S3c x :: Sum3 Int Int Int) ]

pGeneric :: Sum3 Int Bool String -> Int -> Bool
pGeneric :: Sum3 Int Bool String -> Word -> Bool
pGeneric x salt = hashWithSalt salt x == genericHashWithSalt salt x

instance (Arbitrary a, Hashable a) => Arbitrary (Hashed a) where
arbitrary = fmap hashed arbitrary
shrink xs = map hashed $ shrink $ unhashed xs

pLiftedHashed :: Int -> Hashed (Either Int String) -> Bool
pLiftedHashed :: Word -> Hashed (Either Int String) -> Bool
pLiftedHashed s h = hashWithSalt s h == hashWithSalt1 s h

properties :: [Test]
Expand Down

0 comments on commit 497060f

Please sign in to comment.