diff --git a/CHANGES.md b/CHANGES.md
new file mode 100644
--- /dev/null
+++ b/CHANGES.md
@@ -0,0 +1,16 @@
+## 0.2.6.0
+
+ * Mark several modules as Trustworthy.
+
+ * Add Hashable instances for HashMap and HashSet.
+
+ * Add mapMaybe, mapMaybeWithKey, update, alter, and
+   intersectionWithKey.
+
+ * Add roles.
+
+ * Add Hashable and Semigroup instances.
+
+## 0.2.5.1 (2014-10-11)
+
+ * Support base-4.8
diff --git a/Data/HashMap/Array.hs b/Data/HashMap/Array.hs
--- a/Data/HashMap/Array.hs
+++ b/Data/HashMap/Array.hs
@@ -53,7 +53,6 @@
 import Control.Applicative (Applicative)
 #endif
 import Control.DeepSeq
-import Control.Monad.ST hiding (runST)
 -- GHC 7.7 exports toList/fromList from GHC.Exts
 -- In order to avoid warnings on previous GHC versions, we provide
 -- an explicit import list instead of only hiding the offending symbols
diff --git a/Data/HashMap/Base.hs b/Data/HashMap/Base.hs
--- a/Data/HashMap/Base.hs
+++ b/Data/HashMap/Base.hs
@@ -1,6 +1,8 @@
 {-# LANGUAGE BangPatterns, CPP, DeriveDataTypeable, MagicHash #-}
 {-# LANGUAGE ScopedTypeVariables #-}
+{-# LANGUAGE PatternGuards #-}
 #if __GLASGOW_HASKELL__ >= 708
+{-# LANGUAGE RoleAnnotations #-}
 {-# LANGUAGE TypeFamilies #-}
 #endif
 {-# OPTIONS_GHC -fno-full-laziness -funbox-strict-fields #-}
@@ -26,6 +28,8 @@
     , unsafeInsert
     , delete
     , adjust
+    , update
+    , alter
 
       -- * Combine
       -- ** Union
@@ -42,6 +46,7 @@
     , difference
     , intersection
     , intersectionWith
+    , intersectionWithKey
 
       -- * Folds
     , foldl'
@@ -50,6 +55,8 @@
     , foldrWithKey
 
       -- * Filter
+    , mapMaybe
+    , mapMaybeWithKey
     , filter
     , filterWithKey
 
@@ -79,16 +86,18 @@
     , update16M
     , update16With'
     , updateOrConcatWith
+    , filterMapAux
     ) where
 
-#if __GLASGOW_HASKELL__ >= 709
-import Data.Functor ((<$>))
-#else
+#if __GLASGOW_HASKELL__ < 710
 import Control.Applicative ((<$>), Applicative(pure))
 import Data.Monoid (Monoid(mempty, mappend))
 import Data.Traversable (Traversable(..))
 import Data.Word (Word)
 #endif
+#if __GLASGOW_HASKELL__ >= 711
+import Data.Semigroup (Semigroup((<>)))
+#endif
 import Control.DeepSeq (NFData(rnf))
 import Control.Monad.ST (ST)
 import Data.Bits ((.&.), (.|.), complement)
@@ -140,6 +149,10 @@
     | Collision !Hash !(A.Array (Leaf k v))
       deriving (Typeable)
 
+#if __GLASGOW_HASKELL__ >= 708
+type role HashMap nominal representational
+#endif
+
 instance (NFData k, NFData v) => NFData (HashMap k v) where
     rnf Empty                 = ()
     rnf (BitmapIndexed _ ary) = rnf ary
@@ -153,10 +166,20 @@
 instance Foldable.Foldable (HashMap k) where
     foldr f = foldrWithKey (const f)
 
+#if __GLASGOW_HASKELL__ >= 711
+instance (Eq k, Hashable k) => Semigroup (HashMap k v) where
+  (<>) = union
+  {-# INLINE (<>) #-}
+#endif
+
 instance (Eq k, Hashable k) => Monoid (HashMap k v) where
   mempty = empty
   {-# INLINE mempty #-}
+#if __GLASGOW_HASKELL__ >= 711
+  mappend = (<>)
+#else
   mappend = union
+#endif
   {-# INLINE mappend #-}
 
 instance (Data k, Data v, Eq k, Hashable k) => Data (HashMap k v) where
@@ -213,12 +236,40 @@
     go [] [] = True
     go _  _  = False
 
-    toList' (BitmapIndexed _ ary) a = A.foldr toList' a ary
-    toList' (Full ary)            a = A.foldr toList' a ary
-    toList' l@(Leaf _ _)          a = l : a
-    toList' c@(Collision _ _)     a = c : a
-    toList' Empty                 a = a
+instance (Hashable k, Hashable v) => Hashable (HashMap k v) where
+    hashWithSalt salt hm = go salt (toList' hm [])
+      where
+        go :: Int -> [HashMap k v] -> Int
+        go s [] = s
+        go s (Leaf _ l : tl)
+          = s `hashLeafWithSalt` l `go` tl
+        -- For collisions we hashmix hash value
+        -- and then array of values' hashes sorted
+        go s (Collision h a : tl)
+          = (s `H.hashWithSalt` h) `hashCollisionWithSalt` a `go` tl
+        go s (_ : tl) = s `go` tl
 
+        hashLeafWithSalt :: Int -> Leaf k v -> Int
+        hashLeafWithSalt s (L k v) = s `H.hashWithSalt` k `H.hashWithSalt` v
+
+        hashCollisionWithSalt :: Int -> A.Array (Leaf k v) -> Int
+        hashCollisionWithSalt s
+          = L.foldl' H.hashWithSalt s . arrayHashesSorted
+
+        arrayHashesSorted :: A.Array (Leaf k v) -> [Int]
+        arrayHashesSorted = L.sort . L.map leafValueHash . A.toList
+
+        leafValueHash :: Leaf k v -> Int
+        leafValueHash (L _ v) = H.hash v
+
+  -- Helper to get 'Leaf's and 'Collision's as a list.
+toList' :: HashMap k v -> [HashMap k v] -> [HashMap k v]
+toList' (BitmapIndexed _ ary) a = A.foldr toList' a ary
+toList' (Full ary)            a = A.foldr toList' a ary
+toList' l@(Leaf _ _)          a = l : a
+toList' c@(Collision _ _)     a = c : a
+toList' Empty                 a = a
+
 -- Helper function to detect 'Leaf's and 'Collision's.
 isLeafOrCollision :: HashMap k v -> Bool
 isLeafOrCollision (Leaf _ _)      = True
@@ -460,8 +511,7 @@
 unsafeInsertWith f k0 v0 m0 = runST (go h0 k0 v0 0 m0)
   where
     h0 = hash k0
-    go :: (Eq k, Hashable k) => Hash -> k -> v -> Shift -> HashMap k v
-       -> ST s (HashMap k v)
+    go :: Hash -> k -> v -> Shift -> HashMap k v -> ST s (HashMap k v)
     go !h !k x !_ Empty = return $! Leaf h (L k x)
     go h k x s (Leaf hy l@(L ky y))
         | hy == h = if ky == k
@@ -574,6 +624,24 @@
         | otherwise = t
 {-# INLINABLE adjust #-}
 
+-- | /O(log n)/  The expression (@'update' f k map@) updates the value @x@ at @k@,
+-- (if it is in the map). If (f k x) is @'Nothing', the element is deleted.
+-- If it is (@'Just' y), the key k is bound to the new value y.
+update :: (Eq k, Hashable k) => (a -> Maybe a) -> k -> HashMap k a -> HashMap k a
+update f = alter (>>= f)
+{-# INLINABLE update #-}
+
+
+-- | /O(log n)/  The expression (@'alter' f k map@) alters the value @x@ at @k@, or
+-- absence thereof. @alter@ can be used to insert, delete, or update a value in a
+-- map. In short : @'lookup' k ('alter' f k m) = f ('lookup' k m)@.
+alter :: (Eq k, Hashable k) => (Maybe v -> Maybe v) -> k -> HashMap k v -> HashMap k v
+alter f k m =
+  case f (lookup k m) of
+    Nothing -> delete k m
+    Just v  -> insert k v m
+{-# INLINABLE alter #-}
+
 ------------------------------------------------------------------------
 -- * Combine
 
@@ -777,6 +845,18 @@
                  _      -> m
 {-# INLINABLE intersectionWith #-}
 
+-- | /O(n+m)/ Intersection of two maps. If a key occurs in both maps
+-- the provided function is used to combine the values from the two
+-- maps.
+intersectionWithKey :: (Eq k, Hashable k) => (k -> v1 -> v2 -> v3)
+                    -> HashMap k v1 -> HashMap k v2 -> HashMap k v3
+intersectionWithKey f a b = foldlWithKey' go empty a
+  where
+    go m k v = case lookup k b of
+                 Just w -> insert k (f k v w) m
+                 _      -> m
+{-# INLINABLE intersectionWithKey #-}
+
 ------------------------------------------------------------------------
 -- * Folds
 
@@ -835,14 +915,47 @@
     A.unsafeFreeze mary2
 {-# INLINE trim #-}
 
+-- | /O(n)/ Transform this map by applying a function to every value
+--   and retaining only some of them.
+mapMaybeWithKey :: (k -> v1 -> Maybe v2) -> HashMap k v1 -> HashMap k v2
+mapMaybeWithKey f = filterMapAux onLeaf onColl
+  where onLeaf (Leaf h (L k v)) | Just v' <- f k v = Just (Leaf h (L k v'))
+        onLeaf _ = Nothing
+
+        onColl (L k v) | Just v' <- f k v = Just (L k v')
+                       | otherwise = Nothing
+{-# INLINE mapMaybeWithKey #-}
+
+-- | /O(n)/ Transform this map by applying a function to every value
+--   and retaining only some of them.
+mapMaybe :: (v1 -> Maybe v2) -> HashMap k v1 -> HashMap k v2
+mapMaybe f = mapMaybeWithKey (const f)
+{-# INLINE mapMaybe #-}
+
 -- | /O(n)/ Filter this map by retaining only elements satisfying a
 -- predicate.
 filterWithKey :: forall k v. (k -> v -> Bool) -> HashMap k v -> HashMap k v
-filterWithKey pred = go
+filterWithKey pred = filterMapAux onLeaf onColl
+  where onLeaf t@(Leaf _ (L k v)) | pred k v = Just t
+        onLeaf _ = Nothing
+
+        onColl el@(L k v) | pred k v = Just el
+        onColl _ = Nothing
+{-# INLINE filterWithKey #-}
+
+
+-- | Common implementation for 'filterWithKey' and 'mapMaybeWithKey',
+--   allowing the former to former to reuse terms.
+filterMapAux :: forall k v1 v2
+              . (HashMap k v1 -> Maybe (HashMap k v2))
+             -> (Leaf k v1 -> Maybe (Leaf k v2))
+             -> HashMap k v1
+             -> HashMap k v2
+filterMapAux onLeaf onColl = go
   where
     go Empty = Empty
-    go t@(Leaf _ (L k v))
-        | pred k v  = t
+    go t@Leaf{}
+        | Just t' <- onLeaf t = t'
         | otherwise = Empty
     go (BitmapIndexed b ary) = filterA ary b
     go (Full ary) = filterA ary fullNodeMask
@@ -854,9 +967,9 @@
             mary <- A.new_ n
             step ary0 mary b0 0 0 1 n
       where
-        step :: A.Array (HashMap k v) -> A.MArray s (HashMap k v)
+        step :: A.Array (HashMap k v1) -> A.MArray s (HashMap k v2)
              -> Bitmap -> Int -> Int -> Bitmap -> Int
-             -> ST s (HashMap k v)
+             -> ST s (HashMap k v2)
         step !ary !mary !b i !j !bi n
             | i >= n = case j of
                 0 -> return Empty
@@ -883,9 +996,9 @@
             mary <- A.new_ n
             step ary0 mary 0 0 n
       where
-        step :: A.Array (Leaf k v) -> A.MArray s (Leaf k v)
+        step :: A.Array (Leaf k v1) -> A.MArray s (Leaf k v2)
              -> Int -> Int -> Int
-             -> ST s (HashMap k v)
+             -> ST s (HashMap k v2)
         step !ary !mary i !j n
             | i >= n    = case j of
                 0 -> return Empty
@@ -895,10 +1008,10 @@
                                  return $! Collision h ary2
                   | otherwise -> do ary2 <- trim mary j
                                     return $! Collision h ary2
-            | pred k v  = A.write mary j el >> step ary mary (i+1) (j+1) n
+            | Just el <- onColl (A.index ary i)
+                = A.write mary j el >> step ary mary (i+1) (j+1) n
             | otherwise = step ary mary (i+1) j n
-          where el@(L k v) = A.index ary i
-{-# INLINE filterWithKey #-}
+{-# INLINE filterMapAux #-}
 
 -- | /O(n)/ Filter this map by retaining only elements which values
 -- satisfy a predicate.
diff --git a/Data/HashMap/Lazy.hs b/Data/HashMap/Lazy.hs
--- a/Data/HashMap/Lazy.hs
+++ b/Data/HashMap/Lazy.hs
@@ -47,6 +47,8 @@
     , insertWith
     , delete
     , adjust
+    , update
+    , alter
 
       -- * Combine
       -- ** Union
@@ -63,6 +65,7 @@
     , difference
     , intersection
     , intersectionWith
+    , intersectionWithKey
 
       -- * Folds
     , foldl'
@@ -73,6 +76,8 @@
       -- * Filter
     , HM.filter
     , filterWithKey
+    , mapMaybe
+    , mapMaybeWithKey
 
       -- * Conversions
     , keys
diff --git a/Data/HashMap/Strict.hs b/Data/HashMap/Strict.hs
--- a/Data/HashMap/Strict.hs
+++ b/Data/HashMap/Strict.hs
@@ -1,4 +1,4 @@
-{-# LANGUAGE BangPatterns, CPP #-}
+{-# LANGUAGE BangPatterns, CPP, PatternGuards #-}
 
 #if __GLASGOW_HASKELL__ >= 702
 {-# LANGUAGE Trustworthy #-}
@@ -47,6 +47,8 @@
     , insertWith
     , delete
     , adjust
+    , update
+    , alter
 
       -- * Combine
       -- ** Union
@@ -63,6 +65,7 @@
     , difference
     , intersection
     , intersectionWith
+    , intersectionWithKey
 
       -- * Folds
     , foldl'
@@ -73,6 +76,8 @@
       -- * Filter
     , HM.filter
     , filterWithKey
+    , mapMaybe
+    , mapMaybeWithKey
 
       -- * Conversions
     , keys
@@ -92,8 +97,9 @@
 import qualified Data.HashMap.Array as A
 import qualified Data.HashMap.Base as HM
 import Data.HashMap.Base hiding (
-    adjust, fromList, fromListWith, insert, insertWith, intersectionWith,
-    map, mapWithKey, singleton, unionWith)
+    alter, adjust, fromList, fromListWith, insert, insertWith, intersectionWith,
+    intersectionWithKey, map, mapWithKey, mapMaybe, mapMaybeWithKey, singleton,
+    update, unionWith)
 import Data.HashMap.Unsafe (runST)
 
 -- $strictness
@@ -227,6 +233,23 @@
         | otherwise = t
 {-# INLINABLE adjust #-}
 
+-- | /O(log n)/  The expression (@'update' f k map@) updates the value @x@ at @k@, 
+-- (if it is in the map). If (f k x) is @'Nothing', the element is deleted. 
+-- If it is (@'Just' y), the key k is bound to the new value y.
+update :: (Eq k, Hashable k) => (a -> Maybe a) -> k -> HashMap k a -> HashMap k a
+update f = alter (>>= f)
+{-# INLINABLE update #-}
+
+-- | /O(log n)/  The expression (@'alter' f k map@) alters the value @x@ at @k@, or
+-- absence thereof. @alter@ can be used to insert, delete, or update a value in a
+-- map. In short : @'lookup' k ('alter' f k m) = f ('lookup' k m)@.
+alter :: (Eq k, Hashable k) => (Maybe v -> Maybe v) -> k -> HashMap k v -> HashMap k v
+alter f k m =
+  case f (HM.lookup k m) of
+    Nothing -> delete k m
+    Just v  -> insert k v m
+{-# INLINABLE alter #-}
+
 ------------------------------------------------------------------------
 -- * Combine
 
@@ -336,6 +359,28 @@
 map f = mapWithKey (const f)
 {-# INLINE map #-}
 
+
+------------------------------------------------------------------------
+-- * Filter
+
+-- | /O(n)/ Transform this map by applying a function to every value
+--   and retaining only some of them.
+mapMaybeWithKey :: (k -> v1 -> Maybe v2) -> HashMap k v1 -> HashMap k v2
+mapMaybeWithKey f = filterMapAux onLeaf onColl
+  where onLeaf (Leaf h (L k v)) | Just v' <- f k v = Just (leaf h k v')
+        onLeaf _ = Nothing
+
+        onColl (L k v) | Just v' <- f k v = Just (L k v')
+                       | otherwise = Nothing
+{-# INLINE mapMaybeWithKey #-}
+
+-- | /O(n)/ Transform this map by applying a function to every value
+--   and retaining only some of them.
+mapMaybe :: (v1 -> Maybe v2) -> HashMap k v1 -> HashMap k v2
+mapMaybe f = mapMaybeWithKey (const f)
+{-# INLINE mapMaybe #-}
+
+
 -- TODO: Should we add a strict traverseWithKey?
 
 ------------------------------------------------------------------------
@@ -352,6 +397,18 @@
                  Just w -> insert k (f v w) m
                  _      -> m
 {-# INLINABLE intersectionWith #-}
+
+-- | /O(n+m)/ Intersection of two maps. If a key occurs in both maps
+-- the provided function is used to combine the values from the two
+-- maps.
+intersectionWithKey :: (Eq k, Hashable k) => (k -> v1 -> v2 -> v3)
+                    -> HashMap k v1 -> HashMap k v2 -> HashMap k v3
+intersectionWithKey f a b = foldlWithKey' go empty a
+  where
+    go m k v = case HM.lookup k b of
+                 Just w -> insert k (f k v w) m
+                 _      -> m
+{-# INLINABLE intersectionWithKey #-}
 
 ------------------------------------------------------------------------
 -- ** Lists
diff --git a/Data/HashMap/Unsafe.hs b/Data/HashMap/Unsafe.hs
--- a/Data/HashMap/Unsafe.hs
+++ b/Data/HashMap/Unsafe.hs
@@ -13,16 +13,16 @@
     ) where
 
 import GHC.Base (realWorld#)
-import GHC.ST hiding (runST, runSTRep)
+import qualified GHC.ST as ST
 
 -- | Return the value computed by a state transformer computation.
 -- The @forall@ ensures that the internal state used by the 'ST'
 -- computation is inaccessible to the rest of the program.
-runST :: (forall s. ST s a) -> a
-runST st = runSTRep (case st of { ST st_rep -> st_rep })
+runST :: (forall s. ST.ST s a) -> a
+runST st = runSTRep (case st of { ST.ST st_rep -> st_rep })
 {-# INLINE runST #-}
 
-runSTRep :: (forall s. STRep s a) -> a
+runSTRep :: (forall s. ST.STRep s a) -> a
 runSTRep st_rep = case st_rep realWorld# of
                         (# _, r #) -> r
 {-# INLINE [0] runSTRep #-}
diff --git a/Data/HashSet.hs b/Data/HashSet.hs
--- a/Data/HashSet.hs
+++ b/Data/HashSet.hs
@@ -1,7 +1,11 @@
 {-# LANGUAGE CPP, DeriveDataTypeable #-}
 #if __GLASGOW_HASKELL__ >= 708
+{-# LANGUAGE RoleAnnotations #-}
 {-# LANGUAGE TypeFamilies #-}
 #endif
+#if __GLASGOW_HASKELL__ >= 702
+{-# LANGUAGE Trustworthy #-}
+#endif
 
 ------------------------------------------------------------------------
 -- |
@@ -57,16 +61,24 @@
     -- * Filter
     , filter
 
+    -- * Conversions
+
     -- ** Lists
     , toList
     , fromList
+
+    -- * HashMaps
+    , toMap
+    , fromMap
     ) where
 
 import Control.DeepSeq (NFData(..))
 import Data.Data hiding (Typeable)
 import Data.HashMap.Base (HashMap, foldrWithKey)
-import Data.Hashable (Hashable)
-#if __GLASGOW_HASKELL__ < 709
+import Data.Hashable (Hashable(hashWithSalt))
+#if __GLASGOW_HASKELL__ >= 711
+import Data.Semigroup (Semigroup(..), Monoid(..))
+#elif __GLASGOW_HASKELL__ < 709
 import Data.Monoid (Monoid(..))
 #endif
 import GHC.Exts (build)
@@ -86,6 +98,10 @@
       asMap :: HashMap a ()
     } deriving (Typeable)
 
+#if __GLASGOW_HASKELL__ >= 708
+type role HashSet nominal
+#endif
+
 instance (NFData a) => NFData (HashSet a) where
     rnf = rnf . asMap
     {-# INLINE rnf #-}
@@ -100,10 +116,20 @@
     foldr = Data.HashSet.foldr
     {-# INLINE foldr #-}
 
+#if __GLASGOW_HASKELL__ >= 711
+instance (Hashable a, Eq a) => Semigroup (HashSet a) where
+    (<>) = union
+    {-# INLINE (<>) #-}
+#endif
+
 instance (Hashable a, Eq a) => Monoid (HashSet a) where
     mempty = empty
     {-# INLINE mempty #-}
+#if __GLASGOW_HASKELL__ >= 711
+    mappend = (<>)
+#else
     mappend = union
+#endif
     {-# INLINE mappend #-}
 
 instance (Eq a, Hashable a, Read a) => Read (HashSet a) where
@@ -127,6 +153,9 @@
     dataTypeOf _   = hashSetDataType
     dataCast1 f    = gcast1 f
 
+instance (Hashable a) => Hashable (HashSet a) where
+    hashWithSalt salt = hashWithSalt salt . asMap
+
 fromListConstr :: Constr
 fromListConstr = mkConstr hashSetDataType "fromList" [] Prefix
 
@@ -141,6 +170,14 @@
 singleton :: Hashable a => a -> HashSet a
 singleton a = HashSet (H.singleton a ())
 {-# INLINABLE singleton #-}
+
+-- | /O(1)/ Convert to the equivalent 'HashMap'.
+toMap :: HashSet a -> HashMap a ()
+toMap = asMap
+
+-- | /O(1)/ Convert from the equivalent 'HashMap'.
+fromMap :: HashMap a () -> HashSet a
+fromMap = HashSet
 
 -- | /O(n+m)/ Construct a set containing all elements from both sets.
 --
diff --git a/benchmarks/Benchmarks.hs b/benchmarks/Benchmarks.hs
--- a/benchmarks/Benchmarks.hs
+++ b/benchmarks/Benchmarks.hs
@@ -1,12 +1,10 @@
-{-# LANGUAGE CPP, GADTs, PackageImports #-}
+{-# LANGUAGE CPP, DeriveGeneric, GADTs, PackageImports, RecordWildCards #-}
 
 module Main where
 
 import Control.DeepSeq
-import Control.Exception (evaluate)
-import Control.Monad.Trans (liftIO)
-import Criterion.Config
-import Criterion.Main
+import Control.DeepSeq.Generics (genericRnf)
+import Criterion.Main (bench, bgroup, defaultMain, env, nf, whnf)
 import Data.Bits ((.&.))
 import Data.Hashable (Hashable)
 import qualified Data.ByteString as BS
@@ -16,6 +14,7 @@
 import qualified Data.Map as M
 import Data.List (foldl')
 import Data.Maybe (fromMaybe)
+import GHC.Generics (Generic)
 import Prelude hiding (lookup)
 
 import qualified Util.ByteString as UBS
@@ -32,20 +31,82 @@
 instance NFData B where
     rnf (B b) = rnf b
 
+-- TODO: This a stopgap measure to keep the benchmark work with
+-- Criterion 1.0.
+data Env = Env {
+    n :: !Int,
+
+    elems   :: ![(String, Int)],
+    keys    :: ![String],
+    elemsBS :: ![(BS.ByteString, Int)],
+    keysBS  :: ![BS.ByteString],
+    elemsI  :: ![(Int, Int)],
+    keysI   :: ![Int],
+    elemsI2 :: ![(Int, Int)],  -- for union
+
+    keys'    :: ![String],
+    keysBS'  :: ![BS.ByteString],
+    keysI'   :: ![Int],
+
+    keysDup    :: ![String],
+    keysDupBS  :: ![BS.ByteString],
+    keysDupI   :: ![Int],
+    elemsDup   :: ![(String, Int)],
+    elemsDupBS :: ![(BS.ByteString, Int)],
+    elemsDupI  :: ![(Int, Int)],
+
+    hm    :: !(HM.HashMap String Int),
+    hmbs  :: !(HM.HashMap BS.ByteString Int),
+    hmi   :: !(HM.HashMap Int Int),
+    hmi2  :: !(HM.HashMap Int Int),
+    m     :: !(M.Map String Int),
+    mbs   :: !(M.Map BS.ByteString Int),
+    im    :: !(IM.IntMap Int),
+    ihm   :: !(IHM.Map String Int),
+    ihmbs :: !(IHM.Map BS.ByteString Int)
+    } deriving Generic
+
+instance NFData Env where rnf = genericRnf
+
+setupEnv :: IO Env
+setupEnv = do
+    let n = 2^(12 :: Int)
+
+        elems   = zip keys [1..n]
+        keys    = US.rnd 8 n
+        elemsBS = zip keysBS [1..n]
+        keysBS  = UBS.rnd 8 n
+        elemsI  = zip keysI [1..n]
+        keysI   = UI.rnd (n+n) n
+        elemsI2 = zip [n `div` 2..n + (n `div` 2)] [1..n]  -- for union
+
+        keys'    = US.rnd' 8 n
+        keysBS'  = UBS.rnd' 8 n
+        keysI'   = UI.rnd' (n+n) n
+
+        keysDup    = US.rnd 2 n
+        keysDupBS  = UBS.rnd 2 n
+        keysDupI   = UI.rnd (n`div`4) n
+        elemsDup   = zip keysDup [1..n]
+        elemsDupBS = zip keysDupBS [1..n]
+        elemsDupI  = zip keysDupI [1..n]
+
+        hm   = HM.fromList elems
+        hmbs = HM.fromList elemsBS
+        hmi  = HM.fromList elemsI
+        hmi2 = HM.fromList elemsI2
+        m    = M.fromList elems
+        mbs  = M.fromList elemsBS
+        im   = IM.fromList elemsI
+        ihm  = IHM.fromList elems
+        ihmbs = IHM.fromList elemsBS
+    return Env{..}
+
 main :: IO ()
 main = do
-    let hm   = HM.fromList elems :: HM.HashMap String Int
-        hmbs = HM.fromList elemsBS :: HM.HashMap BS.ByteString Int
-        hmi  = HM.fromList elemsI :: HM.HashMap Int Int
-        hmi2 = HM.fromList elemsI2 :: HM.HashMap Int Int
-        m    = M.fromList elems :: M.Map String Int
-        mbs  = M.fromList elemsBS :: M.Map BS.ByteString Int
-        im   = IM.fromList elemsI :: IM.IntMap Int
-        ihm  = IHM.fromList elems :: IHM.Map String Int
-        ihmbs = IHM.fromList elemsBS :: IHM.Map BS.ByteString Int
-    defaultMainWith defaultConfig
-        (liftIO . evaluate $ rnf [B m, B mbs, B hm, B hmbs, B hmi, B im])
+    defaultMain
         [
+          env setupEnv $ \ ~(Env{..}) ->
           -- * Comparison to other data structures
           -- ** Map
           bgroup "Map"
@@ -84,7 +145,8 @@
           ]
 
           -- ** Map from the hashmap package
-        , bgroup "hashmap/Map"
+        , env setupEnv $ \ ~(Env{..}) ->
+          bgroup "hashmap/Map"
           [ bgroup "lookup"
             [ bench "String" $ whnf (lookupIHM keys) ihm
             , bench "ByteString" $ whnf (lookupIHM keysBS) ihmbs
@@ -120,7 +182,8 @@
           ]
 
           -- ** IntMap
-        , bgroup "IntMap"
+        , env setupEnv $ \ ~(Env{..}) ->
+          bgroup "IntMap"
           [ bench "lookup" $ whnf (lookupIM keysI) im
           , bench "lookup-miss" $ whnf (lookupIM keysI') im
           , bench "insert" $ whnf (insertIM elemsI) IM.empty
@@ -131,7 +194,8 @@
           , bench "fromList" $ whnf IM.fromList elemsI
           ]
 
-        , bgroup "HashMap"
+        , env setupEnv $ \ ~(Env{..}) ->
+          bgroup "HashMap"
           [ -- * Basic interface
             bgroup "lookup"
             [ bench "String" $ whnf (lookup keys) hm
@@ -217,28 +281,6 @@
             ]
           ]
         ]
-  where
-    n :: Int
-    n = 2^(12 :: Int)
-
-    elems   = zip keys [1..n]
-    keys    = US.rnd 8 n
-    elemsBS = zip keysBS [1..n]
-    keysBS  = UBS.rnd 8 n
-    elemsI  = zip keysI [1..n]
-    keysI   = UI.rnd (n+n) n
-    elemsI2 = zip [n `div` 2..n + (n `div` 2)] [1..n]  -- for union
-
-    keys'    = US.rnd' 8 n
-    keysBS'  = UBS.rnd' 8 n
-    keysI'   = UI.rnd' (n+n) n
-
-    keysDup    = US.rnd 2 n
-    keysDupBS  = UBS.rnd 2 n
-    keysDupI   = UI.rnd (n`div`4) n
-    elemsDup   = zip keysDup [1..n]
-    elemsDupBS = zip keysDupBS [1..n]
-    elemsDupI  = zip keysDupI [1..n]
 
 ------------------------------------------------------------------------
 -- * HashMap
diff --git a/tests/HashMapProperties.hs b/tests/HashMapProperties.hs
--- a/tests/HashMapProperties.hs
+++ b/tests/HashMapProperties.hs
@@ -5,17 +5,19 @@
 
 module Main (main) where
 
+import Control.Monad ( guard )
 import qualified Data.Foldable as Foldable
 import Data.Function (on)
 import Data.Hashable (Hashable(hashWithSalt))
 import qualified Data.List as L
+import Data.Ord (comparing)
 #if defined(STRICT)
 import qualified Data.HashMap.Strict as HM
 #else
 import qualified Data.HashMap.Lazy as HM
 #endif
 import qualified Data.Map as M
-import Test.QuickCheck (Arbitrary, Property, (==>))
+import Test.QuickCheck (Arbitrary, Property, (==>), (===))
 import Test.Framework (Test, defaultMain, testGroup)
 import Test.Framework.Providers.QuickCheck2 (testProperty)
 
@@ -48,6 +50,19 @@
 pFoldable = (L.sort . Foldable.foldr (:) []) `eq`
             (L.sort . Foldable.foldr (:) [])
 
+pHashable :: [(Key, Int)] -> [Int] -> Int -> Property
+pHashable xs is salt =
+    x == y ==> hashWithSalt salt x === hashWithSalt salt y
+  where
+    ys = shuffle is xs
+    x = HM.fromList xs
+    y = HM.fromList ys
+    -- Shuffle the list using indexes in the second
+    shuffle :: [Int] -> [a] -> [a]
+    shuffle idxs = L.map snd
+                 . L.sortBy (comparing fst)
+                 . L.zip (idxs ++ [L.maximum (0:is) + 1 ..])
+
 ------------------------------------------------------------------------
 -- ** Basic interface
 
@@ -98,6 +113,21 @@
 pAdjust :: Key -> [(Key, Int)] -> Bool
 pAdjust k = M.adjust succ k `eq_` HM.adjust succ k
 
+pUpdateAdjust :: Key -> [(Key, Int)] -> Bool
+pUpdateAdjust k = M.update (Just . succ) k `eq_` HM.update (Just . succ) k
+
+pUpdateDelete :: Key -> [(Key, Int)] -> Bool
+pUpdateDelete k = M.update (const Nothing) k `eq_` HM.update (const Nothing) k
+
+pAlterAdjust :: Key -> [(Key, Int)] -> Bool
+pAlterAdjust k = M.alter (fmap succ) k `eq_` HM.alter (fmap succ) k
+
+pAlterInsert :: Key -> [(Key, Int)] -> Bool
+pAlterInsert k = M.alter (const $ Just 3) k `eq_` HM.alter (const $ Just 3) k
+
+pAlterDelete :: Key -> [(Key, Int)] -> Bool
+pAlterDelete k = M.alter (const Nothing) k `eq_` HM.alter (const Nothing) k
+
 ------------------------------------------------------------------------
 -- ** Combine
 
@@ -133,6 +163,13 @@
 pIntersectionWith xs ys = M.intersectionWith (-) (M.fromList xs) `eq_`
                           HM.intersectionWith (-) (HM.fromList xs) $ ys
 
+pIntersectionWithKey :: [(Key, Int)] -> [(Key, Int)] -> Bool
+pIntersectionWithKey xs ys = M.intersectionWithKey go (M.fromList xs) `eq_`
+                             HM.intersectionWithKey go (HM.fromList xs) $ ys
+  where
+    go :: Key -> Int -> Int -> Int
+    go (K k) i1 i2 = k - i1 - i2
+
 ------------------------------------------------------------------------
 -- ** Folds
 
@@ -158,6 +195,14 @@
 ------------------------------------------------------------------------
 -- ** Filter
 
+pMapMaybeWithKey :: [(Key, Int)] -> Bool
+pMapMaybeWithKey = M.mapMaybeWithKey f `eq_` HM.mapMaybeWithKey f
+  where f k v = guard (odd (unK k + v)) >> Just (v + 1)
+
+pMapMaybe :: [(Key, Int)] -> Bool
+pMapMaybe = M.mapMaybe f `eq_` HM.mapMaybe f
+  where f v = guard (odd v) >> Just (v + 1)
+
 pFilter :: [(Key, Int)] -> Bool
 pFilter = M.filter odd `eq_` HM.filter odd
 
@@ -198,6 +243,7 @@
       , testProperty "Read/Show" pReadShow
       , testProperty "Functor" pFunctor
       , testProperty "Foldable" pFoldable
+      , testProperty "Hashable" pHashable
       ]
     -- Basic interface
     , testGroup "basic interface"
@@ -209,6 +255,11 @@
       , testProperty "deleteCollision" pDeleteCollision
       , testProperty "insertWith" pInsertWith
       , testProperty "adjust" pAdjust
+      , testProperty "updateAdjust" pUpdateAdjust
+      , testProperty "updateDelete" pUpdateDelete
+      , testProperty "alterAdjust" pAlterAdjust
+      , testProperty "alterInsert" pAlterInsert
+      , testProperty "alterDelete" pAlterDelete
       ]
     -- Combine
     , testProperty "union" pUnion
@@ -226,11 +277,14 @@
       [ testProperty "difference" pDifference
       , testProperty "intersection" pIntersection
       , testProperty "intersectionWith" pIntersectionWith
+      , testProperty "intersectionWithKey" pIntersectionWithKey
       ]
     -- Filter
     , testGroup "filter"
       [ testProperty "filter" pFilter
       , testProperty "filterWithKey" pFilterWithKey
+      , testProperty "mapMaybe" pMapMaybe
+      , testProperty "mapMaybeWithKey" pMapMaybeWithKey
       ]
     -- Conversions
     , testGroup "conversions"
diff --git a/tests/HashSetProperties.hs b/tests/HashSetProperties.hs
--- a/tests/HashSetProperties.hs
+++ b/tests/HashSetProperties.hs
@@ -10,7 +10,8 @@
 import qualified Data.List as L
 import qualified Data.HashSet as S
 import qualified Data.Set as Set
-import Test.QuickCheck (Arbitrary)
+import Data.Ord (comparing)
+import Test.QuickCheck (Arbitrary, Property, (==>), (===))
 import Test.Framework (Test, defaultMain, testGroup)
 import Test.Framework.Providers.QuickCheck2 (testProperty)
 
@@ -40,6 +41,25 @@
 pFoldable = (L.sort . Foldable.foldr (:) []) `eq`
             (L.sort . Foldable.foldr (:) [])
 
+pPermutationEq :: [Key] -> [Int] -> Bool
+pPermutationEq xs is = S.fromList xs == S.fromList ys
+  where
+    ys = shuffle is xs
+    shuffle idxs = L.map snd
+                 . L.sortBy (comparing fst)
+                 . L.zip (idxs ++ [L.maximum (0:is) + 1 ..])
+
+pHashable :: [Key] -> [Int] -> Int -> Property
+pHashable xs is salt =
+    x == y ==> hashWithSalt salt x === hashWithSalt salt y
+  where
+    ys = shuffle is xs
+    x = S.fromList xs
+    y = S.fromList ys
+    shuffle idxs = L.map snd
+                 . L.sortBy (comparing fst)
+                 . L.zip (idxs ++ [L.maximum (0:is) + 1 ..])
+
 ------------------------------------------------------------------------
 -- ** Basic interface
 
@@ -113,9 +133,11 @@
     -- Instances
       testGroup "instances"
       [ testProperty "==" pEq
+      , testProperty "Permutation ==" pPermutationEq
       , testProperty "/=" pNeq
       , testProperty "Read/Show" pReadShow
       , testProperty "Foldable" pFoldable
+      , testProperty "Hashable" pHashable
       ]
     -- Basic interface
     , testGroup "basic interface"
diff --git a/unordered-containers.cabal b/unordered-containers.cabal
--- a/unordered-containers.cabal
+++ b/unordered-containers.cabal
@@ -1,5 +1,5 @@
 name:           unordered-containers
-version:        0.2.5.1
+version:        0.2.6.0
 synopsis:       Efficient hashing-based container types
 description:
   Efficient hashing-based container types.  The containers have been
@@ -19,6 +19,8 @@
 category:       Data
 build-type:     Simple
 cabal-version:  >=1.8
+extra-source-files: CHANGES.md
+tested-with:    GHC==7.10.3, GHC==7.8.4, GHC==7.6.3, GHC==7.4.2
 
 flag debug
   description:  Enable debug support
@@ -39,7 +41,7 @@
   build-depends:
     base >= 4 && < 5,
     deepseq >= 1.1,
-    hashable >= 1.0.1.1
+    hashable >= 1.0.1.1 && < 1.3
 
   if impl(ghc < 7.4)
     c-sources: cbits/popc.c
@@ -151,8 +153,9 @@
     base,
     bytestring,
     containers,
-    criterion,
+    criterion >= 1.0 && < 1.1,
     deepseq >= 1.1,
+    deepseq-generics,
     hashable >= 1.0.1.1,
     hashmap,
     mtl,
