containers 0.5.5.1 → 0.5.6.0
raw patch · 23 files changed
+1239/−490 lines, 23 filesdep −containersdep ~basedep ~deepseq
Dependencies removed: containers
Dependency ranges changed: base, deepseq
Files
- Data/BitUtil.hs +0/−71
- Data/Graph.hs +1/−1
- Data/IntMap.hs +1/−1
- Data/IntMap/Base.hs +100/−12
- Data/IntMap/Lazy.hs +1/−1
- Data/IntMap/Strict.hs +30/−2
- Data/IntSet/Base.hs +28/−32
- Data/Map/Base.hs +92/−10
- Data/Map/Strict.hs +40/−4
- Data/Sequence.hs +441/−49
- Data/Set/Base.hs +54/−8
- Data/StrictPair.hs +0/−13
- Data/Tree.hs +33/−3
- Data/Utils/BitUtil.hs +71/−0
- Data/Utils/StrictFold.hs +16/−0
- Data/Utils/StrictPair.hs +13/−0
- benchmarks/Sequence.hs +27/−6
- containers.cabal +25/−22
- tests/IntMapStrictness.hs +0/−127
- tests/MapStrictness.hs +0/−128
- tests/intmap-strictness.hs +127/−0
- tests/map-strictness.hs +128/−0
- tests/seq-properties.hs +11/−0
− Data/BitUtil.hs
@@ -1,71 +0,0 @@-{-# LANGUAGE CPP #-}-#if __GLASGOW_HASKELL__-{-# LANGUAGE MagicHash #-}-#endif-#if !defined(TESTING) && __GLASGOW_HASKELL__ >= 703-{-# LANGUAGE Trustworthy #-}-#endif--------------------------------------------------------------------------------- |--- Module : Data.BitUtil--- Copyright : (c) Clark Gaebel 2012--- (c) Johan Tibel 2012--- License : BSD-style--- Maintainer : libraries@haskell.org--- Stability : provisional--- Portability : portable--------------------------------------------------------------------------------module Data.BitUtil- ( highestBitMask- , shiftLL- , shiftRL- ) where---- On GHC, include MachDeps.h to get WORD_SIZE_IN_BITS macro.-#if defined(__GLASGOW_HASKELL__)-# include "MachDeps.h"-#endif--import Data.Bits ((.|.), xor)--#if __GLASGOW_HASKELL__-import GHC.Exts (Word(..), Int(..))-import GHC.Prim (uncheckedShiftL#, uncheckedShiftRL#)-#else-import Data.Word (shiftL, shiftR)-#endif---- The highestBitMask implementation is based on--- http://graphics.stanford.edu/~seander/bithacks.html#RoundUpPowerOf2--- which has been put in the public domain.---- | Return a word where only the highest bit is set.-highestBitMask :: Word -> Word-highestBitMask x1 = let x2 = x1 .|. x1 `shiftRL` 1- x3 = x2 .|. x2 `shiftRL` 2- x4 = x3 .|. x3 `shiftRL` 4- x5 = x4 .|. x4 `shiftRL` 8- x6 = x5 .|. x5 `shiftRL` 16-#if !(defined(__GLASGOW_HASKELL__) && WORD_SIZE_IN_BITS==32)- x7 = x6 .|. x6 `shiftRL` 32- in x7 `xor` (x7 `shiftRL` 1)-#else- in x6 `xor` (x6 `shiftRL` 1)-#endif-{-# INLINE highestBitMask #-}---- Right and left logical shifts.-shiftRL, shiftLL :: Word -> Int -> Word-#if __GLASGOW_HASKELL__-{--------------------------------------------------------------------- GHC: use unboxing to get @shiftRL@ inlined.---------------------------------------------------------------------}-shiftRL (W# x) (I# i) = W# (uncheckedShiftRL# x i)-shiftLL (W# x) (I# i) = W# (uncheckedShiftL# x i)-#else-shiftRL x i = shiftR x i-shiftLL x i = shiftL x i-#endif-{-# INLINE shiftRL #-}-{-# INLINE shiftLL #-}
Data/Graph.hs view
@@ -244,7 +244,7 @@ EQ -> Just mid GT -> findVertex (mid+1) b where- mid = (a + b) `div` 2+ mid = a + (b - a) `div` 2 ------------------------------------------------------------------------- -- -
Data/IntMap.hs view
@@ -1,6 +1,6 @@ {-# LANGUAGE CPP #-} #if !defined(TESTING) && __GLASGOW_HASKELL__ >= 703-{-# LANGUAGE Trustworthy #-}+{-# LANGUAGE Safe #-} #endif ----------------------------------------------------------------------------- -- |
Data/IntMap/Base.hs view
@@ -5,6 +5,17 @@ #if !defined(TESTING) && __GLASGOW_HASKELL__ >= 703 {-# LANGUAGE Trustworthy #-} #endif+{-# LANGUAGE ScopedTypeVariables #-}+#if __GLASGOW_HASKELL__ >= 708+{-# LANGUAGE TypeFamilies #-}+#endif+-- We use cabal-generated MIN_VERSION_base to adapt to changes of base.+-- Nevertheless, as a convenience, we also allow compiling without cabal by+-- defining trivial MIN_VERSION_base if needed.+#ifndef MIN_VERSION_base+#define MIN_VERSION_base(major1,major2,minor) 0+#endif+ ----------------------------------------------------------------------------- -- | -- Module : Data.IntMap.Base@@ -207,7 +218,6 @@ , shorter , branchMask , highestBitMask- , foldlStrict ) where import Control.Applicative (Applicative(pure, (<*>)), (<$>))@@ -222,17 +232,24 @@ import Data.Word (Word) import Prelude hiding (lookup, map, filter, foldr, foldl, null) -import Data.BitUtil import Data.IntSet.Base (Key) import qualified Data.IntSet.Base as IntSet-import Data.StrictPair+import Data.Utils.BitUtil+import Data.Utils.StrictFold+import Data.Utils.StrictPair #if __GLASGOW_HASKELL__ import Data.Data (Data(..), Constr, mkConstr, constrIndex, Fixity(Prefix), DataType, mkDataType) import GHC.Exts (build)+#if __GLASGOW_HASKELL__ >= 708+import qualified GHC.Exts as GHCExts+#endif import Text.Read #endif+#if __GLASGOW_HASKELL__ >= 709+import Data.Coerce+#endif -- Use macros to define strictness of functions. -- STRICT_x_OF_y denotes an y-ary function strict in the x-th parameter.@@ -240,6 +257,7 @@ -- want the compilers to be compiled by as many compilers as possible. #define STRICT_1_OF_2(fn) fn arg _ | arg `seq` False = undefined + -- A "Nat" is a natural machine word (an unsigned Int) type Nat = Word @@ -298,7 +316,7 @@ mconcat = unions instance Foldable.Foldable IntMap where- fold t = go t+ fold = go where go Nil = mempty go (Tip _ v) = v go (Bin _ _ l r) = go l `mappend` go r@@ -313,6 +331,51 @@ go (Bin _ _ l r) = go l `mappend` go r {-# INLINE foldMap #-} +#if MIN_VERSION_base(4,6,0)+ foldl' = foldl'+ {-# INLINE foldl' #-}+ foldr' = foldr'+ {-# INLINE foldr' #-}+#endif+#if MIN_VERSION_base(4,8,0)+ length = size+ {-# INLINE length #-}+ null = null+ {-# INLINE null #-}+ toList = elems -- NB: Foldable.toList /= IntMap.toList+ {-# INLINE toList #-}+ elem = go+ where STRICT_1_OF_2(go)+ go _ Nil = False+ go x (Tip _ y) = x == y+ go x (Bin _ _ l r) = go x l || go x r+ {-# INLINABLE elem #-}+ maximum = start+ where start Nil = error "IntMap.Foldable.maximum: called with empty map"+ start (Tip _ y) = y+ start (Bin _ _ l r) = go (start l) r++ STRICT_1_OF_2(go)+ go m Nil = m+ go m (Tip _ y) = max m y+ go m (Bin _ _ l r) = go (go m l) r+ {-# INLINABLE maximum #-}+ minimum = start+ where start Nil = error "IntMap.Foldable.minimum: called with empty map"+ start (Tip _ y) = y+ start (Bin _ _ l r) = go (start l) r++ STRICT_1_OF_2(go)+ go m Nil = m+ go m (Tip _ y) = min m y+ go m (Bin _ _ l r) = go (go m l) r+ {-# INLINABLE minimum #-}+ sum = foldl' (+) 0+ {-# INLINABLE sum #-}+ product = foldl' (*) 1+ {-# INLINABLE product #-}+#endif+ instance Traversable IntMap where traverse f = traverseWithKey (\_ -> f) {-# INLINE traverse #-}@@ -1241,6 +1304,19 @@ Tip k x -> Tip k (f x) Nil -> Nil +#ifdef __GLASGOW_HASKELL__+{-# NOINLINE [1] map #-}+{-# RULES+"map/map" forall f g xs . map f (map g xs) = map (f . g) xs+ #-}+#endif+#if __GLASGOW_HASKELL__ >= 709+-- Safe coercions were introduced in 7.8, but did not play well with RULES yet.+{-# RULES+"map/coerce" map coerce = coerce+ #-}+#endif+ -- | /O(n)/. Map a function over all values in the map. -- -- > let f key x = (show key) ++ ":" ++ x@@ -1253,6 +1329,18 @@ Tip k x -> Tip k (f k x) Nil -> Nil +#ifdef __GLASGOW_HASKELL__+{-# NOINLINE [1] mapWithKey #-}+{-# RULES+"mapWithKey/mapWithKey" forall f g xs . mapWithKey f (mapWithKey g xs) =+ mapWithKey (\k a -> f k (g k a)) xs+"mapWithKey/map" forall f g xs . mapWithKey f (map g xs) =+ mapWithKey (\k a -> f k (g a)) xs+"map/mapWithKey" forall f g xs . map f (mapWithKey g xs) =+ mapWithKey (\k a -> f (g k a)) xs+ #-}+#endif+ -- | /O(n)/. -- @'traverseWithKey' f s == 'fromList' <$> 'traverse' (\(k, v) -> (,) k <$> f k v) ('toList' m)@ -- That is, behaves exactly like a regular 'traverse' except that the traversing@@ -1770,6 +1858,13 @@ {-------------------------------------------------------------------- Lists --------------------------------------------------------------------}+#if __GLASGOW_HASKELL__ >= 708+instance GHCExts.IsList (IntMap a) where+ type Item (IntMap a) = (Key,a)+ fromList = fromList+ toList = toList+#endif+ -- | /O(n)/. Convert the map to a list of key\/value pairs. Subject to list -- fusion. --@@ -1907,7 +2002,7 @@ -- -- > fromDistinctAscList [(3,"b"), (5,"a")] == fromList [(3, "b"), (5, "a")] -fromDistinctAscList :: [(Key,a)] -> IntMap a+fromDistinctAscList :: forall a. [(Key,a)] -> IntMap a fromDistinctAscList [] = Nil fromDistinctAscList (z0 : zs0) = work z0 zs0 Nada where@@ -2070,13 +2165,6 @@ {-------------------------------------------------------------------- Utilities --------------------------------------------------------------------}--foldlStrict :: (a -> b -> a) -> a -> [b] -> a-foldlStrict f = go- where- go z [] = z- go z (x:xs) = let z' = f z x in z' `seq` go z' xs-{-# INLINE foldlStrict #-} -- | /O(1)/. Decompose a map into pieces based on the structure of the underlying -- tree. This function is useful for consuming a map in parallel.
Data/IntMap/Lazy.hs view
@@ -1,6 +1,6 @@ {-# LANGUAGE CPP #-} #if !defined(TESTING) && __GLASGOW_HASKELL__ >= 703-{-# LANGUAGE Trustworthy #-}+{-# LANGUAGE Safe #-} #endif ----------------------------------------------------------------------------- -- |
Data/IntMap/Strict.hs view
@@ -256,9 +256,13 @@ , fromDistinctAscList ) -import Data.BitUtil import qualified Data.IntSet.Base as IntSet-import Data.StrictPair+import Data.Utils.BitUtil+import Data.Utils.StrictFold+import Data.Utils.StrictPair+#if __GLASGOW_HASKELL__ >= 709+import Data.Coerce+#endif -- $strictness --@@ -715,6 +719,18 @@ Tip k x -> Tip k $! f x Nil -> Nil +#ifdef __GLASGOW_HASKELL__+{-# NOINLINE [1] map #-}+{-# RULES+"map/map" forall f g xs . map f (map g xs) = map (f . g) xs+ #-}+#endif+#if __GLASGOW_HASKELL__ >= 709+{-# RULES+"map/coerce" map coerce = coerce+ #-}+#endif+ -- | /O(n)/. Map a function over all values in the map. -- -- > let f key x = (show key) ++ ":" ++ x@@ -726,6 +742,18 @@ Bin p m l r -> Bin p m (mapWithKey f l) (mapWithKey f r) Tip k x -> Tip k $! f k x Nil -> Nil++#ifdef __GLASGOW_HASKELL__+{-# NOINLINE [1] mapWithKey #-}+{-# RULES+"mapWithKey/mapWithKey" forall f g xs . mapWithKey f (mapWithKey g xs) =+ mapWithKey (\k a -> f k (g k a)) xs+"mapWithKey/map" forall f g xs . mapWithKey f (map g xs) =+ mapWithKey (\k a -> f k (g a)) xs+"map/mapWithKey" forall f g xs . map f (mapWithKey g xs) =+ mapWithKey (\k a -> f (g k a)) xs+ #-}+#endif -- | /O(n)/. The function @'mapAccum'@ threads an accumulating -- argument through the map in ascending order of keys.
Data/IntSet/Base.hs view
@@ -5,6 +5,9 @@ #if !defined(TESTING) && __GLASGOW_HASKELL__ >= 703 {-# LANGUAGE Trustworthy #-} #endif+#if __GLASGOW_HASKELL__ >= 708+{-# LANGUAGE TypeFamilies #-}+#endif ----------------------------------------------------------------------------- -- | -- Module : Data.IntSet.Base@@ -159,27 +162,7 @@ , bitmapOf ) where --- We want to be able to compile without cabal. Nevertheless--- #if defined(MIN_VERSION_base) && MIN_VERSION_base(4,5,0)--- does not work, because if MIN_VERSION_base is undefined,--- the last condition is syntactically wrong.-#define MIN_VERSION_base_4_5_0 0-#ifdef MIN_VERSION_base-#if MIN_VERSION_base(4,5,0)-#undef MIN_VERSION_base_4_5_0-#define MIN_VERSION_base_4_5_0 1-#endif-#endif--#define MIN_VERSION_base_4_7_0 0-#ifdef MIN_VERSION_base-#if MIN_VERSION_base(4,7,0)-#undef MIN_VERSION_base_4_7_0-#define MIN_VERSION_base_4_7_0 1-#endif-#endif--import Control.DeepSeq (NFData)+import Control.DeepSeq (NFData(rnf)) import Data.Bits import qualified Data.List as List import Data.Maybe (fromMaybe)@@ -188,8 +171,9 @@ import Data.Word (Word) import Prelude hiding (filter, foldr, foldl, null, map) -import Data.BitUtil-import Data.StrictPair+import Data.Utils.BitUtil+import Data.Utils.StrictFold+import Data.Utils.StrictPair #if __GLASGOW_HASKELL__ import Data.Data (Data(..), Constr, mkConstr, constrIndex, Fixity(Prefix), DataType, mkDataType)@@ -198,6 +182,9 @@ #if __GLASGOW_HASKELL__ import GHC.Exts (Int(..), build)+#if __GLASGOW_HASKELL__ >= 708+import qualified GHC.Exts as GHCExts+#endif import GHC.Prim (indexInt8OffAddr#) #endif @@ -215,6 +202,14 @@ #define STRICT_1_OF_3(fn) fn arg _ _ | arg `seq` False = undefined #define STRICT_2_OF_3(fn) fn _ arg _ | arg `seq` False = undefined +-- We use cabal-generated MIN_VERSION_base to adapt to changes of base.+-- Nevertheless, as a convenience, we also allow compiling without cabal by+-- defining trivial MIN_VERSION_base if needed.+#ifndef MIN_VERSION_base+#define MIN_VERSION_base(major1,major2,minor) 0+#endif++ infixl 9 \\{-This comment teaches CPP correct behaviour -} -- A "Nat" is a natural machine word (an unsigned Int)@@ -936,6 +931,13 @@ {-------------------------------------------------------------------- Lists --------------------------------------------------------------------}+#if __GLASGOW_HASKELL__ >= 708+instance GHCExts.IsList IntSet where+ type Item IntSet = Key+ fromList = fromList+ toList = toList+#endif+ -- | /O(n)/. Convert the set to a list of elements. Subject to list fusion. toList :: IntSet -> [Key] toList@@ -1097,7 +1099,7 @@ -- The IntSet constructors consist only of strict fields of Ints and -- IntSets, thus the default NFData instance which evaluates to whnf -- should suffice-instance NFData IntSet+instance NFData IntSet where rnf x = seq x () {-------------------------------------------------------------------- Debugging@@ -1214,7 +1216,7 @@ ----------------------------------------------------------------------} suffixBitMask :: Int-#if MIN_VERSION_base_4_7_0+#if MIN_VERSION_base(4,7,0) suffixBitMask = finiteBitSize (undefined::Word) - 1 #else suffixBitMask = bitSize (undefined::Word) - 1@@ -1465,7 +1467,7 @@ ----------------------------------------------------------------------} bitcount :: Int -> Word -> Int-#if MIN_VERSION_base_4_5_0+#if MIN_VERSION_base(4,5,0) bitcount a x = a + popCount x #else bitcount a0 x0 = go a0 x0@@ -1478,12 +1480,6 @@ {-------------------------------------------------------------------- Utilities --------------------------------------------------------------------}-foldlStrict :: (a -> b -> a) -> a -> [b] -> a-foldlStrict f = go- where- go z [] = z- go z (x:xs) = let z' = f z x in z' `seq` go z' xs-{-# INLINE foldlStrict #-} -- | /O(1)/. Decompose a set into pieces based on the structure of the underlying -- tree. This function is useful for consuming a set in parallel.
Data/Map/Base.hs view
@@ -5,6 +5,16 @@ #if !defined(TESTING) && __GLASGOW_HASKELL__ >= 703 {-# LANGUAGE Trustworthy #-} #endif+#if __GLASGOW_HASKELL__ >= 708+{-# LANGUAGE RoleAnnotations #-}+{-# LANGUAGE TypeFamilies #-}+#endif+-- We use cabal-generated MIN_VERSION_base to adapt to changes of base.+-- Nevertheless, as a convenience, we also allow compiling without cabal by+-- defining trivial MIN_VERSION_base if needed.+#ifndef MIN_VERSION_base+#define MIN_VERSION_base(major1,major2,minor) 0+#endif ----------------------------------------------------------------------------- -- | -- Module : Data.Map.Base@@ -258,7 +268,6 @@ , glue , trim , trimLookupLo- , foldlStrict , MaybeS(..) , filterGt , filterLt@@ -269,18 +278,25 @@ import Data.Bits (shiftL, shiftR) import qualified Data.Foldable as Foldable import Data.Monoid (Monoid(..))-import Data.StrictPair import Data.Traversable (Traversable(traverse)) import Data.Typeable import Prelude hiding (lookup, map, filter, foldr, foldl, null) import qualified Data.Set.Base as Set+import Data.Utils.StrictFold+import Data.Utils.StrictPair #if __GLASGOW_HASKELL__ import GHC.Exts ( build )+#if __GLASGOW_HASKELL__ >= 708+import qualified GHC.Exts as GHCExts+#endif import Text.Read import Data.Data #endif+#if __GLASGOW_HASKELL__ >= 709+import Data.Coerce+#endif -- Use macros to define strictness of functions. -- STRICT_x_OF_y denotes an y-ary function strict in the x-th parameter.@@ -292,6 +308,7 @@ #define STRICT_1_OF_4(fn) fn arg _ _ _ | arg `seq` False = undefined #define STRICT_2_OF_4(fn) fn _ arg _ _ | arg `seq` False = undefined + {-------------------------------------------------------------------- Operators --------------------------------------------------------------------}@@ -1164,6 +1181,7 @@ -- | /O(log n)/. Retrieves the value associated with maximal key of the -- map, and the map stripped of that element, or 'Nothing' if passed an+-- empty map. -- -- > maxView (fromList [(5,"a"), (3,"b")]) == Just ("a", singleton 3 "b") -- > maxView empty == Nothing@@ -1644,6 +1662,18 @@ map :: (a -> b) -> Map k a -> Map k b map _ Tip = Tip map f (Bin sx kx x l r) = Bin sx kx (f x) (map f l) (map f r)+#ifdef __GLASGOW_HASKELL__+{-# NOINLINE [1] map #-}+{-# RULES+"map/map" forall f g xs . map f (map g xs) = map (f . g) xs+ #-}+#endif+#if __GLASGOW_HASKELL__ >= 709+-- Safe coercions were introduced in 7.8, but did not work well with RULES yet.+{-# RULES+"map/coerce" map coerce = coerce+ #-}+#endif -- | /O(n)/. Map a function over all values in the map. --@@ -1654,6 +1684,18 @@ mapWithKey _ Tip = Tip mapWithKey f (Bin sx kx x l r) = Bin sx kx (f kx x) (mapWithKey f l) (mapWithKey f r) +#ifdef __GLASGOW_HASKELL__+{-# NOINLINE [1] mapWithKey #-}+{-# RULES+"mapWithKey/mapWithKey" forall f g xs . mapWithKey f (mapWithKey g xs) =+ mapWithKey (\k a -> f k (g k a)) xs+"mapWithKey/map" forall f g xs . mapWithKey f (map g xs) =+ mapWithKey (\k a -> f k (g a)) xs+"map/mapWithKey" forall f g xs . map f (mapWithKey g xs) =+ mapWithKey (\k a -> f (g k a)) xs+ #-}+#endif+ -- | /O(n)/. -- @'traverseWithKey' f s == 'fromList' <$> 'traverse' (\(k, v) -> (,) k <$> f k v) ('toList' m)@ -- That is, behaves exactly like a regular 'traverse' except that the traversing@@ -1948,6 +1990,13 @@ Lists use [foldlStrict] to reduce demand on the control-stack --------------------------------------------------------------------}+#if __GLASGOW_HASKELL__ >= 708+instance (Ord k) => GHCExts.IsList (Map k v) where+ type Item (Map k v) = (k,v)+ fromList = fromList+ toList = toList+#endif+ -- | /O(n*log n)/. Build a map from a list of key\/value pairs. See also 'fromAscList'. -- If the list contains more than one value for the same key, the last value -- for the key is retained.@@ -2624,7 +2673,7 @@ {-# INLINE traverse #-} instance Foldable.Foldable (Map k) where- fold t = go t+ fold = go where go Tip = mempty go (Bin 1 _ v _ _) = v go (Bin _ _ v l r) = go l `mappend` (v `mappend` go r)@@ -2639,6 +2688,46 @@ go (Bin _ _ v l r) = go l `mappend` (f v `mappend` go r) {-# INLINE foldMap #-} +#if MIN_VERSION_base(4,6,0)+ foldl' = foldl'+ {-# INLINE foldl' #-}+ foldr' = foldr'+ {-# INLINE foldr' #-}+#endif+#if MIN_VERSION_base(4,8,0)+ length = size+ {-# INLINE length #-}+ null = null+ {-# INLINE null #-}+ toList = elems -- NB: Foldable.toList /= Map.toList+ {-# INLINE toList #-}+ elem = go+ where STRICT_1_OF_2(go)+ go _ Tip = False+ go x (Bin _ _ v l r) = x == v || go x l || go x r+ {-# INLINABLE elem #-}+ maximum = start+ where start Tip = error "Map.Foldable.maximum: called with empty map"+ start (Bin _ _ v l r) = go (go v l) r++ STRICT_1_OF_2(go)+ go m Tip = m+ go m (Bin _ _ v l r) = go (go (max m v) l) r+ {-# INLINABLE maximum #-}+ minimum = start+ where start Tip = error "Map.Foldable.minumum: called with empty map"+ start (Bin _ _ v l r) = go (go v l) r++ STRICT_1_OF_2(go)+ go m Tip = m+ go m (Bin _ _ v l r) = go (go (min m v) l) r+ {-# INLINABLE minimum #-}+ sum = foldl' (+) 0+ {-# INLINABLE sum #-}+ product = foldl' (*) 1+ {-# INLINABLE product #-}+#endif+ instance (NFData k, NFData a) => NFData (Map k a) where rnf Tip = () rnf (Bin _ kx x l r) = rnf kx `seq` rnf x `seq` rnf l `seq` rnf r@@ -2812,13 +2901,6 @@ {-------------------------------------------------------------------- Utilities --------------------------------------------------------------------}-foldlStrict :: (a -> b -> a) -> a -> [b] -> a-foldlStrict f = go- where- go z [] = z- go z (x:xs) = let z' = f z x in z' `seq` go z' xs-{-# INLINE foldlStrict #-}- -- | /O(1)/. Decompose a map into pieces based on the structure of the underlying -- tree. This function is useful for consuming a map in parallel.
Data/Map/Strict.hs view
@@ -1,7 +1,13 @@ {-# LANGUAGE CPP #-} #if !defined(TESTING) && __GLASGOW_HASKELL__ >= 703-{-# LANGUAGE Safe #-}+{-# LANGUAGE Trustworthy #-} #endif+-- We use cabal-generated MIN_VERSION_base to adapt to changes of base.+-- Nevertheless, as a convenience, we also allow compiling without cabal by+-- defining trivial MIN_VERSION_base if needed.+#ifndef MIN_VERSION_base+#define MIN_VERSION_base(major1,major2,minor) 0+#endif ----------------------------------------------------------------------------- -- | -- Module : Data.Map.Strict@@ -269,8 +275,13 @@ , updateMaxWithKey ) import qualified Data.Set.Base as Set-import Data.StrictPair+import Data.Utils.StrictFold+import Data.Utils.StrictPair+ import Data.Bits (shiftL, shiftR)+#if __GLASGOW_HASKELL__ >= 709+import Data.Coerce+#endif -- Use macros to define strictness of functions. STRICT_x_OF_y -- denotes an y-ary function strict in the x-th parameter. Similarly@@ -924,6 +935,18 @@ map :: (a -> b) -> Map k a -> Map k b map _ Tip = Tip map f (Bin sx kx x l r) = let x' = f x in x' `seq` Bin sx kx x' (map f l) (map f r)+#ifdef __GLASGOW_HASKELL__+{-# NOINLINE [1] map #-}+{-# RULES+"map/map" forall f g xs . map f (map g xs) = map (f . g) xs+ #-}+#endif+#if __GLASGOW_HASKELL__ >= 709+-- Safe coercions were introduced in 7.8, but did not work well with RULES yet.+{-# RULES+"mapSeq/coerce" map coerce = coerce+ #-}+#endif -- | /O(n)/. Map a function over all values in the map. --@@ -932,8 +955,21 @@ mapWithKey :: (k -> a -> b) -> Map k a -> Map k b mapWithKey _ Tip = Tip-mapWithKey f (Bin sx kx x l r) = let x' = f kx x- in x' `seq` Bin sx kx x' (mapWithKey f l) (mapWithKey f r)+mapWithKey f (Bin sx kx x l r) =+ let x' = f kx x+ in x' `seq` Bin sx kx x' (mapWithKey f l) (mapWithKey f r)++#ifdef __GLASGOW_HASKELL__+{-# NOINLINE [1] mapWithKey #-}+{-# RULES+"mapWithKey/mapWithKey" forall f g xs . mapWithKey f (mapWithKey g xs) =+ mapWithKey (\k a -> f k (g k a)) xs+"mapWithKey/map" forall f g xs . mapWithKey f (map g xs) =+ mapWithKey (\k a -> f k (g a)) xs+"map/mapWithKey" forall f g xs . map f (mapWithKey g xs) =+ mapWithKey (\k a -> f (g k a)) xs+ #-}+#endif -- | /O(n)/. The function 'mapAccum' threads an accumulating -- argument through the map in ascending order of keys.
Data/Sequence.hs view
@@ -5,11 +5,21 @@ #if __GLASGOW_HASKELL__ >= 703 {-# LANGUAGE Trustworthy #-} #endif+#if __GLASGOW_HASKELL__ >= 708+{-# LANGUAGE TypeFamilies #-}+#endif+-- We use cabal-generated MIN_VERSION_base to adapt to changes of base.+-- Nevertheless, as a convenience, we also allow compiling without cabal by+-- defining trivial MIN_VERSION_base if needed.+#ifndef MIN_VERSION_base+#define MIN_VERSION_base(major1,major2,minor) 0+#endif ----------------------------------------------------------------------------- -- | -- Module : Data.Sequence -- Copyright : (c) Ross Paterson 2005 -- (c) Louis Wasserman 2009+-- (c) David Feuer and Milan Straka 2014 -- License : BSD-style -- Maintainer : libraries@haskell.org -- Stability : experimental@@ -30,7 +40,7 @@ -- * Ralf Hinze and Ross Paterson, -- \"Finger trees: a simple general-purpose data structure\", -- /Journal of Functional Programming/ 16:2 (2006) pp 197-217.--- <http://www.soi.city.ac.uk/~ross/papers/FingerTree.html>+-- <http://staff.city.ac.uk/~ross/papers/FingerTree.html> -- -- /Note/: Many of these operations have the same names as similar -- operations on lists in the "Prelude". The ambiguity may be resolved@@ -51,6 +61,8 @@ (|>), -- :: Seq a -> a -> Seq a (><), -- :: Seq a -> Seq a -> Seq a fromList, -- :: [a] -> Seq a+ fromFunction, -- :: Int -> (Int -> a) -> Seq a+ fromArray, -- :: Ix i => Array i a -> Seq a -- ** Repetition replicate, -- :: Int -> a -> Seq a replicateA, -- :: Applicative f => Int -> f a -> f (Seq a)@@ -149,10 +161,19 @@ import Control.Monad (MonadPlus(..), ap) import Data.Monoid (Monoid(..)) import Data.Functor (Functor(..))-import Data.Foldable+#if MIN_VERSION_base(4,8,0)+import Data.Foldable (Foldable(foldl, foldl1, foldr, foldr1, foldMap, foldl', foldr', toList))+#else+#if MIN_VERSION_base(4,6,0)+import Data.Foldable (Foldable(foldl, foldl1, foldr, foldr1, foldMap, foldl'), toList)+#else+import Data.Foldable (Foldable(foldl, foldl1, foldr, foldr1, foldMap), foldl', toList)+#endif+#endif import Data.Traversable import Data.Typeable +-- GHC specific stuff #ifdef __GLASGOW_HASKELL__ import GHC.Exts (build) import Text.Read (Lexeme(Ident), lexP, parens, prec,@@ -160,6 +181,25 @@ import Data.Data #endif +-- Array stuff, with GHC.Arr on GHC+import Data.Array (Ix, Array)+import qualified Data.Array+#ifdef __GLASGOW_HASKELL__+import qualified GHC.Arr+#endif++-- Coercion on GHC 7.8++#if __GLASGOW_HASKELL__ >= 708+import Data.Coerce+import qualified GHC.Exts+#else+#endif++-- Identity functor on base 4.8 (GHC 7.10+)+#if MIN_VERSION_base(4,8,0)+import Data.Functor.Identity (Identity(..))+#endif+ infixr 5 `consTree` infixl 5 `snocTree` @@ -174,12 +214,28 @@ newtype Seq a = Seq (FingerTree (Elem a)) instance Functor Seq where- fmap f (Seq xs) = Seq (fmap (fmap f) xs)+ fmap = fmapSeq #ifdef __GLASGOW_HASKELL__ x <$ s = replicate (length s) x #endif +fmapSeq :: (a -> b) -> Seq a -> Seq b+fmapSeq f (Seq xs) = Seq (fmap (fmap f) xs)+#ifdef __GLASGOW_HASKELL__+{-# NOINLINE [1] fmapSeq #-}+{-# RULES+"fmapSeq/fmapSeq" forall f g xs . fmapSeq f (fmapSeq g xs) = fmapSeq (f . g) xs+ #-}+#endif+#if __GLASGOW_HASKELL__ >= 709+-- Safe coercions were introduced in 7.8, but did not work well with RULES yet.+{-# RULES+"fmapSeq/coerce" fmapSeq coerce = coerce+ #-}+#endif+ instance Foldable Seq where+ foldMap f (Seq xs) = foldMap (foldMap f) xs foldr f z (Seq xs) = foldr (flip (foldr f)) z xs foldl f z (Seq xs) = foldl (foldl f) z xs @@ -189,6 +245,15 @@ foldl1 f (Seq xs) = getElem (foldl1 f' xs) where f' (Elem x) (Elem y) = Elem (f x y) +#if MIN_VERSION_base(4,8,0)+ length = length+ {-# INLINE length #-}+ null = null+ {-# INLINE null #-}+ toList = toList+ {-# INLINE toList #-}+#endif+ instance Traversable Seq where traverse f (Seq xs) = Seq <$> traverse (traverse f) xs @@ -199,11 +264,13 @@ return = singleton xs >>= f = foldl' add empty xs where add ys x = ys >< f x+ (>>) = (*>) instance Applicative Seq where pure = singleton fs <*> xs = foldl' add empty fs where add ys f = ys >< fmap f xs+ xs *> ys = replicateSeq (length xs) ys instance MonadPlus Seq where mzero = empty@@ -295,6 +362,11 @@ size (Deep v _ _ _) = v instance Foldable FingerTree where+ foldMap _ Empty = mempty+ foldMap f (Single x) = f x+ foldMap f (Deep _ pr m sf) =+ foldMap f pr `mappend` (foldMap (foldMap f) m `mappend` foldMap f sf)+ foldr _ z Empty = z foldr f z (Single x) = x `f` z foldr f z (Deep _ pr m sf) =@@ -331,7 +403,7 @@ instance NFData a => NFData (FingerTree a) where rnf (Empty) = () rnf (Single x) = rnf x- rnf (Deep _ pr m sf) = rnf pr `seq` rnf m `seq` rnf sf+ rnf (Deep _ pr m sf) = rnf pr `seq` rnf sf `seq` rnf m {-# INLINE deep #-} deep :: Sized a => Digit a -> FingerTree (Node a) -> Digit a -> FingerTree a@@ -373,6 +445,11 @@ #endif instance Foldable Digit where+ foldMap f (One a) = f a+ foldMap f (Two a b) = f a `mappend` f b+ foldMap f (Three a b c) = f a `mappend` (f b `mappend` f c)+ foldMap f (Four a b c d) = f a `mappend` (f b `mappend` (f c `mappend` f d))+ foldr f z (One a) = a `f` z foldr f z (Two a b) = a `f` (b `f` z) foldr f z (Three a b c) = a `f` (b `f` (c `f` z))@@ -443,6 +520,9 @@ #endif instance Foldable Node where+ foldMap f (Node2 _ a b) = f a `mappend` f b+ foldMap f (Node3 _ a b c) = f a `mappend` (f b `mappend` f c)+ foldr f z (Node2 _ a b) = a `f` (b `f` z) foldr f z (Node3 _ a b c) = a `f` (b `f` (c `f` z)) @@ -493,6 +573,7 @@ fmap f (Elem x) = Elem (f x) instance Foldable Elem where+ foldMap f (Elem x) = f x foldr f z (Elem x) = f x z foldl f z (Elem x) = f z x @@ -505,19 +586,16 @@ ------------------------------------------------------- -- Applicative construction ---------------------------------------------------------newtype Id a = Id {runId :: a}--instance Functor Id where- fmap f (Id x) = Id (f x)+#if !MIN_VERSION_base(4,8,0)+newtype Identity a = Identity {runIdentity :: a} -instance Monad Id where- return = Id- m >>= k = k (runId m)+instance Functor Identity where+ fmap f (Identity x) = Identity (f x) -instance Applicative Id where- pure = return- (<*>) = ap+instance Applicative Identity where+ pure = Identity+ Identity f <*> Identity x = Identity (f x)+#endif -- | This is essentially a clone of Control.Monad.State.Strict. newtype State s a = State {runState :: s -> (s, a)}@@ -539,23 +617,19 @@ execState :: State s a -> s -> a execState m x = snd (runState m x) --- | A helper method: a strict version of mapAccumL.-mapAccumL' :: Traversable t => (a -> b -> (a, c)) -> a -> t b -> (a, t c)-mapAccumL' f s t = runState (traverse (State . flip f) t) s- -- | 'applicativeTree' takes an Applicative-wrapped construction of a -- piece of a FingerTree, assumed to always have the same size (which -- is put in the second argument), and replicates it as many times as -- specified. This is a generalization of 'replicateA', which itself -- is a generalization of many Data.Sequence methods. {-# SPECIALIZE applicativeTree :: Int -> Int -> State s a -> State s (FingerTree a) #-}-{-# SPECIALIZE applicativeTree :: Int -> Int -> Id a -> Id (FingerTree a) #-}--- Special note: the Id specialization automatically does node sharing,+{-# SPECIALIZE applicativeTree :: Int -> Int -> Identity a -> Identity (FingerTree a) #-}+-- Special note: the Identity specialization automatically does node sharing, -- reducing memory usage of the resulting tree to /O(log n)/. applicativeTree :: Applicative f => Int -> Int -> f a -> f (FingerTree a) applicativeTree n mSize m = mSize `seq` case n of 0 -> pure Empty- 1 -> liftA Single m+ 1 -> fmap Single m 2 -> deepA one emptyTree one 3 -> deepA two emptyTree one 4 -> deepA two emptyTree two@@ -563,12 +637,12 @@ 6 -> deepA three emptyTree three 7 -> deepA four emptyTree three 8 -> deepA four emptyTree four- _ -> let (q, r) = n `quotRem` 3 in q `seq` case r of- 0 -> deepA three (applicativeTree (q - 2) mSize' n3) three- 1 -> deepA four (applicativeTree (q - 2) mSize' n3) three- _ -> deepA four (applicativeTree (q - 2) mSize' n3) four+ _ -> case n `quotRem` 3 of+ (q,0) -> deepA three (applicativeTree (q - 2) mSize' n3) three+ (q,1) -> deepA four (applicativeTree (q - 2) mSize' n3) three+ (q,_) -> deepA four (applicativeTree (q - 2) mSize' n3) four where- one = liftA One m+ one = fmap One m two = liftA2 Two m m three = liftA3 Three m m m four = liftA3 Four m m m <*> m@@ -592,7 +666,7 @@ -- | /O(log n)/. @replicate n x@ is a sequence consisting of @n@ copies of @x@. replicate :: Int -> a -> Seq a replicate n x- | n >= 0 = runId (replicateA n (Id x))+ | n >= 0 = runIdentity (replicateA n (Identity x)) | otherwise = error "replicate takes a nonnegative integer argument" -- | 'replicateA' is an 'Applicative' version of 'replicate', and makes@@ -612,6 +686,19 @@ | n >= 0 = unwrapMonad (replicateA n (WrapMonad x)) | otherwise = error "replicateM takes a nonnegative integer argument" +-- | @'replicateSeq' n xs@ concatenates @n@ copies of @xs@.+replicateSeq :: Int -> Seq a -> Seq a+replicateSeq n s+ | n < 0 = error "replicateSeq takes a nonnegative integer argument"+ | n == 0 = empty+ | otherwise = go n s+ where+ -- Invariant: k >= 1+ go 1 xs = xs+ go k xs | even k = kxs+ | otherwise = xs >< kxs+ where kxs = go (k `quot` 2) $! (xs >< xs)+ -- | /O(1)/. Add an element to the left end of a sequence. -- Mnemonic: a triangle with the single element at the pointy end. (<|) :: a -> Seq a -> Seq a@@ -994,6 +1081,9 @@ fmap f (xs :> x) = fmap f xs :> f x instance Foldable ViewR where+ foldMap _ EmptyR = mempty+ foldMap f (xs :> x) = foldMap f xs `mappend` f x+ foldr _ z EmptyR = z foldr f z (xs :> x) = foldr f (f x z) xs @@ -1002,7 +1092,15 @@ foldr1 _ EmptyR = error "foldr1: empty view" foldr1 f (xs :> x) = foldr f x xs+#if MIN_VERSION_base(4,8,0)+ -- The default definitions are sensible for ViewL, but not so much for+ -- ViewR.+ null EmptyR = True+ null (_ :> _) = False + length = foldr' (\_ k -> k+1) 0+#endif+ instance Traversable ViewR where traverse _ EmptyR = pure EmptyR traverse f (xs :> x) = (:>) <$> traverse f xs <*> f x@@ -1086,14 +1184,14 @@ lookupTree :: Sized a => Int -> FingerTree a -> Place a lookupTree _ Empty = error "lookupTree of empty tree" lookupTree i (Single x) = Place i x-lookupTree i (Deep _ pr m sf)+lookupTree i (Deep totalSize pr m sf) | i < spr = lookupDigit i pr | i < spm = case lookupTree (i - spr) m of Place i' xs -> lookupNode i' xs | otherwise = lookupDigit (i - spm) sf where spr = size pr- spm = spr + size m+ spm = totalSize - size sf {-# SPECIALIZE lookupNode :: Int -> Node (Elem a) -> Place (Elem a) #-} {-# SPECIALIZE lookupNode :: Int -> Node (Node a) -> Place (Node a) #-}@@ -1205,12 +1303,121 @@ sab = sa + size b sabc = sab + size c --- | A generalization of 'fmap', 'mapWithIndex' takes a mapping function--- that also depends on the element's index, and applies it to every+-- | /O(n)/. A generalization of 'fmap', 'mapWithIndex' takes a mapping+-- function that also depends on the element's index, and applies it to every -- element in the sequence. mapWithIndex :: (Int -> a -> b) -> Seq a -> Seq b-mapWithIndex f xs = snd (mapAccumL' (\ i x -> (i + 1, f i x)) 0 xs)+mapWithIndex f' (Seq xs') = Seq $ mapWithIndexTree (\s (Elem a) -> Elem (f' s a)) 0 xs'+ where+ {-# SPECIALIZE mapWithIndexTree :: (Int -> Elem y -> b) -> Int -> FingerTree (Elem y) -> FingerTree b #-}+ {-# SPECIALIZE mapWithIndexTree :: (Int -> Node y -> b) -> Int -> FingerTree (Node y) -> FingerTree b #-}+ mapWithIndexTree :: Sized a => (Int -> a -> b) -> Int -> FingerTree a -> FingerTree b+ mapWithIndexTree _ s Empty = s `seq` Empty+ mapWithIndexTree f s (Single xs) = Single $ f s xs+ mapWithIndexTree f s (Deep n pr m sf) = sPspr `seq` sPsprm `seq`+ Deep n+ (mapWithIndexDigit f s pr)+ (mapWithIndexTree (mapWithIndexNode f) sPspr m)+ (mapWithIndexDigit f sPsprm sf)+ where+ sPspr = s + size pr+ sPsprm = s + n - size sf + {-# SPECIALIZE mapWithIndexDigit :: (Int -> Elem y -> b) -> Int -> Digit (Elem y) -> Digit b #-}+ {-# SPECIALIZE mapWithIndexDigit :: (Int -> Node y -> b) -> Int -> Digit (Node y) -> Digit b #-}+ mapWithIndexDigit :: Sized a => (Int -> a -> b) -> Int -> Digit a -> Digit b+ mapWithIndexDigit f s (One a) = One (f s a)+ mapWithIndexDigit f s (Two a b) = sPsa `seq` Two (f s a) (f sPsa b)+ where+ sPsa = s + size a+ mapWithIndexDigit f s (Three a b c) = sPsa `seq` sPsab `seq`+ Three (f s a) (f sPsa b) (f sPsab c)+ where+ sPsa = s + size a+ sPsab = sPsa + size b+ mapWithIndexDigit f s (Four a b c d) = sPsa `seq` sPsab `seq` sPsabc `seq`+ Four (f s a) (f sPsa b) (f sPsab c) (f sPsabc d)+ where+ sPsa = s + size a+ sPsab = sPsa + size b+ sPsabc = sPsab + size c++ {-# SPECIALIZE mapWithIndexNode :: (Int -> Elem y -> b) -> Int -> Node (Elem y) -> Node b #-}+ {-# SPECIALIZE mapWithIndexNode :: (Int -> Node y -> b) -> Int -> Node (Node y) -> Node b #-}+ mapWithIndexNode :: Sized a => (Int -> a -> b) -> Int -> Node a -> Node b+ mapWithIndexNode f s (Node2 ns a b) = sPsa `seq` Node2 ns (f s a) (f sPsa b)+ where+ sPsa = s + size a+ mapWithIndexNode f s (Node3 ns a b c) = sPsa `seq` sPsab `seq`+ Node3 ns (f s a) (f sPsa b) (f sPsab c)+ where+ sPsa = s + size a+ sPsab = sPsa + size b++#ifdef __GLASGOW_HASKELL__+{-# NOINLINE [1] mapWithIndex #-}+{-# RULES+"mapWithIndex/mapWithIndex" forall f g xs . mapWithIndex f (mapWithIndex g xs) =+ mapWithIndex (\k a -> f k (g k a)) xs+"mapWithIndex/fmapSeq" forall f g xs . mapWithIndex f (fmapSeq g xs) =+ mapWithIndex (\k a -> f k (g a)) xs+"fmapSeq/mapWithIndex" forall f g xs . fmapSeq f (mapWithIndex g xs) =+ mapWithIndex (\k a -> f (g k a)) xs+ #-}+#endif++-- | /O(n)/. Convert a given sequence length and a function representing that+-- sequence into a sequence.+fromFunction :: Int -> (Int -> a) -> Seq a+fromFunction len f | len < 0 = error "Data.Sequence.fromFunction called with negative len"+ | len == 0 = empty+ | otherwise = Seq $ create (lift_elem f) 1 0 len+ where+ create :: (Int -> a) -> Int -> Int -> Int -> FingerTree a+ create b{-tree_builder-} s{-tree_size-} i{-start_index-} trees = i `seq` s `seq` case trees of+ 1 -> Single $ b i+ 2 -> Deep (2*s) (One (b i)) Empty (One (b (i+s)))+ 3 -> Deep (3*s) (createTwo i) Empty (One (b (i+2*s)))+ 4 -> Deep (4*s) (createTwo i) Empty (createTwo (i+2*s))+ 5 -> Deep (5*s) (createThree i) Empty (createTwo (i+3*s))+ 6 -> Deep (6*s) (createThree i) Empty (createThree (i+3*s))+ _ -> case trees `quotRem` 3 of+ (trees', 1) -> Deep (trees*s) (createTwo i)+ (create mb (3*s) (i+2*s) (trees'-1))+ (createTwo (i+(2+3*(trees'-1))*s))+ (trees', 2) -> Deep (trees*s) (createThree i)+ (create mb (3*s) (i+3*s) (trees'-1))+ (createTwo (i+(3+3*(trees'-1))*s))+ (trees', _) -> Deep (trees*s) (createThree i)+ (create mb (3*s) (i+3*s) (trees'-2))+ (createThree (i+(3+3*(trees'-2))*s))+ where+ createTwo j = Two (b j) (b (j + s))+ {-# INLINE createTwo #-}+ createThree j = Three (b j) (b (j + s)) (b (j + 2*s))+ {-# INLINE createThree #-}+ mb j = Node3 (3*s) (b j) (b (j + s)) (b (j + 2*s))+ {-# INLINE mb #-}++ lift_elem :: (Int -> a) -> (Int -> Elem a)+#if __GLASGOW_HASKELL__ >= 708+ lift_elem g = coerce g+#else+ lift_elem g = Elem . g+#endif+ {-# INLINE lift_elem #-}++-- | /O(n)/. Create a sequence consisting of the elements of an 'Array'.+-- Note that the resulting sequence elements may be evaluated lazily (as on GHC),+-- so you must force the entire structure to be sure that the original array+-- can be garbage-collected.+fromArray :: Ix i => Array i a -> Seq a+#ifdef __GLASGOW_HASKELL__+fromArray a = fromFunction (GHC.Arr.numElements a) (GHC.Arr.unsafeAt a)+#else+fromArray a = fromList2 (Data.Array.rangeSize (Data.Array.bounds a)) (Data.Array.elems a)+#endif+ -- Splitting -- | /O(log(min(i,n-i)))/. The first @i@ elements of a sequence.@@ -1218,14 +1425,14 @@ -- If the sequence contains fewer than @i@ elements, the whole sequence -- is returned. take :: Int -> Seq a -> Seq a-take i = fst . splitAt i+take i = fst . splitAt' i -- | /O(log(min(i,n-i)))/. Elements of a sequence after the first @i@. -- If @i@ is negative, @'drop' i s@ yields the whole sequence. -- If the sequence contains fewer than @i@ elements, the empty sequence -- is returned. drop :: Int -> Seq a -> Seq a-drop i = snd . splitAt i+drop i = snd . splitAt' i -- | /O(log(min(i,n-i)))/. Split a sequence at a given position. -- @'splitAt' i s = ('take' i s, 'drop' i s)@.@@ -1233,13 +1440,18 @@ splitAt i (Seq xs) = (Seq l, Seq r) where (l, r) = split i xs +-- | /O(log(min(i,n-i))) A strict version of 'splitAt'.+splitAt' :: Int -> Seq a -> (Seq a, Seq a)+splitAt' i (Seq xs) = case split i xs of+ (l, r) -> (Seq l, Seq r)+ split :: Int -> FingerTree (Elem a) -> (FingerTree (Elem a), FingerTree (Elem a)) split i Empty = i `seq` (Empty, Empty) split i xs- | size xs > i = (l, consTree x r)+ | size xs > i = case splitTree i xs of+ Split l x r -> (l, consTree x r) | otherwise = (xs, Empty)- where Split l x r = splitTree i xs data Split t a = Split t a t #if TESTING@@ -1564,12 +1776,50 @@ -- Lists ------------------------------------------------------------------------ +-- The implementation below, by Ross Paterson, avoids the rebuilding+-- the previous (|>)-based implementation suffered from.+ -- | /O(n)/. Create a sequence from a finite list of elements. -- There is a function 'toList' in the opposite direction for all -- instances of the 'Foldable' class, including 'Seq'. fromList :: [a] -> Seq a-fromList = Data.List.foldl' (|>) empty+fromList xs = Seq $ mkTree 1 $ map_elem xs+ where+ {-# SPECIALIZE mkTree :: Int -> [Elem a] -> FingerTree (Elem a) #-}+ {-# SPECIALIZE mkTree :: Int -> [Node a] -> FingerTree (Node a) #-}+ mkTree :: (Sized a) => Int -> [a] -> FingerTree a+ mkTree s [] = s `seq` Empty+ mkTree s [x1] = s `seq` Single x1+ mkTree s [x1, x2] = Deep (2*s) (One x1) Empty (One x2)+ mkTree s [x1, x2, x3] = Deep (3*s) (One x1) Empty (Two x2 x3)+ mkTree s (x1:x2:x3:xs) = s `seq` case getNodes (3*s) xs of+ (ns, sf) -> m `seq` deep' (Three x1 x2 x3) m sf+ where m = mkTree (3*s) ns + deep' pr@(Three x1 _ _) m sf = Deep (3*size x1 + size m + size sf) pr m sf++ getNodes :: Int -> [a] -> ([Node a], Digit a)+ getNodes s [x1] = s `seq` ([], One x1)+ getNodes s [x1, x2] = s `seq` ([], Two x1 x2)+ getNodes s [x1, x2, x3] = s `seq` ([], Three x1 x2 x3)+ getNodes s (x1:x2:x3:xs) = s `seq` (Node3 s x1 x2 x3:ns, d)+ where (ns, d) = getNodes s xs++ map_elem :: [a] -> [Elem a]+#if __GLASGOW_HASKELL__ >= 708+ map_elem xs = coerce xs+#else+ map_elem xs = Data.List.map Elem xs+#endif+ {-# INLINE map_elem #-}++#if __GLASGOW_HASKELL__ >= 708+instance GHC.Exts.IsList (Seq a) where+ type Item (Seq a) = a+ fromList = fromList+ toList = toList+#endif+ ------------------------------------------------------------------------ -- Reverse ------------------------------------------------------------------------@@ -1598,6 +1848,136 @@ reverseNode f (Node3 s a b c) = Node3 s (f c) (f b) (f a) ------------------------------------------------------------------------+-- Mapping with a splittable value+------------------------------------------------------------------------++-- For zipping, and probably also for (<*>), it is useful to build a result by+-- traversing a sequence while splitting up something else. For zipping, we+-- traverse the first sequence while splitting up the second [and third [and+-- fourth]]. For fs <*> xs, we hope to traverse+--+-- > replicate (length fs * length xs) ()+--+-- while splitting something essentially equivalent to+--+-- > fmap (\f -> fmap f xs) fs+--+-- What makes all this crazy code a good idea:+--+-- Suppose we zip together two sequences of the same length:+--+-- zs = zip xs ys+--+-- We want to get reasonably fast indexing into zs immediately, rather than+-- needing to construct the entire thing first, as the previous implementation+-- required. The first aspect is that we build the result "outside-in" or+-- "top-down", rather than left to right. That gives us access to both ends+-- quickly. But that's not enough, by itself, to give immediate access to the+-- center of zs. For that, we need to be able to skip over larger segments of+-- zs, delaying their construction until we actually need them. The way we do+-- this is to traverse xs, while splitting up ys according to the structure of+-- xs. If we have a Deep _ pr m sf, we split ys into three pieces, and hand off+-- one piece to the prefix, one to the middle, and one to the suffix of the+-- result. The key point is that we don't need to actually do anything further+-- with those pieces until we actually need them; the computations to split+-- them up further and zip them with their matching pieces can be delayed until+-- they're actually needed. We do the same thing for Digits (splitting into+-- between one and four pieces) and Nodes (splitting into two or three). The+-- ultimate result is that we can index, or split at, any location in zs in+-- O(log(min{i,n-i})) time *immediately*, with only a constant-factor slowdown+-- as thunks are forced along the path.+--+-- Benchmark info, and alternatives:+--+-- The old zipping code used mapAccumL to traverse the first sequence while+-- cutting down the second sequence one piece at a time.+--+-- An alternative way to express that basic idea is to convert both sequences+-- to lists, zip the lists, and then convert the result back to a sequence.+-- I'll call this the "listy" implementation.+--+-- I benchmarked two operations: Each started by zipping two sequences+-- constructed with replicate and/or fromList. The first would then immediately+-- index into the result. The second would apply deepseq to force the entire+-- result. The new implementation worked much better than either of the others+-- on the immediate indexing test, as expected. It also worked better than the+-- old implementation for all the deepseq tests. For short sequences, the listy+-- implementation outperformed all the others on the deepseq test. However, the+-- splitting implementation caught up and surpassed it once the sequences grew+-- long enough. It seems likely that by avoiding rebuilding, it interacts+-- better with the cache hierarchy.+--+-- David Feuer, with excellent guidance from Carter Schonwald, December 2014++-- | /O(n)/. Constructs a new sequence with the same structure as an existing+-- sequence using a user-supplied mapping function along with a splittable+-- value and a way to split it. The value is split up lazily according to the+-- structure of the sequence, so one piece of the value is distributed to each+-- element of the sequence. The caller should provide a splitter function that+-- takes a number, @n@, and a splittable value, breaks off a chunk of size @n@+-- from the value, and returns that chunk and the remainder as a pair. The+-- following examples will hopefully make the usage clear:+--+-- > zipWith :: (a -> b -> c) -> Seq a -> Seq b -> Seq c+-- > zipWith f s1 s2 = splitMap splitAt (\b a -> f a (b `index` 0)) s2' s1'+-- > where+-- > minLen = min (length s1) (length s2)+-- > s1' = take minLen s1+-- > s2' = take minLen s2+--+-- > mapWithIndex :: (Int -> a -> b) -> Seq a -> Seq b+-- > mapWithIndex f = splitMap (\n i -> (i, n+i)) f 0+splitMap :: (Int -> s -> (s,s)) -> (s -> a -> b) -> s -> Seq a -> Seq b+splitMap splt' = go+ where+ go f s (Seq xs) = Seq $ splitMapTree splt' (\s' (Elem a) -> Elem (f s' a)) s xs++ {-# SPECIALIZE splitMapTree :: (Int -> s -> (s,s)) -> (s -> Elem y -> b) -> s -> FingerTree (Elem y) -> FingerTree b #-}+ {-# SPECIALIZE splitMapTree :: (Int -> s -> (s,s)) -> (s -> Node y -> b) -> s -> FingerTree (Node y) -> FingerTree b #-}+ splitMapTree :: Sized a => (Int -> s -> (s,s)) -> (s -> a -> b) -> s -> FingerTree a -> FingerTree b+ splitMapTree _ _ _ Empty = Empty+ splitMapTree _ f s (Single xs) = Single $ f s xs+ splitMapTree splt f s (Deep n pr m sf) = Deep n (splitMapDigit splt f prs pr) (splitMapTree splt (splitMapNode splt f) ms m) (splitMapDigit splt f sfs sf)+ where+ (prs, r) = splt (size pr) s+ (ms, sfs) = splt (n - size pr - size sf) r++ {-# SPECIALIZE splitMapDigit :: (Int -> s -> (s,s)) -> (s -> Elem y -> b) -> s -> Digit (Elem y) -> Digit b #-}+ {-# SPECIALIZE splitMapDigit :: (Int -> s -> (s,s)) -> (s -> Node y -> b) -> s -> Digit (Node y) -> Digit b #-}+ splitMapDigit :: Sized a => (Int -> s -> (s,s)) -> (s -> a -> b) -> s -> Digit a -> Digit b+ splitMapDigit _ f s (One a) = One (f s a)+ splitMapDigit splt f s (Two a b) = Two (f first a) (f second b)+ where+ (first, second) = splt (size a) s+ splitMapDigit splt f s (Three a b c) = Three (f first a) (f second b) (f third c)+ where+ (first, r) = splt (size a) s+ (second, third) = splt (size b) r+ splitMapDigit splt f s (Four a b c d) = Four (f first a) (f second b) (f third c) (f fourth d)+ where+ (first, s') = splt (size a) s+ (middle, fourth) = splt (size b + size c) s'+ (second, third) = splt (size b) middle++ {-# SPECIALIZE splitMapNode :: (Int -> s -> (s,s)) -> (s -> Elem y -> b) -> s -> Node (Elem y) -> Node b #-}+ {-# SPECIALIZE splitMapNode :: (Int -> s -> (s,s)) -> (s -> Node y -> b) -> s -> Node (Node y) -> Node b #-}+ splitMapNode :: Sized a => (Int -> s -> (s,s)) -> (s -> a -> b) -> s -> Node a -> Node b+ splitMapNode splt f s (Node2 ns a b) = Node2 ns (f first a) (f second b)+ where+ (first, second) = splt (size a) s+ splitMapNode splt f s (Node3 ns a b c) = Node3 ns (f first a) (f second b) (f third c)+ where+ (first, r) = splt (size a) s+ (second, third) = splt (size b) r++{-# INLINE splitMap #-}++getSingleton :: Seq a -> a+getSingleton (Seq (Single (Elem a))) = a+getSingleton (Seq Empty) = error "getSingleton: Empty"+getSingleton _ = error "getSingleton: Not a singleton."++------------------------------------------------------------------------ -- Zipping ------------------------------------------------------------------------ @@ -1612,17 +1992,15 @@ -- For example, @zipWith (+)@ is applied to two sequences to take the -- sequence of corresponding sums. zipWith :: (a -> b -> c) -> Seq a -> Seq b -> Seq c-zipWith f xs ys- | length xs <= length ys = zipWith' f xs ys- | otherwise = zipWith' (flip f) ys xs+zipWith f s1 s2 = zipWith' f s1' s2'+ where+ minLen = min (length s1) (length s2)+ s1' = take minLen s1+ s2' = take minLen s2 --- like 'zipWith', but assumes length xs <= length ys+-- | A version of zipWith that assumes the sequences have the same length. zipWith' :: (a -> b -> c) -> Seq a -> Seq b -> Seq c-zipWith' f xs ys = snd (mapAccumL k ys xs)- where- k kys x = case viewl kys of- (z :< zs) -> (zs, f x z)- EmptyL -> error "zipWith': unexpected EmptyL"+zipWith' f s1 s2 = splitMap splitAt' (\s a -> f a (getSingleton s)) s2 s1 -- | /O(min(n1,n2,n3))/. 'zip3' takes three sequences and returns a -- sequence of triples, analogous to 'zip'.@@ -1633,8 +2011,16 @@ -- three elements, as well as three sequences and returns a sequence of -- their point-wise combinations, analogous to 'zipWith'. zipWith3 :: (a -> b -> c -> d) -> Seq a -> Seq b -> Seq c -> Seq d-zipWith3 f s1 s2 s3 = zipWith ($) (zipWith f s1 s2) s3+zipWith3 f s1 s2 s3 = zipWith' ($) (zipWith' f s1' s2') s3'+ where+ minLen = minimum [length s1, length s2, length s3]+ s1' = take minLen s1+ s2' = take minLen s2+ s3' = take minLen s3 +zipWith3' :: (a -> b -> c -> d) -> Seq a -> Seq b -> Seq c -> Seq d+zipWith3' f s1 s2 s3 = zipWith' ($) (zipWith' f s1 s2) s3+ -- | /O(min(n1,n2,n3,n4))/. 'zip4' takes four sequences and returns a -- sequence of quadruples, analogous to 'zip'. zip4 :: Seq a -> Seq b -> Seq c -> Seq d -> Seq (a,b,c,d)@@ -1644,7 +2030,13 @@ -- four elements, as well as four sequences and returns a sequence of -- their point-wise combinations, analogous to 'zipWith'. zipWith4 :: (a -> b -> c -> d -> e) -> Seq a -> Seq b -> Seq c -> Seq d -> Seq e-zipWith4 f s1 s2 s3 s4 = zipWith ($) (zipWith ($) (zipWith f s1 s2) s3) s4+zipWith4 f s1 s2 s3 s4 = zipWith' ($) (zipWith3' f s1' s2' s3') s4'+ where+ minLen = minimum [length s1, length s2, length s3, length s4]+ s1' = take minLen s1+ s2' = take minLen s2+ s3' = take minLen s3+ s4' = take minLen s4 ------------------------------------------------------------------------ -- Sorting
Data/Set/Base.hs view
@@ -5,6 +5,10 @@ #if !defined(TESTING) && __GLASGOW_HASKELL__ >= 703 {-# LANGUAGE Trustworthy #-} #endif+#if __GLASGOW_HASKELL__ >= 708+{-# LANGUAGE RoleAnnotations #-}+{-# LANGUAGE TypeFamilies #-}+#endif ----------------------------------------------------------------------------- -- | -- Module : Data.Set.Base@@ -190,10 +194,14 @@ import Data.Typeable import Control.DeepSeq (NFData(rnf)) -import Data.StrictPair+import Data.Utils.StrictFold+import Data.Utils.StrictPair #if __GLASGOW_HASKELL__ import GHC.Exts ( build )+#if __GLASGOW_HASKELL__ >= 708+import qualified GHC.Exts as GHCExts+#endif import Text.Read import Data.Data #endif@@ -206,6 +214,14 @@ #define STRICT_1_OF_3(fn) fn arg _ _ | arg `seq` False = undefined #define STRICT_2_OF_3(fn) fn _ arg _ | arg `seq` False = undefined +-- We use cabal-generated MIN_VERSION_base to adapt to changes of base.+-- Nevertheless, as a convenience, we also allow compiling without cabal by+-- defining trivial MIN_VERSION_base if needed.+#ifndef MIN_VERSION_base+#define MIN_VERSION_base(major1,major2,minor) 0+#endif++ {-------------------------------------------------------------------- Operators --------------------------------------------------------------------}@@ -239,7 +255,7 @@ mconcat = unions instance Foldable.Foldable Set where- fold t = go t+ fold = go where go Tip = mempty go (Bin 1 k _ _) = k go (Bin _ k l r) = go l `mappend` (k `mappend` go r)@@ -254,6 +270,35 @@ go (Bin _ k l r) = go l `mappend` (f k `mappend` go r) {-# INLINE foldMap #-} +#if MIN_VERSION_base(4,6,0)+ foldl' = foldl'+ {-# INLINE foldl' #-}+ foldr' = foldr'+ {-# INLINE foldr' #-}+#endif+#if MIN_VERSION_base(4,8,0)+ length = size+ {-# INLINE length #-}+ null = null+ {-# INLINE null #-}+ toList = toList+ {-# INLINE toList #-}+ elem = go+ where STRICT_1_OF_2(go)+ go _ Tip = False+ go x (Bin _ y l r) = x == y || go x l || go x r+ {-# INLINABLE elem #-}+ minimum = findMin+ {-# INLINE minimum #-}+ maximum = findMax+ {-# INLINE maximum #-}+ sum = foldl' (+) 0+ {-# INLINABLE sum #-}+ product = foldl' (*) 1+ {-# INLINABLE product #-}+#endif++ #if __GLASGOW_HASKELL__ {--------------------------------------------------------------------@@ -763,6 +808,13 @@ {-------------------------------------------------------------------- Lists --------------------------------------------------------------------}+#if __GLASGOW_HASKELL__ >= 708+instance (Ord a) => GHCExts.IsList (Set a) where+ type Item (Set a) = a+ fromList = fromList+ toList = toList+#endif+ -- | /O(n)/. Convert the set to a list of elements. Subject to list fusion. toList :: Set a -> [a] toList = toAscList@@ -1402,12 +1454,6 @@ {-------------------------------------------------------------------- Utilities --------------------------------------------------------------------}-foldlStrict :: (a -> b -> a) -> a -> [b] -> a-foldlStrict f = go- where- go z [] = z- go z (x:xs) = let z' = f z x in z' `seq` go z' xs-{-# INLINE foldlStrict #-} -- | /O(1)/. Decompose a set into pieces based on the structure of the underlying -- tree. This function is useful for consuming a set in parallel.
− Data/StrictPair.hs
@@ -1,13 +0,0 @@-{-# LANGUAGE CPP #-}-#if !defined(TESTING) && __GLASGOW_HASKELL__ >= 703-{-# LANGUAGE Trustworthy #-}-#endif-module Data.StrictPair (StrictPair(..), toPair) where---- | Same as regular Haskell pairs, but (x :*: _|_) = (_|_ :*: y) =--- _|_-data StrictPair a b = !a :*: !b--toPair :: StrictPair a b -> (a, b)-toPair (x :*: y) = (x, y)-{-# INLINE toPair #-}
Data/Tree.hs view
@@ -3,8 +3,15 @@ {-# LANGUAGE DeriveDataTypeable, StandaloneDeriving #-} #endif #if __GLASGOW_HASKELL__ >= 703-{-# LANGUAGE Safe #-}+{-# LANGUAGE Trustworthy #-} #endif+-- We use cabal-generated MIN_VERSION_base to adapt to changes of base.+-- Nevertheless, as a convenience, we also allow compiling without cabal by+-- defining trivial MIN_VERSION_base if needed.+#ifndef MIN_VERSION_base+#define MIN_VERSION_base(major1,major2,minor) 0+#endif+ ----------------------------------------------------------------------------- -- | -- Module : Data.Tree@@ -32,7 +39,7 @@ ) where import Control.Applicative (Applicative(..), (<$>))-import Control.Monad+import Control.Monad (liftM) import Data.Monoid (Monoid(..)) import Data.Sequence (Seq, empty, singleton, (<|), (|>), fromList, ViewL(..), ViewR(..), viewl, viewr)@@ -45,6 +52,11 @@ import Data.Data (Data) #endif +#if MIN_VERSION_base(4,8,0)+import Data.Coerce+#endif++ -- | Multi-way trees, also known as /rose trees/. data Tree a = Node { rootLabel :: a, -- ^ label value@@ -61,8 +73,19 @@ INSTANCE_TYPEABLE1(Tree,treeTc,"Tree") instance Functor Tree where- fmap f (Node x ts) = Node (f x) (map (fmap f) ts)+ fmap = fmapTree +fmapTree :: (a -> b) -> Tree a -> Tree b+fmapTree f (Node x ts) = Node (f x) (map (fmapTree f) ts)+#if MIN_VERSION_base(4,8,0)+-- Safe coercions were introduced in 4.7.0, but I am not sure if they played+-- well enough with RULES to do what we want.+{-# NOINLINE [1] fmapTree #-}+{-# RULES+"fmapTree/coerce" fmapTree coerce = coerce+ #-}+#endif+ instance Applicative Tree where pure x = Node x [] Node f tfs <*> tx@(Node x txs) =@@ -78,6 +101,13 @@ instance Foldable Tree where foldMap f (Node x ts) = f x `mappend` foldMap (foldMap f) ts++#if MIN_VERSION_base(4,8,0)+ null _ = False+ {-# INLINE null #-}+ toList = flatten+ {-# INLINE toList #-}+#endif instance NFData a => NFData (Tree a) where rnf (Node x ts) = rnf x `seq` rnf ts
+ Data/Utils/BitUtil.hs view
@@ -0,0 +1,71 @@+{-# LANGUAGE CPP #-}+#if __GLASGOW_HASKELL__+{-# LANGUAGE MagicHash #-}+#endif+#if !defined(TESTING) && __GLASGOW_HASKELL__ >= 703+{-# LANGUAGE Trustworthy #-}+#endif+-----------------------------------------------------------------------------+-- |+-- Module : Data.Utils.BitUtil+-- Copyright : (c) Clark Gaebel 2012+-- (c) Johan Tibel 2012+-- License : BSD-style+-- Maintainer : libraries@haskell.org+-- Stability : provisional+-- Portability : portable+-----------------------------------------------------------------------------++module Data.Utils.BitUtil+ ( highestBitMask+ , shiftLL+ , shiftRL+ ) where++-- On GHC, include MachDeps.h to get WORD_SIZE_IN_BITS macro.+#if defined(__GLASGOW_HASKELL__)+# include "MachDeps.h"+#endif++import Data.Bits ((.|.), xor)++#if __GLASGOW_HASKELL__+import GHC.Exts (Word(..), Int(..))+import GHC.Prim (uncheckedShiftL#, uncheckedShiftRL#)+#else+import Data.Word (shiftL, shiftR)+#endif++-- The highestBitMask implementation is based on+-- http://graphics.stanford.edu/~seander/bithacks.html#RoundUpPowerOf2+-- which has been put in the public domain.++-- | Return a word where only the highest bit is set.+highestBitMask :: Word -> Word+highestBitMask x1 = let x2 = x1 .|. x1 `shiftRL` 1+ x3 = x2 .|. x2 `shiftRL` 2+ x4 = x3 .|. x3 `shiftRL` 4+ x5 = x4 .|. x4 `shiftRL` 8+ x6 = x5 .|. x5 `shiftRL` 16+#if !(defined(__GLASGOW_HASKELL__) && WORD_SIZE_IN_BITS==32)+ x7 = x6 .|. x6 `shiftRL` 32+ in x7 `xor` (x7 `shiftRL` 1)+#else+ in x6 `xor` (x6 `shiftRL` 1)+#endif+{-# INLINE highestBitMask #-}++-- Right and left logical shifts.+shiftRL, shiftLL :: Word -> Int -> Word+#if __GLASGOW_HASKELL__+{--------------------------------------------------------------------+ GHC: use unboxing to get @shiftRL@ inlined.+--------------------------------------------------------------------}+shiftRL (W# x) (I# i) = W# (uncheckedShiftRL# x i)+shiftLL (W# x) (I# i) = W# (uncheckedShiftL# x i)+#else+shiftRL x i = shiftR x i+shiftLL x i = shiftL x i+#endif+{-# INLINE shiftRL #-}+{-# INLINE shiftLL #-}
+ Data/Utils/StrictFold.hs view
@@ -0,0 +1,16 @@+{-# LANGUAGE CPP #-}+#if !defined(TESTING) && __GLASGOW_HASKELL__ >= 703+{-# LANGUAGE Safe #-}+#endif+module Data.Utils.StrictFold (foldlStrict) where++-- | Same as regular 'Data.List.foldl'', but marked INLINE so that it is always+-- inlined. This allows further optimization of the call to f, which can be+-- optimized/specialised/inlined.++foldlStrict :: (a -> b -> a) -> a -> [b] -> a+foldlStrict f = go+ where+ go z [] = z+ go z (x:xs) = let z' = f z x in z' `seq` go z' xs+{-# INLINE foldlStrict #-}
+ Data/Utils/StrictPair.hs view
@@ -0,0 +1,13 @@+{-# LANGUAGE CPP #-}+#if !defined(TESTING) && __GLASGOW_HASKELL__ >= 703+{-# LANGUAGE Safe #-}+#endif+module Data.Utils.StrictPair (StrictPair(..), toPair) where++-- | Same as regular Haskell pairs, but (x :*: _|_) = (_|_ :*: y) =+-- _|_+data StrictPair a b = !a :*: !b++toPair :: StrictPair a b -> (a, b)+toPair (x :*: y) = (x, y)+{-# INLINE toPair #-}
benchmarks/Sequence.hs view
@@ -12,18 +12,39 @@ let s10 = S.fromList [1..10] :: S.Seq Int s100 = S.fromList [1..100] :: S.Seq Int s1000 = S.fromList [1..1000] :: S.Seq Int- rnf [s10, s100, s1000] `seq` return ()+ s10000 = S.fromList [1..10000] :: S.Seq Int+ rnf [s10, s100, s1000, s10000] `seq` return () let g = mkStdGen 1 let rlist n = map (`mod` (n+1)) (take 10000 (randoms g)) :: [Int] r10 = rlist 10 r100 = rlist 100 r1000 = rlist 1000- rnf [r10, r100, r1000] `seq` return ()+ r10000 = rlist 10000+ rnf [r10, r100, r1000, r10000] `seq` return ()+ let u10 = S.replicate 10 () :: S.Seq ()+ u100 = S.replicate 100 () :: S.Seq ()+ u1000 = S.replicate 1000 () :: S.Seq ()+ u10000 = S.replicate 10000 () :: S.Seq ()+ rnf [u10, u100, u1000, u10000] `seq` return () defaultMain- [ bench "splitAt/append 10" $ nf (shuffle r10) s10- , bench "splitAt/append 100" $ nf (shuffle r100) s100- , bench "splitAt/append 1000" $ nf (shuffle r1000) s1000- ]+ [ bgroup "splitAt/append"+ [ bench "10" $ nf (shuffle r10) s10+ , bench "100" $ nf (shuffle r100) s100+ , bench "1000" $ nf (shuffle r1000) s1000+ ]+ , bgroup "zip"+ [ bench "ix10000/5000" $ nf (\(xs,ys) -> S.zip xs ys `S.index` 5000) (s10000, u10000)+ , bench "nf100" $ nf (uncurry S.zip) (s100, u100)+ , bench "nf10000" $ nf (uncurry S.zip) (s10000, u10000)+ ]+ , bgroup "fromFunction"+ [ bench "ix10000/5000" $ nf (\s -> S.fromFunction s (+1) `S.index` (s `div` 2)) 10000+ , bench "nf10" $ nf (\s -> S.fromFunction s (+1)) 10+ , bench "nf100" $ nf (\s -> S.fromFunction s (+1)) 100+ , bench "nf1000" $ nf (\s -> S.fromFunction s (+1)) 1000+ , bench "nf10000" $ nf (\s -> S.fromFunction s (+1)) 10000+ ]+ ] -- splitAt+append: repeatedly cut the sequence at a random point -- and rejoin the pieces in the opposite order.
containers.cabal view
@@ -1,5 +1,5 @@ name: containers-version: 0.5.5.1+version: 0.5.6.0 license: BSD3 license-file: LICENSE maintainer: fox@ucw.cz@@ -31,7 +31,7 @@ location: http://github.com/haskell/containers.git Library- build-depends: base >= 4.2 && < 5, array, deepseq >= 1.2 && < 1.4+ build-depends: base >= 4.2 && < 5, array, deepseq >= 1.2 && < 1.5 if impl(ghc>=6.10) build-depends: ghc-prim @@ -52,19 +52,18 @@ Data.Sequence Data.Tree other-modules:- Data.BitUtil Data.IntMap.Base Data.IntSet.Base Data.Map.Base Data.Set.Base- Data.StrictPair+ Data.Utils.BitUtil+ Data.Utils.StrictFold+ Data.Utils.StrictPair include-dirs: include if impl(ghc<7.0) extensions: MagicHash, DeriveDataTypeable, StandaloneDeriving, Rank2Types- if impl(ghc >= 7.8)- extensions: RoleAnnotations ------------------- -- T E S T I N G --@@ -84,7 +83,7 @@ type: exitcode-stdio-1.0 cpp-options: -DTESTING - build-depends: base >= 4.2 && < 5, array, deepseq >= 1.2 && < 1.4, ghc-prim+ build-depends: base >= 4.2 && < 5, array, deepseq >= 1.2 && < 1.5, ghc-prim ghc-options: -O2 extensions: MagicHash, DeriveDataTypeable, StandaloneDeriving, Rank2Types @@ -101,7 +100,7 @@ type: exitcode-stdio-1.0 cpp-options: -DTESTING -DSTRICT - build-depends: base >= 4.2 && < 5, array, deepseq >= 1.2 && < 1.4, ghc-prim+ build-depends: base >= 4.2 && < 5, array, deepseq >= 1.2 && < 1.5, ghc-prim ghc-options: -O2 extensions: MagicHash, DeriveDataTypeable, StandaloneDeriving, Rank2Types @@ -118,7 +117,7 @@ type: exitcode-stdio-1.0 cpp-options: -DTESTING - build-depends: base >= 4.2 && < 5, array, deepseq >= 1.2 && < 1.4, ghc-prim+ build-depends: base >= 4.2 && < 5, array, deepseq >= 1.2 && < 1.5, ghc-prim ghc-options: -O2 extensions: MagicHash, DeriveDataTypeable, StandaloneDeriving, Rank2Types @@ -135,7 +134,7 @@ type: exitcode-stdio-1.0 cpp-options: -DTESTING - build-depends: base >= 4.2 && < 5, array, deepseq >= 1.2 && < 1.4, ghc-prim+ build-depends: base >= 4.2 && < 5, array, deepseq >= 1.2 && < 1.5, ghc-prim ghc-options: -O2 extensions: MagicHash, DeriveDataTypeable, StandaloneDeriving, Rank2Types @@ -152,7 +151,7 @@ type: exitcode-stdio-1.0 cpp-options: -DTESTING -DSTRICT - build-depends: base >= 4.2 && < 5, array, deepseq >= 1.2 && < 1.4, ghc-prim+ build-depends: base >= 4.2 && < 5, array, deepseq >= 1.2 && < 1.5, ghc-prim ghc-options: -O2 extensions: MagicHash, DeriveDataTypeable, StandaloneDeriving, Rank2Types @@ -169,7 +168,7 @@ type: exitcode-stdio-1.0 cpp-options: -DTESTING - build-depends: base >= 4.2 && < 5, array, deepseq >= 1.2 && < 1.4, ghc-prim+ build-depends: base >= 4.2 && < 5, array, deepseq >= 1.2 && < 1.5, ghc-prim ghc-options: -O2 extensions: MagicHash, DeriveDataTypeable, StandaloneDeriving, Rank2Types @@ -186,7 +185,7 @@ type: exitcode-stdio-1.0 cpp-options: -DTESTING - build-depends: base >= 4.2 && < 5, array, deepseq >= 1.2 && < 1.4, ghc-prim+ build-depends: base >= 4.2 && < 5, array, deepseq >= 1.2 && < 1.5, ghc-prim ghc-options: -O2 extensions: MagicHash, DeriveDataTypeable, StandaloneDeriving, Rank2Types @@ -201,7 +200,7 @@ type: exitcode-stdio-1.0 cpp-options: -DTESTING - build-depends: base >= 4.2 && < 5, array, deepseq >= 1.2 && < 1.4, ghc-prim+ build-depends: base >= 4.2 && < 5, array, deepseq >= 1.2 && < 1.5, ghc-prim ghc-options: -O2 extensions: MagicHash, DeriveDataTypeable, StandaloneDeriving, Rank2Types @@ -211,30 +210,34 @@ test-framework-quickcheck2 test-suite map-strictness-properties- hs-source-dirs: tests- main-is: MapStrictness.hs+ hs-source-dirs: tests, .+ main-is: map-strictness.hs type: exitcode-stdio-1.0 build-depends:- base,+ array,+ base >= 4.2 && < 5, ChasingBottoms,- containers,+ deepseq >= 1.2 && < 1.5, QuickCheck >= 2.4.0.1,+ ghc-prim, test-framework >= 0.3.3, test-framework-quickcheck2 >= 0.2.9 ghc-options: -Wall test-suite intmap-strictness-properties- hs-source-dirs: tests- main-is: IntMapStrictness.hs+ hs-source-dirs: tests, .+ main-is: intmap-strictness.hs type: exitcode-stdio-1.0 build-depends:- base,+ array,+ base >= 4.2 && < 5, ChasingBottoms,- containers,+ deepseq >= 1.2 && < 1.5, QuickCheck >= 2.4.0.1,+ ghc-prim, test-framework >= 0.3.3, test-framework-quickcheck2 >= 0.2.9
− tests/IntMapStrictness.hs
@@ -1,127 +0,0 @@-{-# LANGUAGE FlexibleInstances, GeneralizedNewtypeDeriving #-}-{-# OPTIONS_GHC -fno-warn-orphans #-}--module Main (main) where--import Test.ChasingBottoms.IsBottom-import Test.Framework (Test, defaultMain, testGroup)-import Test.Framework.Providers.QuickCheck2 (testProperty)-import Test.QuickCheck (Arbitrary(arbitrary))--import Data.IntMap.Strict (IntMap)-import qualified Data.IntMap.Strict as M--instance Arbitrary v => Arbitrary (IntMap v) where- arbitrary = M.fromList `fmap` arbitrary--instance Show (Int -> Int) where- show _ = "<function>"--instance Show (Int -> Int -> Int) where- show _ = "<function>"--instance Show (Int -> Int -> Int -> Int) where- show _ = "<function>"----------------------------------------------------------------------------- * Properties----------------------------------------------------------------------------- ** Strict module--pSingletonKeyStrict :: Int -> Bool-pSingletonKeyStrict v = isBottom $ M.singleton (bottom :: Int) v--pSingletonValueStrict :: Int -> Bool-pSingletonValueStrict k = isBottom $ (M.singleton k (bottom :: Int))--pFindWithDefaultKeyStrict :: Int -> IntMap Int -> Bool-pFindWithDefaultKeyStrict def m = isBottom $ M.findWithDefault def bottom m--pFindWithDefaultValueStrict :: Int -> IntMap Int -> Bool-pFindWithDefaultValueStrict k m =- M.member k m || (isBottom $ M.findWithDefault bottom k m)--pAdjustKeyStrict :: (Int -> Int) -> IntMap Int -> Bool-pAdjustKeyStrict f m = isBottom $ M.adjust f bottom m--pAdjustValueStrict :: Int -> IntMap Int -> Bool-pAdjustValueStrict k m- | k `M.member` m = isBottom $ M.adjust (const bottom) k m- | otherwise = case M.keys m of- [] -> True- (k':_) -> isBottom $ M.adjust (const bottom) k' m--pInsertKeyStrict :: Int -> IntMap Int -> Bool-pInsertKeyStrict v m = isBottom $ M.insert bottom v m--pInsertValueStrict :: Int -> IntMap Int -> Bool-pInsertValueStrict k m = isBottom $ M.insert k bottom m--pInsertWithKeyStrict :: (Int -> Int -> Int) -> Int -> IntMap Int -> Bool-pInsertWithKeyStrict f v m = isBottom $ M.insertWith f bottom v m--pInsertWithValueStrict :: (Int -> Int -> Int) -> Int -> Int -> IntMap Int- -> Bool-pInsertWithValueStrict f k v m- | M.member k m = (isBottom $ M.insertWith (const2 bottom) k v m) &&- not (isBottom $ M.insertWith (const2 1) k bottom m)- | otherwise = isBottom $ M.insertWith f k bottom m--pInsertLookupWithKeyKeyStrict :: (Int -> Int -> Int -> Int) -> Int -> IntMap Int- -> Bool-pInsertLookupWithKeyKeyStrict f v m = isBottom $ M.insertLookupWithKey f bottom v m--pInsertLookupWithKeyValueStrict :: (Int -> Int -> Int -> Int) -> Int -> Int- -> IntMap Int -> Bool-pInsertLookupWithKeyValueStrict f k v m- | M.member k m = (isBottom $ M.insertLookupWithKey (const3 bottom) k v m) &&- not (isBottom $ M.insertLookupWithKey (const3 1) k bottom m)- | otherwise = isBottom $ M.insertLookupWithKey f k bottom m----------------------------------------------------------------------------- * Test list--tests :: [Test]-tests =- [- -- Basic interface- testGroup "IntMap.Strict"- [ testProperty "singleton is key-strict" pSingletonKeyStrict- , testProperty "singleton is value-strict" pSingletonValueStrict- , testProperty "member is key-strict" $ keyStrict M.member- , testProperty "lookup is key-strict" $ keyStrict M.lookup- , testProperty "findWithDefault is key-strict" pFindWithDefaultKeyStrict- , testProperty "findWithDefault is value-strict" pFindWithDefaultValueStrict- , testProperty "! is key-strict" $ keyStrict (flip (M.!))- , testProperty "delete is key-strict" $ keyStrict M.delete- , testProperty "adjust is key-strict" pAdjustKeyStrict- , testProperty "adjust is value-strict" pAdjustValueStrict- , testProperty "insert is key-strict" pInsertKeyStrict- , testProperty "insert is value-strict" pInsertValueStrict- , testProperty "insertWith is key-strict" pInsertWithKeyStrict- , testProperty "insertWith is value-strict" pInsertWithValueStrict- , testProperty "insertLookupWithKey is key-strict"- pInsertLookupWithKeyKeyStrict- , testProperty "insertLookupWithKey is value-strict"- pInsertLookupWithKeyValueStrict- ]- ]----------------------------------------------------------------------------- * Test harness--main :: IO ()-main = defaultMain tests----------------------------------------------------------------------------- * Utilities--keyStrict :: (Int -> IntMap Int -> a) -> IntMap Int -> Bool-keyStrict f m = isBottom $ f bottom m--const2 :: a -> b -> c -> a-const2 x _ _ = x--const3 :: a -> b -> c -> d -> a-const3 x _ _ _ = x
− tests/MapStrictness.hs
@@ -1,128 +0,0 @@-{-# LANGUAGE FlexibleInstances, GeneralizedNewtypeDeriving #-}-{-# OPTIONS_GHC -fno-warn-orphans #-}--module Main (main) where--import Test.ChasingBottoms.IsBottom-import Test.Framework (Test, defaultMain, testGroup)-import Test.Framework.Providers.QuickCheck2 (testProperty)-import Test.QuickCheck (Arbitrary(arbitrary))--import Data.Map.Strict (Map)-import qualified Data.Map.Strict as M--instance (Arbitrary k, Arbitrary v, Eq k, Ord k) =>- Arbitrary (Map k v) where- arbitrary = M.fromList `fmap` arbitrary--instance Show (Int -> Int) where- show _ = "<function>"--instance Show (Int -> Int -> Int) where- show _ = "<function>"--instance Show (Int -> Int -> Int -> Int) where- show _ = "<function>"----------------------------------------------------------------------------- * Properties----------------------------------------------------------------------------- ** Strict module--pSingletonKeyStrict :: Int -> Bool-pSingletonKeyStrict v = isBottom $ M.singleton (bottom :: Int) v--pSingletonValueStrict :: Int -> Bool-pSingletonValueStrict k = isBottom $ (M.singleton k (bottom :: Int))--pFindWithDefaultKeyStrict :: Int -> Map Int Int -> Bool-pFindWithDefaultKeyStrict def m = isBottom $ M.findWithDefault def bottom m--pFindWithDefaultValueStrict :: Int -> Map Int Int -> Bool-pFindWithDefaultValueStrict k m =- M.member k m || (isBottom $ M.findWithDefault bottom k m)--pAdjustKeyStrict :: (Int -> Int) -> Map Int Int -> Bool-pAdjustKeyStrict f m = isBottom $ M.adjust f bottom m--pAdjustValueStrict :: Int -> Map Int Int -> Bool-pAdjustValueStrict k m- | k `M.member` m = isBottom $ M.adjust (const bottom) k m- | otherwise = case M.keys m of- [] -> True- (k':_) -> isBottom $ M.adjust (const bottom) k' m--pInsertKeyStrict :: Int -> Map Int Int -> Bool-pInsertKeyStrict v m = isBottom $ M.insert bottom v m--pInsertValueStrict :: Int -> Map Int Int -> Bool-pInsertValueStrict k m = isBottom $ M.insert k bottom m--pInsertWithKeyStrict :: (Int -> Int -> Int) -> Int -> Map Int Int -> Bool-pInsertWithKeyStrict f v m = isBottom $ M.insertWith f bottom v m--pInsertWithValueStrict :: (Int -> Int -> Int) -> Int -> Int -> Map Int Int- -> Bool-pInsertWithValueStrict f k v m- | M.member k m = (isBottom $ M.insertWith (const2 bottom) k v m) &&- not (isBottom $ M.insertWith (const2 1) k bottom m)- | otherwise = isBottom $ M.insertWith f k bottom m--pInsertLookupWithKeyKeyStrict :: (Int -> Int -> Int -> Int) -> Int- -> Map Int Int -> Bool-pInsertLookupWithKeyKeyStrict f v m = isBottom $ M.insertLookupWithKey f bottom v m--pInsertLookupWithKeyValueStrict :: (Int -> Int -> Int -> Int) -> Int -> Int- -> Map Int Int -> Bool-pInsertLookupWithKeyValueStrict f k v m- | M.member k m = (isBottom $ M.insertLookupWithKey (const3 bottom) k v m) &&- not (isBottom $ M.insertLookupWithKey (const3 1) k bottom m)- | otherwise = isBottom $ M.insertLookupWithKey f k bottom m----------------------------------------------------------------------------- * Test list--tests :: [Test]-tests =- [- -- Basic interface- testGroup "Map.Strict"- [ testProperty "singleton is key-strict" pSingletonKeyStrict- , testProperty "singleton is value-strict" pSingletonValueStrict- , testProperty "member is key-strict" $ keyStrict M.member- , testProperty "lookup is key-strict" $ keyStrict M.lookup- , testProperty "findWithDefault is key-strict" pFindWithDefaultKeyStrict- , testProperty "findWithDefault is value-strict" pFindWithDefaultValueStrict- , testProperty "! is key-strict" $ keyStrict (flip (M.!))- , testProperty "delete is key-strict" $ keyStrict M.delete- , testProperty "adjust is key-strict" pAdjustKeyStrict- , testProperty "adjust is value-strict" pAdjustValueStrict- , testProperty "insert is key-strict" pInsertKeyStrict- , testProperty "insert is value-strict" pInsertValueStrict- , testProperty "insertWith is key-strict" pInsertWithKeyStrict- , testProperty "insertWith is value-strict" pInsertWithValueStrict- , testProperty "insertLookupWithKey is key-strict"- pInsertLookupWithKeyKeyStrict- , testProperty "insertLookupWithKey is value-strict"- pInsertLookupWithKeyValueStrict- ]- ]----------------------------------------------------------------------------- * Test harness--main :: IO ()-main = defaultMain tests----------------------------------------------------------------------------- * Utilities--keyStrict :: (Int -> Map Int Int -> a) -> Map Int Int -> Bool-keyStrict f m = isBottom $ f bottom m--const2 :: a -> b -> c -> a-const2 x _ _ = x--const3 :: a -> b -> c -> d -> a-const3 x _ _ _ = x
+ tests/intmap-strictness.hs view
@@ -0,0 +1,127 @@+{-# LANGUAGE FlexibleInstances, GeneralizedNewtypeDeriving #-}+{-# OPTIONS_GHC -fno-warn-orphans #-}++module Main (main) where++import Test.ChasingBottoms.IsBottom+import Test.Framework (Test, defaultMain, testGroup)+import Test.Framework.Providers.QuickCheck2 (testProperty)+import Test.QuickCheck (Arbitrary(arbitrary))++import Data.IntMap.Strict (IntMap)+import qualified Data.IntMap.Strict as M++instance Arbitrary v => Arbitrary (IntMap v) where+ arbitrary = M.fromList `fmap` arbitrary++instance Show (Int -> Int) where+ show _ = "<function>"++instance Show (Int -> Int -> Int) where+ show _ = "<function>"++instance Show (Int -> Int -> Int -> Int) where+ show _ = "<function>"++------------------------------------------------------------------------+-- * Properties++------------------------------------------------------------------------+-- ** Strict module++pSingletonKeyStrict :: Int -> Bool+pSingletonKeyStrict v = isBottom $ M.singleton (bottom :: Int) v++pSingletonValueStrict :: Int -> Bool+pSingletonValueStrict k = isBottom $ (M.singleton k (bottom :: Int))++pFindWithDefaultKeyStrict :: Int -> IntMap Int -> Bool+pFindWithDefaultKeyStrict def m = isBottom $ M.findWithDefault def bottom m++pFindWithDefaultValueStrict :: Int -> IntMap Int -> Bool+pFindWithDefaultValueStrict k m =+ M.member k m || (isBottom $ M.findWithDefault bottom k m)++pAdjustKeyStrict :: (Int -> Int) -> IntMap Int -> Bool+pAdjustKeyStrict f m = isBottom $ M.adjust f bottom m++pAdjustValueStrict :: Int -> IntMap Int -> Bool+pAdjustValueStrict k m+ | k `M.member` m = isBottom $ M.adjust (const bottom) k m+ | otherwise = case M.keys m of+ [] -> True+ (k':_) -> isBottom $ M.adjust (const bottom) k' m++pInsertKeyStrict :: Int -> IntMap Int -> Bool+pInsertKeyStrict v m = isBottom $ M.insert bottom v m++pInsertValueStrict :: Int -> IntMap Int -> Bool+pInsertValueStrict k m = isBottom $ M.insert k bottom m++pInsertWithKeyStrict :: (Int -> Int -> Int) -> Int -> IntMap Int -> Bool+pInsertWithKeyStrict f v m = isBottom $ M.insertWith f bottom v m++pInsertWithValueStrict :: (Int -> Int -> Int) -> Int -> Int -> IntMap Int+ -> Bool+pInsertWithValueStrict f k v m+ | M.member k m = (isBottom $ M.insertWith (const2 bottom) k v m) &&+ not (isBottom $ M.insertWith (const2 1) k bottom m)+ | otherwise = isBottom $ M.insertWith f k bottom m++pInsertLookupWithKeyKeyStrict :: (Int -> Int -> Int -> Int) -> Int -> IntMap Int+ -> Bool+pInsertLookupWithKeyKeyStrict f v m = isBottom $ M.insertLookupWithKey f bottom v m++pInsertLookupWithKeyValueStrict :: (Int -> Int -> Int -> Int) -> Int -> Int+ -> IntMap Int -> Bool+pInsertLookupWithKeyValueStrict f k v m+ | M.member k m = (isBottom $ M.insertLookupWithKey (const3 bottom) k v m) &&+ not (isBottom $ M.insertLookupWithKey (const3 1) k bottom m)+ | otherwise = isBottom $ M.insertLookupWithKey f k bottom m++------------------------------------------------------------------------+-- * Test list++tests :: [Test]+tests =+ [+ -- Basic interface+ testGroup "IntMap.Strict"+ [ testProperty "singleton is key-strict" pSingletonKeyStrict+ , testProperty "singleton is value-strict" pSingletonValueStrict+ , testProperty "member is key-strict" $ keyStrict M.member+ , testProperty "lookup is key-strict" $ keyStrict M.lookup+ , testProperty "findWithDefault is key-strict" pFindWithDefaultKeyStrict+ , testProperty "findWithDefault is value-strict" pFindWithDefaultValueStrict+ , testProperty "! is key-strict" $ keyStrict (flip (M.!))+ , testProperty "delete is key-strict" $ keyStrict M.delete+ , testProperty "adjust is key-strict" pAdjustKeyStrict+ , testProperty "adjust is value-strict" pAdjustValueStrict+ , testProperty "insert is key-strict" pInsertKeyStrict+ , testProperty "insert is value-strict" pInsertValueStrict+ , testProperty "insertWith is key-strict" pInsertWithKeyStrict+ , testProperty "insertWith is value-strict" pInsertWithValueStrict+ , testProperty "insertLookupWithKey is key-strict"+ pInsertLookupWithKeyKeyStrict+ , testProperty "insertLookupWithKey is value-strict"+ pInsertLookupWithKeyValueStrict+ ]+ ]++------------------------------------------------------------------------+-- * Test harness++main :: IO ()+main = defaultMain tests++------------------------------------------------------------------------+-- * Utilities++keyStrict :: (Int -> IntMap Int -> a) -> IntMap Int -> Bool+keyStrict f m = isBottom $ f bottom m++const2 :: a -> b -> c -> a+const2 x _ _ = x++const3 :: a -> b -> c -> d -> a+const3 x _ _ _ = x
+ tests/map-strictness.hs view
@@ -0,0 +1,128 @@+{-# LANGUAGE FlexibleInstances, GeneralizedNewtypeDeriving #-}+{-# OPTIONS_GHC -fno-warn-orphans #-}++module Main (main) where++import Test.ChasingBottoms.IsBottom+import Test.Framework (Test, defaultMain, testGroup)+import Test.Framework.Providers.QuickCheck2 (testProperty)+import Test.QuickCheck (Arbitrary(arbitrary))++import Data.Map.Strict (Map)+import qualified Data.Map.Strict as M++instance (Arbitrary k, Arbitrary v, Eq k, Ord k) =>+ Arbitrary (Map k v) where+ arbitrary = M.fromList `fmap` arbitrary++instance Show (Int -> Int) where+ show _ = "<function>"++instance Show (Int -> Int -> Int) where+ show _ = "<function>"++instance Show (Int -> Int -> Int -> Int) where+ show _ = "<function>"++------------------------------------------------------------------------+-- * Properties++------------------------------------------------------------------------+-- ** Strict module++pSingletonKeyStrict :: Int -> Bool+pSingletonKeyStrict v = isBottom $ M.singleton (bottom :: Int) v++pSingletonValueStrict :: Int -> Bool+pSingletonValueStrict k = isBottom $ (M.singleton k (bottom :: Int))++pFindWithDefaultKeyStrict :: Int -> Map Int Int -> Bool+pFindWithDefaultKeyStrict def m = isBottom $ M.findWithDefault def bottom m++pFindWithDefaultValueStrict :: Int -> Map Int Int -> Bool+pFindWithDefaultValueStrict k m =+ M.member k m || (isBottom $ M.findWithDefault bottom k m)++pAdjustKeyStrict :: (Int -> Int) -> Map Int Int -> Bool+pAdjustKeyStrict f m = isBottom $ M.adjust f bottom m++pAdjustValueStrict :: Int -> Map Int Int -> Bool+pAdjustValueStrict k m+ | k `M.member` m = isBottom $ M.adjust (const bottom) k m+ | otherwise = case M.keys m of+ [] -> True+ (k':_) -> isBottom $ M.adjust (const bottom) k' m++pInsertKeyStrict :: Int -> Map Int Int -> Bool+pInsertKeyStrict v m = isBottom $ M.insert bottom v m++pInsertValueStrict :: Int -> Map Int Int -> Bool+pInsertValueStrict k m = isBottom $ M.insert k bottom m++pInsertWithKeyStrict :: (Int -> Int -> Int) -> Int -> Map Int Int -> Bool+pInsertWithKeyStrict f v m = isBottom $ M.insertWith f bottom v m++pInsertWithValueStrict :: (Int -> Int -> Int) -> Int -> Int -> Map Int Int+ -> Bool+pInsertWithValueStrict f k v m+ | M.member k m = (isBottom $ M.insertWith (const2 bottom) k v m) &&+ not (isBottom $ M.insertWith (const2 1) k bottom m)+ | otherwise = isBottom $ M.insertWith f k bottom m++pInsertLookupWithKeyKeyStrict :: (Int -> Int -> Int -> Int) -> Int+ -> Map Int Int -> Bool+pInsertLookupWithKeyKeyStrict f v m = isBottom $ M.insertLookupWithKey f bottom v m++pInsertLookupWithKeyValueStrict :: (Int -> Int -> Int -> Int) -> Int -> Int+ -> Map Int Int -> Bool+pInsertLookupWithKeyValueStrict f k v m+ | M.member k m = (isBottom $ M.insertLookupWithKey (const3 bottom) k v m) &&+ not (isBottom $ M.insertLookupWithKey (const3 1) k bottom m)+ | otherwise = isBottom $ M.insertLookupWithKey f k bottom m++------------------------------------------------------------------------+-- * Test list++tests :: [Test]+tests =+ [+ -- Basic interface+ testGroup "Map.Strict"+ [ testProperty "singleton is key-strict" pSingletonKeyStrict+ , testProperty "singleton is value-strict" pSingletonValueStrict+ , testProperty "member is key-strict" $ keyStrict M.member+ , testProperty "lookup is key-strict" $ keyStrict M.lookup+ , testProperty "findWithDefault is key-strict" pFindWithDefaultKeyStrict+ , testProperty "findWithDefault is value-strict" pFindWithDefaultValueStrict+ , testProperty "! is key-strict" $ keyStrict (flip (M.!))+ , testProperty "delete is key-strict" $ keyStrict M.delete+ , testProperty "adjust is key-strict" pAdjustKeyStrict+ , testProperty "adjust is value-strict" pAdjustValueStrict+ , testProperty "insert is key-strict" pInsertKeyStrict+ , testProperty "insert is value-strict" pInsertValueStrict+ , testProperty "insertWith is key-strict" pInsertWithKeyStrict+ , testProperty "insertWith is value-strict" pInsertWithValueStrict+ , testProperty "insertLookupWithKey is key-strict"+ pInsertLookupWithKeyKeyStrict+ , testProperty "insertLookupWithKey is value-strict"+ pInsertLookupWithKeyValueStrict+ ]+ ]++------------------------------------------------------------------------+-- * Test harness++main :: IO ()+main = defaultMain tests++------------------------------------------------------------------------+-- * Utilities++keyStrict :: (Int -> Map Int Int -> a) -> Map Int Int -> Bool+keyStrict f m = isBottom $ f bottom m++const2 :: a -> b -> c -> a+const2 x _ _ = x++const3 :: a -> b -> c -> d -> a+const3 x _ _ _ = x
tests/seq-properties.hs view
@@ -2,6 +2,7 @@ import Control.Applicative (Applicative(..)) import Control.Arrow ((***))+import Data.Array (listArray) import Data.Foldable (Foldable(..), toList, all, sum) import Data.Functor ((<$>), (<$)) import Data.Maybe@@ -36,6 +37,8 @@ , testProperty "(|>)" prop_snoc , testProperty "(><)" prop_append , testProperty "fromList" prop_fromList+ , testProperty "fromFunction" prop_fromFunction+ , testProperty "fromArray" prop_fromArray , testProperty "replicate" prop_replicate , testProperty "replicateA" prop_replicateA , testProperty "replicateM" prop_replicateM@@ -269,6 +272,14 @@ prop_fromList :: [A] -> Bool prop_fromList xs = toList' (fromList xs) ~= xs++prop_fromFunction :: [A] -> Bool+prop_fromFunction xs =+ toList' (fromFunction (Prelude.length xs) (xs!!)) ~= xs++prop_fromArray :: [A] -> Bool+prop_fromArray xs =+ toList' (fromArray (listArray (42, 42+Prelude.length xs-1) xs)) ~= xs -- ** Repetition