packages feed

unordered-containers 0.2.1.0 → 0.2.2.0

raw patch · 8 files changed

+236/−146 lines, 8 filesdep ~basedep ~containersdep ~deepseq

Dependency ranges changed: base, containers, deepseq, hashable, test-framework, test-framework-quickcheck2

Files

Data/HashMap/Array.hs view
@@ -1,5 +1,5 @@ {-# LANGUAGE BangPatterns, CPP, MagicHash, Rank2Types, UnboxedTuples #-}-{-# OPTIONS_GHC -funbox-strict-fields #-}+{-# OPTIONS_GHC -fno-full-laziness -funbox-strict-fields #-}  -- | Zero based arrays. --@@ -48,15 +48,18 @@     , map'     , traverse     , filter+    , toList     ) where  import qualified Data.Traversable as Traversable import Control.Applicative (Applicative) import Control.DeepSeq-import Control.Monad.ST+import Control.Monad.ST hiding (runST) import GHC.Exts import GHC.ST (ST(..)) import Prelude hiding (filter, foldr, length, map, read)++import Data.HashMap.Unsafe (runST)  ------------------------------------------------------------------------ 
Data/HashMap/Base.hs view
@@ -1,5 +1,5 @@ {-# LANGUAGE BangPatterns, CPP, DeriveDataTypeable, MagicHash #-}-{-# OPTIONS_GHC -funbox-strict-fields #-}+{-# OPTIONS_GHC -fno-full-laziness -funbox-strict-fields #-}  module Data.HashMap.Base     (@@ -36,6 +36,7 @@       -- * Difference and intersection     , difference     , intersection+    , intersectionWith        -- * Folds     , foldl'@@ -76,7 +77,7 @@  import Control.Applicative ((<$>), Applicative(pure)) import Control.DeepSeq (NFData(rnf))-import Control.Monad.ST (ST, runST)+import Control.Monad.ST (ST) import Data.Bits ((.&.), (.|.), complement) import qualified Data.Foldable as Foldable import qualified Data.List as L@@ -89,6 +90,7 @@ import qualified Data.Hashable as H import Data.Hashable (Hashable) import Data.HashMap.PopCount (popCount)+import Data.HashMap.Unsafe (runST) import Data.HashMap.UnsafeShift (unsafeShiftL, unsafeShiftR) import Data.Typeable (Typeable) @@ -103,6 +105,7 @@ hash = fromIntegral . H.hash  data Leaf k v = L !k v+  deriving (Eq)  instance (NFData k, NFData v) => NFData (Leaf k v) where     rnf (L k v) = rnf k `seq` rnf v@@ -149,10 +152,22 @@ instance Traversable (HashMap k) where     traverse f = traverseWithKey (const f) --- NOTE: This is just a placeholder. instance (Eq k, Eq v) => Eq (HashMap k v) where-    a == b = toList a == toList b+    (==) = equal +equal :: (Eq k, Eq v) => HashMap k v -> HashMap k v -> Bool+equal (BitmapIndexed b1 ary1) (BitmapIndexed b2 ary2) =+    b1 == b2 && A.toList ary1 == A.toList ary2+equal (Leaf k1 v1) (Leaf k2 v2) =+    k1 == k2 && v1 == v2+equal (Full ary1) (Full ary2) =+    A.toList ary1 == A.toList ary2+equal (Collision k1 ary1) (Collision k2 ary2) =+    k1 == k2 && A.length ary1 == A.length ary2+      && L.null (A.toList ary1 L.\\ A.toList ary2)+equal Empty Empty = True+equal _     _     = False+ ------------------------------------------------------------------------ -- * Construction @@ -254,42 +269,38 @@ -- key in this map.  If this map previously contained a mapping for -- the key, the old value is replaced. insert :: (Eq k, Hashable k) => k -> v -> HashMap k v -> HashMap k v-insert k0 v0 m0 = runST (go h0 k0 v0 0 m0)+insert k0 v0 m0 = go h0 k0 v0 0 m0   where     h0 = hash k0-    go !h !k x !_ Empty = return $! Leaf h (L k x)+    go !h !k x !_ Empty = Leaf h (L k x)     go h k x s t@(Leaf hy l@(L ky y))         | hy == h = if ky == k                     then if x `ptrEq` y-                         then return t-                         else return $! Leaf h (L k x)-                    else return $! collision h l (L k x)-        | otherwise = two s h k x hy ky y+                         then t+                         else Leaf h (L k x)+                    else collision h l (L k x)+        | otherwise = runST (two s h k x hy ky y)     go h k x s t@(BitmapIndexed b ary)-        | b .&. m == 0 = do-            !ary' <- A.insert' ary i $! Leaf h (L k x)-            return $! bitmapIndexedOrFull (b .|. m) ary'-        | otherwise = do-            st <- A.index_ ary i-            !st' <- go h k x (s+bitsPerSubkey) st-            if st' `ptrEq` st-                then return t-                else do-                    ary' <- A.update' ary i st'-                    return $! BitmapIndexed b ary'+        | b .&. m == 0 =+            let ary' = A.insert ary i $! Leaf h (L k x)+            in bitmapIndexedOrFull (b .|. m) ary'+        | otherwise =+            let !st  = A.index ary i+                !st' = go h k x (s+bitsPerSubkey) st+            in if st' `ptrEq` st+               then t+               else BitmapIndexed b (A.update ary i st')       where m = mask h s             i = sparseIndex b m-    go h k x s t@(Full ary) = do-        st <- A.index_ ary i-        !st' <- go h k x (s+bitsPerSubkey) st-        if st' `ptrEq` st-            then return t-            else do-                ary' <- update16' ary i st'-                return $! Full ary'+    go h k x s t@(Full ary) =+        let !st  = A.index ary i+            !st' = go h k x (s+bitsPerSubkey) st+        in if st' `ptrEq` st+            then t+            else Full (update16 ary i st')       where i = index h s     go h k x s t@(Collision hy v)-        | h == hy   = return $! Collision h (updateOrSnocWith const k x v)+        | h == hy   = Collision h (updateOrSnocWith const k x v)         | otherwise = go h k x s $ BitmapIndexed (mask hy s) (A.singleton t) #if __GLASGOW_HASKELL__ >= 700 {-# INLINABLE insert #-}@@ -338,7 +349,7 @@   where     go s h1 k1 v1 h2 k2 v2         | bp1 == bp2 = do-            st <- go (s+bitsPerSubkey) h1 k1 v1 h2 k2 v2 +            st <- go (s+bitsPerSubkey) h1 k1 v1 h2 k2 v2             ary <- A.singleton' st             return $! BitmapIndexed bp1 ary         | otherwise  = do@@ -362,34 +373,34 @@ -- >   where f new old = new + old insertWith :: (Eq k, Hashable k) => (v -> v -> v) -> k -> v -> HashMap k v             -> HashMap k v-insertWith f k0 v0 m0 = runST (go h0 k0 v0 0 m0)+insertWith f k0 v0 m0 = go h0 k0 v0 0 m0   where     h0 = hash k0-    go !h !k x !_ Empty = return $! Leaf h (L k x)+    go !h !k x !_ Empty = Leaf h (L k x)     go h k x s (Leaf hy l@(L ky y))         | hy == h = if ky == k-                    then return $! Leaf h (L k (f x y))-                    else return $! collision h l (L k x)-        | otherwise = two s h k x hy ky y+                    then Leaf h (L k (f x y))+                    else collision h l (L k x)+        | otherwise = runST (two s h k x hy ky y)     go h k x s (BitmapIndexed b ary)-        | b .&. m == 0 = do-            ary' <- A.insert' ary i $! Leaf h (L k x)-            return $! bitmapIndexedOrFull (b .|. m) ary'-        | otherwise = do-            st <- A.index_ ary i-            st' <- go h k x (s+bitsPerSubkey) st-            ary' <- A.update' ary i st'-            return $! BitmapIndexed b ary'+        | b .&. m == 0 =+            let ary' = A.insert ary i $! Leaf h (L k x)+            in bitmapIndexedOrFull (b .|. m) ary'+        | otherwise =+            let st   = A.index ary i+                st'  = go h k x (s+bitsPerSubkey) st+                ary' = A.update ary i st'+            in BitmapIndexed b ary'       where m = mask h s             i = sparseIndex b m-    go h k x s (Full ary) = do-        st <- A.index_ ary i-        st' <- go h k x (s+bitsPerSubkey) st-        ary' <- update16' ary i st'-        return $! Full ary'+    go h k x s (Full ary) =+        let st   = A.index ary i+            st'  = go h k x (s+bitsPerSubkey) st+            ary' = update16 ary i st'+        in Full ary'       where i = index h s     go h k x s t@(Collision hy v)-        | h == hy   = return $! Collision h (updateOrSnocWith f k x v)+        | h == hy   = Collision h (updateOrSnocWith f k x v)         | otherwise = go h k x s $ BitmapIndexed (mask hy s) (A.singleton t) #if __GLASGOW_HASKELL__ >= 700 {-# INLINABLE insertWith #-}@@ -434,54 +445,48 @@ -- | /O(log n)/ Remove the mapping for the specified key from this map -- if present. delete :: (Eq k, Hashable k) => k -> HashMap k v -> HashMap k v-delete k0 m0 = runST (go h0 k0 0 m0)+delete k0 m0 = go h0 k0 0 m0   where     h0 = hash k0-    go !_ !_ !_ Empty = return Empty+    go !_ !_ !_ Empty = Empty     go h k _ t@(Leaf hy (L ky _))-        | hy == h && ky == k = return Empty-        | otherwise          = return t+        | hy == h && ky == k = Empty+        | otherwise          = t     go h k s t@(BitmapIndexed b ary)-        | b .&. m == 0 = return t-        | otherwise = do+        | b .&. m == 0 = t+        | otherwise =             let !st = A.index ary i-            !st' <- go h k (s+bitsPerSubkey) st-            if st' `ptrEq` st-                then return t+                !st' = go h k (s+bitsPerSubkey) st+            in if st' `ptrEq` st+                then t                 else case st' of-                Empty | A.length ary == 1 -> return Empty-                      | otherwise -> do-                          ary' <- A.delete' ary i-                          return $! BitmapIndexed (b .&. complement m) ary'-                _ -> do-                    ary' <- A.update' ary i st'-                    return $! BitmapIndexed b ary'+                Empty | A.length ary == 1 -> Empty+                      | otherwise -> BitmapIndexed (b .&. complement m) (A.delete ary i)+                _ -> BitmapIndexed b (A.update ary i st')       where m = mask h s             i = sparseIndex b m-    go h k s t@(Full ary) = do-        let !st = A.index ary i-        !st' <- go h k (s+bitsPerSubkey) st-        if st' `ptrEq` st-            then return t+    go h k s t@(Full ary) =+        let !st   = A.index ary i+            !st' = go h k (s+bitsPerSubkey) st+        in if st' `ptrEq` st+            then t             else case st' of-            Empty -> do-                ary' <- A.delete' ary i-                let bm = fullNodeMask .&. complement (1 `unsafeShiftL` i)-                return $! BitmapIndexed bm ary'-            _ -> do-                ary' <- A.update' ary i st'-                return $! Full ary'+            Empty ->+                let ary' = A.delete ary i+                    bm   = fullNodeMask .&. complement (1 `unsafeShiftL` i)+                in BitmapIndexed bm ary'+            _ -> Full (A.update ary i st')       where i = index h s     go h k _ t@(Collision hy v)         | h == hy = case indexOf k v of             Just i                 | A.length v == 2 ->                     if i == 0-                    then return $! Leaf h (A.index v 1)-                    else return $! Leaf h (A.index v 0)-                | otherwise -> return $! Collision h (A.delete v i)-            Nothing -> return t-        | otherwise = return t+                    then Leaf h (A.index v 1)+                    else Leaf h (A.index v 0)+                | otherwise -> Collision h (A.delete v i)+            Nothing -> t+        | otherwise = t #if __GLASGOW_HASKELL__ >= 700 {-# INLINABLE delete #-} #endif@@ -623,20 +628,20 @@     mary <- A.new_ (popCount b')     -- iterate over nonzero bits of b1 .|. b2     -- it would be nice if we could shift m by more than 1 each time-    let hasBit b m = b .&. m /= 0+    let ba = b1 .&. b2         go !i !i1 !i2 !m-            | m > b'                     = return ()-            | hasBit b1 m && hasBit b2 m = do+            | m > b'        = return ()+            | b' .&. m == 0 = go i i1 i2 (m `unsafeShiftL` 1)+            | ba .&. m /= 0 = do                 A.write mary i $! f (A.index ary1 i1) (A.index ary2 i2)                 go (i+1) (i1+1) (i2+1) (m `unsafeShiftL` 1)-            | hasBit b1 m                = do+            | b1 .&. m /= 0 = do                 A.write mary i =<< A.index_ ary1 i1                 go (i+1) (i1+1) (i2  ) (m `unsafeShiftL` 1)-            | hasBit b2 m                = do+            | otherwise     = do                 A.write mary i =<< A.index_ ary2 i2                 go (i+1) (i1  ) (i2+1) (m `unsafeShiftL` 1)-            | otherwise                  = go i i1 i2 (m `unsafeShiftL` 1)-    go 0 0 0 1+    go 0 0 0 (b' .&. negate b') -- XXX: b' must be non-zero     return mary     -- TODO: For the case where b1 .&. b2 == b1, i.e. when one is a     -- subset of the other, we could use a slightly simpler algorithm,@@ -665,6 +670,9 @@                            A.map' (\ (L k v) -> L k (f v)) ary {-# INLINE map #-} +-- TODO: We should be able to use mutation to create the new+-- 'HashMap'.+ -- | /O(n)/ Transform this map by accumulating an Applicative result -- from every value. traverseWithKey :: Applicative f => (k -> v1 -> f v2) -> HashMap k v1@@ -682,7 +690,7 @@ ------------------------------------------------------------------------ -- * Difference and intersection --- | /O(n+m)/ Difference of two maps. Return elements of the first map+-- | /O(n*log m)/ Difference of two maps. Return elements of the first map -- not existing in the second. difference :: (Eq k, Hashable k) => HashMap k v -> HashMap k w -> HashMap k v difference a b = foldlWithKey' go empty a@@ -694,7 +702,7 @@ {-# INLINABLE difference #-} #endif --- | /O(n+m)/ Intersection of two maps. Return elements of the first+-- | /O(n*log m)/ Intersection of two maps. Return elements of the first -- map for keys existing in the second. intersection :: (Eq k, Hashable k) => HashMap k v -> HashMap k w -> HashMap k v intersection a b = foldlWithKey' go empty a@@ -704,6 +712,20 @@                  _      -> m #if __GLASGOW_HASKELL__ >= 700 {-# INLINABLE intersection #-}+#endif++-- | /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.+intersectionWith :: (Eq k, Hashable k) => (v1 -> v2 -> v3) -> HashMap k v1+                 -> HashMap k v2 -> HashMap k v3+intersectionWith f a b = foldlWithKey' go empty a+  where+    go m k v = case lookup k b of+                 Just w -> insert k (f v w) m+                 _      -> m+#if __GLASGOW_HASKELL__ >= 700+{-# INLINABLE intersectionWith #-} #endif  ------------------------------------------------------------------------
Data/HashMap/Lazy.hs view
@@ -62,6 +62,7 @@       -- * Difference and intersection     , difference     , intersection+    , intersectionWith        -- * Folds     , foldl'
Data/HashMap/Strict.hs view
@@ -63,6 +63,7 @@       -- * Difference and intersection     , difference     , intersection+    , intersectionWith        -- * Folds     , foldl'@@ -93,8 +94,8 @@ import qualified Data.HashMap.Array as A import qualified Data.HashMap.Base as HM import Data.HashMap.Base hiding (-    adjust, fromList, fromListWith, insert, insertWith, map, singleton,-    unionWith)+    adjust, fromList, fromListWith, insert, insertWith, intersectionWith, map,+    singleton, unionWith)  ------------------------------------------------------------------------ -- * Construction@@ -124,34 +125,34 @@ -- >   where f new old = new + old insertWith :: (Eq k, Hashable k) => (v -> v -> v) -> k -> v -> HashMap k v            -> HashMap k v-insertWith f k0 !v0 m0 = runST (go h0 k0 v0 0 m0)+insertWith f k0 !v0 m0 = go h0 k0 v0 0 m0   where     h0 = hash k0-    go !h !k x !_ Empty = return $ Leaf h (L k x)+    go !h !k x !_ Empty = Leaf h (L k x)     go h k x s (Leaf hy l@(L ky y))         | hy == h = if ky == k-                    then let !v' = f x y in return $! Leaf h (L k v')-                    else return $! collision h l (L k x)-        | otherwise = two s h k x hy ky y+                    then let !v' = f x y in Leaf h (L k v')+                    else collision h l (L k x)+        | otherwise = runST (two s h k x hy ky y)     go h k x s (BitmapIndexed b ary)-        | b .&. m == 0 = do-            ary' <- A.insert' ary i $! Leaf h (L k x)-            return $! bitmapIndexedOrFull (b .|. m) ary'-        | otherwise = do-            st <- A.index_ ary i-            st' <- go h k x (s+bitsPerSubkey) st-            ary' <- A.update' ary i st'-            return $! BitmapIndexed b ary'+        | b .&. m == 0 =+            let ary' = A.insert ary i $! Leaf h (L k x)+            in bitmapIndexedOrFull (b .|. m) ary'+        | otherwise =+            let st   = A.index ary i+                st'  = go h k x (s+bitsPerSubkey) st+                ary' = A.update ary i st'+            in BitmapIndexed b ary'       where m = mask h s             i = sparseIndex b m-    go h k x s (Full ary) = do-        st <- A.index_ ary i-        st' <- go h k x (s+bitsPerSubkey) st-        ary' <- update16' ary i st'-        return $! Full ary'+    go h k x s (Full ary) =+        let st   = A.index ary i+            st'  = go h k x (s+bitsPerSubkey) st+            ary' = update16 ary i st'+        in Full ary'       where i = index h s     go h k x s t@(Collision hy v)-        | h == hy   = return $! Collision h (updateOrSnocWith f k x v)+        | h == hy   = Collision h (updateOrSnocWith f k x v)         | otherwise = go h k x s $ BitmapIndexed (mask hy s) (A.singleton t) #if __GLASGOW_HASKELL__ >= 700 {-# INLINABLE insertWith #-}@@ -329,6 +330,23 @@ {-# INLINE map #-}  -- TODO: Should we add a strict traverseWithKey?++------------------------------------------------------------------------+-- * Difference and intersection++-- | /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.+intersectionWith :: (Eq k, Hashable k) => (v1 -> v2 -> v3) -> HashMap k v1+                 -> HashMap k v2 -> HashMap k v3+intersectionWith f a b = foldlWithKey' go empty a+  where+    go m k v = case HM.lookup k b of+                 Just w -> insert k (f v w) m+                 _      -> m+#if __GLASGOW_HASKELL__ >= 700+{-# INLINABLE intersectionWith #-}+#endif  ------------------------------------------------------------------------ -- ** Lists
+ Data/HashMap/Unsafe.hs view
@@ -0,0 +1,28 @@+{-# LANGUAGE MagicHash, Rank2Types, UnboxedTuples #-}++-- | This module exports a workaround for this bug:+--+--    http://hackage.haskell.org/trac/ghc/ticket/5916+--+-- Please read the comments in ghc/libraries/base/GHC/ST.lhs to+-- understand what's going on here.+--+-- Code that uses this module should be compiled with -fno-full-laziness+module Data.HashMap.Unsafe+    ( runST+    ) where++import GHC.Base (realWorld#)+import GHC.ST hiding (runST, runSTRep)++-- | 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 })+{-# INLINE runST #-}++runSTRep :: (forall s. STRep s a) -> a+runSTRep st_rep = case st_rep realWorld# of+                        (# _, r #) -> r+{-# INLINE [0] runSTRep #-}
tests/HashMapProperties.hs view
@@ -71,19 +71,23 @@  -- White-box test that tests the case of deleting one of two keys from -- a map, where the keys' hash values collide.-pDeleteCollision :: AlwaysCollide -> AlwaysCollide -> Bool -> Property-pDeleteCollision k1 k2 keepFst = k1 /= k2 ==> HM.member toKeep $ HM.delete toDelete $-                                 HM.fromList [(k1, 1 :: Int), (k2, 2)]+pDeleteCollision :: AlwaysCollide -> AlwaysCollide -> AlwaysCollide -> Int+                 -> Property+pDeleteCollision k1 k2 k3 idx = (k1 /= k2) && (k2 /= k3) && (k1 /= k3) ==>+                                HM.member toKeep $ HM.delete toDelete $+                                HM.fromList [(k1, 1 :: Int), (k2, 2), (k3, 3)]   where-    (toDelete, toKeep)-        | keepFst   = (k2, k1)-        | otherwise = (k1, k2)---- White-box test that tests the case of deleting one of many keys--- from a map, where the keys' hash values collide.-pDeleteCollisionMany :: AlwaysCollide -> [(AlwaysCollide, Int)] -> Bool-pDeleteCollisionMany k kvs = not $ (HM.member k) $ HM.delete k $-                             HM.fromList ((k, 1):kvs)+    which = idx `mod` 3+    toDelete+        | which == 0 = k1+        | which == 1 = k2+        | which == 2 = k3+        | otherwise = error "Impossible"+    toKeep+        | which == 0 = k2+        | which == 1 = k3+        | which == 2 = k1+        | otherwise = error "Impossible"  pInsertWith :: Key -> [(Key, Int)] -> Bool pInsertWith k = M.insertWith (+) k 1 `eq_` HM.insertWith (+) k 1@@ -122,6 +126,10 @@ pIntersection xs ys = M.intersection (M.fromList xs) `eq_`                       HM.intersection (HM.fromList xs) $ ys +pIntersectionWith :: [(Key, Int)] -> [(Key, Int)] -> Bool+pIntersectionWith xs ys = M.intersectionWith (-) (M.fromList xs) `eq_`+                          HM.intersectionWith (-) (HM.fromList xs) $ ys+ ------------------------------------------------------------------------ -- ** Folds @@ -187,7 +195,6 @@       , testProperty "insert" pInsert       , testProperty "delete" pDelete       , testProperty "deleteCollision" pDeleteCollision-      , testProperty "deleteCollisionMany" pDeleteCollisionMany       , testProperty "insertWith" pInsertWith       , testProperty "adjust" pAdjust       ]@@ -206,6 +213,7 @@     , testGroup "difference and intersection"       [ testProperty "difference" pDifference       , testProperty "intersection" pIntersection+      , testProperty "intersectionWith" pIntersectionWith       ]     -- Filter     , testGroup "filter"
tests/Regressions.hs view
@@ -13,6 +13,14 @@     m = HM.fromList (zip ns (repeat []))         m' = HM.delete 10 m +issue39 :: Assertion+issue39 = assert $ hm1 == hm2+  where+    hm1 = HM.fromList ([a, b] `zip` [1, 1 :: Int ..])+    hm2 = HM.fromList ([b, a] `zip` [1, 1 :: Int ..])+    a = (1, -1) :: (Int, Int)+    b = (-1, 1) :: (Int, Int)+ ------------------------------------------------------------------------ -- * Test list @@ -20,6 +28,7 @@ tests =     [       testCase "issue32" issue32+    , testCase "issue39" issue39     ]  ------------------------------------------------------------------------
unordered-containers.cabal view
@@ -1,5 +1,5 @@ name:           unordered-containers-version:        0.2.1.0+version:        0.2.2.0 synopsis:       Efficient hashing-based container types description:   Efficient hashing-based container types.  The containers have been@@ -32,12 +32,13 @@     Data.HashMap.Array     Data.HashMap.Base     Data.HashMap.PopCount+    Data.HashMap.Unsafe     Data.HashMap.UnsafeShift    build-depends:-    base >= 4 && < 4.6,-    deepseq >= 1.1 && < 1.4,-    hashable >= 1.0.1.1 && < 1.2+    base >= 4 && < 5,+    deepseq >= 1.1,+    hashable >= 1.0.1.1    if impl(ghc < 7.4)     c-sources: cbits/popc.c@@ -57,11 +58,11 @@    build-depends:     base,-    containers >= 0.4.1 && < 0.5,-    hashable >= 1.0.1.1 && < 1.2,+    containers >= 0.4.1,+    hashable >= 1.0.1.1,     QuickCheck >= 2.4.0.1,-    test-framework >= 0.3.3 && < 0.6,-    test-framework-quickcheck2 >= 0.2.9 && < 0.3,+    test-framework >= 0.3.3,+    test-framework-quickcheck2 >= 0.2.9,     unordered-containers    ghc-options: -Wall@@ -74,11 +75,11 @@    build-depends:     base,-    containers >= 0.4.1 && < 0.5,-    hashable >= 1.0.1.1 && < 1.2,+    containers >= 0.4.1,+    hashable >= 1.0.1.1,     QuickCheck >= 2.4.0.1,-    test-framework >= 0.3.3 && < 0.6,-    test-framework-quickcheck2 >= 0.2.9 && < 0.3,+    test-framework >= 0.3.3,+    test-framework-quickcheck2 >= 0.2.9,     unordered-containers    ghc-options: -Wall@@ -91,11 +92,11 @@    build-depends:     base,-    containers >= 0.4.2 && < 0.5,-    hashable >= 1.0.1.1 && < 1.2,+    containers >= 0.4.2,+    hashable >= 1.0.1.1,     QuickCheck >= 2.4.0.1,-    test-framework >= 0.3.3 && < 0.6,-    test-framework-quickcheck2 >= 0.2.9 && < 0.3,+    test-framework >= 0.3.3,+    test-framework-quickcheck2 >= 0.2.9,     unordered-containers    ghc-options: -Wall@@ -108,9 +109,9 @@    build-depends:     base,-    hashable >= 1.0.1.1 && < 1.2,+    hashable >= 1.0.1.1,     HUnit,-    test-framework >= 0.3.3 && < 0.6,+    test-framework >= 0.3.3,     test-framework-hunit,     unordered-containers