-- Simplified Hashable, just to have something module Data.Hashable( Hashable(..), ) where --import Data.Bits import qualified Data.ByteString as B import Data.Complex import Data.Fixed import Data.Int import Data.Integer(_integerToIntList) import Data.List(foldl') import Data.Ratio import qualified Data.Text as T import Data.Word type Salt = Int infixl 0 `hashWithSalt` class Hashable a where hashWithSalt :: Salt -> a -> Int hash :: a -> Int hash = hashWithSalt defaultSalt defaultSalt :: Salt defaultSalt = 0x087fc72c hashUsing :: (Hashable b) => (a -> b) -> Salt -> a -> Int hashUsing f salt x = hashWithSalt salt (f x) defaultHashWithSalt :: Hashable a => Int -> a -> Int defaultHashWithSalt salt x = salt `hashInt` hash x ----------------- instance Hashable Int where hash = id hashWithSalt = hashInt instance Hashable Int8 where hash = fromIntegral hashWithSalt = defaultHashWithSalt instance Hashable Int16 where hash = fromIntegral hashWithSalt = defaultHashWithSalt instance Hashable Int32 where hash = fromIntegral hashWithSalt = defaultHashWithSalt instance Hashable Int64 where hash = fromIntegral hashWithSalt = defaultHashWithSalt instance Hashable Word where hash = fromIntegral hashWithSalt = defaultHashWithSalt instance Hashable Word8 where hash = fromIntegral hashWithSalt = defaultHashWithSalt instance Hashable Word16 where hash = fromIntegral hashWithSalt = defaultHashWithSalt instance Hashable Word32 where hash = fromIntegral hashWithSalt = defaultHashWithSalt instance Hashable Word64 where hash = fromIntegral hashWithSalt = defaultHashWithSalt instance Hashable () where hash _ = 0 hashWithSalt = defaultHashWithSalt instance Hashable Bool where hash = fromEnum hashWithSalt = defaultHashWithSalt instance Hashable Ordering where hash = fromEnum hashWithSalt = defaultHashWithSalt instance Hashable Char where hash = fromEnum hashWithSalt = defaultHashWithSalt instance Hashable Float where hash = hash . show hashWithSalt = defaultHashWithSalt instance Hashable Double where hash = hash . show hashWithSalt = defaultHashWithSalt instance Hashable Integer where hashWithSalt s = hashWithSalt s . _integerToIntList instance Hashable B.ByteString where hashWithSalt s = hashWithSalt s . B.unpack instance Hashable T.Text where hashWithSalt s = hashWithSalt s . T.unpack distinguisher :: Int distinguisher = fromIntegral $ (maxBound :: Word) `quot` 3 instance Hashable a => Hashable (Maybe a) where hash Nothing = 0 hash (Just a) = distinguisher `hashWithSalt` a hashWithSalt = defaultHashWithSalt instance Hashable a => Hashable [a] where hashWithSalt = foldl' hashWithSalt instance (Hashable a, Hashable b) => Hashable (Either a b) where hash (Left a) = 0 `hashWithSalt` a hash (Right b) = distinguisher `hashWithSalt` b hashWithSalt = defaultHashWithSalt instance Hashable a => Hashable (Complex a) where hashWithSalt s (r :+ i) = s `hashWithSalt` r `hashWithSalt` i instance Hashable a => Hashable (Ratio a) where hashWithSalt s r = s `hashWithSalt` numerator r `hashWithSalt` denominator r instance HasResolution a => Hashable (Fixed a) where hashWithSalt s = hashWithSalt s . toRational instance (Hashable a1, Hashable a2) => Hashable (a1, a2) where hashWithSalt s (a1, a2) = s `hashWithSalt` a1 `hashWithSalt` a2 instance (Hashable a1, Hashable a2, Hashable a3) => Hashable (a1, a2, a3) where 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 hashWithSalt s (a1, a2, a3, a4) = s `hashWithSalt` a1 `hashWithSalt` a2 `hashWithSalt` a3 `hashWithSalt` a4 ------------ -- XXX This needs work hashInt :: Salt -> Int -> Salt hashInt s x = s * 33 + x {- -- This is what we'd like, but it uses primitives byteSwap# and timesWord2# hashInt :: Salt -> Int -> Salt hashInt s x = fromIntegral (mixHash (fromIntegral s) (fromIntegral x)) mulFold :: Word -> Word -> Word mulFold (W# x) (W# y) = case timesWord2# x y of (# hi, lo #) -> W# (xor# hi lo) byteSwap :: Word -> Word byteSwap (W# w) = W# (byteSwap# w) avalanche :: Word -> Word avalanche z0 = #if WORD_SIZE_IN_BITS == 64 -- MurmurHash3Mixer let z1 = shiftXorMultiply 33 0xff51afd7ed558ccd z0 z2 = shiftXorMultiply 33 0xc4ceb9fe1a85ec53 z1 z3 = shiftXor 33 z2 in z3 #else -- MurmurHash3Mixer 32bit let z1 = shiftXorMultiply 16 0x85ebca6b z0 z2 = shiftXorMultiply 13 0xc2b2ae35 z1 z3 = shiftXor 16 z2 in z3 #endif shiftXor :: Int -> Word -> Word shiftXor n w = w `xor` (w `unsafeShiftR` n) shiftXorMultiply :: Int -> Word -> Word -> Word 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) -}