iteratee 0.8.7.6 → 0.8.8.0
raw patch · 7 files changed
+359/−81 lines, 7 filesPVP ok
version bump matches the API change (PVP)
API changes (from Hackage documentation)
+ Data.Iteratee.Binary: readWord16be_bs :: Monad m => Iteratee ByteString m Word16
+ Data.Iteratee.Binary: readWord16le_bs :: Monad m => Iteratee ByteString m Word16
+ Data.Iteratee.Binary: readWord32be_bs :: Monad m => Iteratee ByteString m Word32
+ Data.Iteratee.Binary: readWord32le_bs :: Monad m => Iteratee ByteString m Word32
+ Data.Iteratee.Binary: readWord64be_bs :: Monad m => Iteratee ByteString m Word64
+ Data.Iteratee.Binary: readWord64le_bs :: Monad m => Iteratee ByteString m Word64
+ Data.Iteratee.Exception: class (Typeable e, Show e) => Exception e
+ Data.Iteratee.Exception: fromException :: Exception e => SomeException -> Maybe e
+ Data.Iteratee.Exception: toException :: Exception e => e -> SomeException
+ Data.Iteratee.ListLike: countConsumed :: (Monad m, ListLike s el, Nullable s, Integral n) => Iteratee s m a -> Iteratee s m (a, n)
+ Data.Iteratee.ListLike: greedy :: (Monad m, Functor m, ListLike s el', Monoid a) => Iteratee s m a -> Iteratee s m a
Files
- iteratee.cabal +1/−1
- src/Data/Iteratee/Binary.hs +243/−67
- src/Data/Iteratee/Exception.hs +1/−0
- src/Data/Iteratee/Iteratee.hs +8/−2
- src/Data/Iteratee/ListLike.hs +70/−8
- tests/benchmarks.hs +30/−2
- tests/testIteratee.hs +6/−1
iteratee.cabal view
@@ -1,5 +1,5 @@ name: iteratee-version: 0.8.7.6+version: 0.8.8.0 synopsis: Iteratee-based I/O description: The Iteratee monad provides strict, safe, and functional I/O. In addition
src/Data/Iteratee/Binary.hs view
@@ -14,61 +14,67 @@ ,endianRead3i ,endianRead4 ,endianRead8+ -- ** bytestring specializations+ ,readWord16be_bs+ ,readWord16le_bs+ ,readWord32be_bs+ ,readWord32le_bs+ ,readWord64be_bs+ ,readWord64le_bs ) where import Data.Iteratee.Base import qualified Data.Iteratee.ListLike as I import qualified Data.ListLike as LL+import qualified Data.ByteString as B+import qualified Data.ByteString.Unsafe as B import Data.Word import Data.Bits import Data.Int - -- ------------------------------------------------------------------------ -- Binary Random IO Iteratees -- Iteratees to read unsigned integers written in Big- or Little-endian ways --- |Indicate endian-ness.+-- | Indicate endian-ness. data Endian = MSB -- ^ Most Significant Byte is first (big-endian) | LSB -- ^ Least Significan Byte is first (little-endian) deriving (Eq, Ord, Show, Enum) endianRead2- :: (Nullable s, LL.ListLike s Word8, Monad m) =>- Endian- -> Iteratee s m Word16+ :: (Nullable s, LL.ListLike s Word8, Monad m)+ => Endian+ -> Iteratee s m Word16 endianRead2 e = do c1 <- I.head c2 <- I.head case e of- MSB -> return $ (fromIntegral c1 `shiftL` 8) .|. fromIntegral c2- LSB -> return $ (fromIntegral c2 `shiftL` 8) .|. fromIntegral c1+ MSB -> return $ word16 c1 c2+ LSB -> return $ word16 c2 c1+{-# INLINE endianRead2 #-} endianRead3- :: (Nullable s, LL.ListLike s Word8, Monad m) =>- Endian- -> Iteratee s m Word32+ :: (Nullable s, LL.ListLike s Word8, Monad m)+ => Endian+ -> Iteratee s m Word32 endianRead3 e = do c1 <- I.head c2 <- I.head c3 <- I.head case e of- MSB -> return $ (((fromIntegral c1- `shiftL` 8) .|. fromIntegral c2)- `shiftL` 8) .|. fromIntegral c3- LSB -> return $ (((fromIntegral c3- `shiftL` 8) .|. fromIntegral c2)- `shiftL` 8) .|. fromIntegral c1+ MSB -> return $ word32 0 c1 c2 c3+ LSB -> return $ word32 0 c3 c2 c1+{-# INLINE endianRead3 #-} -- |Read 3 bytes in an endian manner. If the first bit is set (negative), -- set the entire first byte so the Int32 will be negative as -- well. endianRead3i- :: (Nullable s, LL.ListLike s Word8, Monad m) =>- Endian- -> Iteratee s m Int32+ :: (Nullable s, LL.ListLike s Word8, Monad m)+ => Endian+ -> Iteratee s m Int32 endianRead3i e = do c1 <- I.head c2 <- I.head@@ -83,57 +89,227 @@ in return $ (((fromIntegral c3 `shiftL` 8) .|. fromIntegral c2) `shiftL` 8) .|. fromIntegral m+{-# INLINE endianRead3i #-} endianRead4- :: (Nullable s, LL.ListLike s Word8, Monad m) =>- Endian- -> Iteratee s m Word32+ :: (Nullable s, LL.ListLike s Word8, Monad m)+ => Endian+ -> Iteratee s m Word32 endianRead4 e = do- c1 <- I.head- c2 <- I.head- c3 <- I.head- c4 <- I.head- case e of- MSB -> return $- (((((fromIntegral c1- `shiftL` 8) .|. fromIntegral c2)- `shiftL` 8) .|. fromIntegral c3)- `shiftL` 8) .|. fromIntegral c4- LSB -> return $- (((((fromIntegral c4- `shiftL` 8) .|. fromIntegral c3)- `shiftL` 8) .|. fromIntegral c2)- `shiftL` 8) .|. fromIntegral c1+ ln' <- I.chunkLength+ case ln' of+ Just ln | ln >= 4 -> do+ ck <- I.getChunk+ let t = LL.drop 4 ck+ res = case e of+ MSB -> word32 (LL.index ck 0)+ (LL.index ck 1)+ (LL.index ck 2)+ (LL.index ck 3)+ LSB -> word32 (LL.index ck 3)+ (LL.index ck 2)+ (LL.index ck 1)+ (LL.index ck 0)+ res `seq` idone res (I.Chunk t)+ _ -> do+ c1 <- I.head+ c2 <- I.head+ c3 <- I.head+ c4 <- I.head+ return $ case e of+ MSB -> word32 c1 c2 c3 c4+ LSB -> word32 c4 c3 c2 c1+{-# INLINE [1] endianRead4 #-} endianRead8- :: (Nullable s, LL.ListLike s Word8, Monad m) =>- Endian- -> Iteratee s m Word64+ :: (Nullable s, LL.ListLike s Word8, Monad m)+ => Endian+ -> Iteratee s m Word64 endianRead8 e = do- c1 <- I.head- c2 <- I.head- c3 <- I.head- c4 <- I.head- c5 <- I.head- c6 <- I.head- c7 <- I.head- c8 <- I.head- case e of- MSB -> return $- (((((((((((((fromIntegral c1- `shiftL` 8) .|. fromIntegral c2)- `shiftL` 8) .|. fromIntegral c3)- `shiftL` 8) .|. fromIntegral c4)- `shiftL` 8) .|. fromIntegral c5)- `shiftL` 8) .|. fromIntegral c6)- `shiftL` 8) .|. fromIntegral c7)- `shiftL` 8) .|. fromIntegral c8- LSB -> return $- (((((((((((((fromIntegral c8- `shiftL` 8) .|. fromIntegral c7)- `shiftL` 8) .|. fromIntegral c6)- `shiftL` 8) .|. fromIntegral c5)- `shiftL` 8) .|. fromIntegral c4)- `shiftL` 8) .|. fromIntegral c3)- `shiftL` 8) .|. fromIntegral c2)- `shiftL` 8) .|. fromIntegral c1+ ln' <- I.chunkLength+ case ln' of+ Just ln | ln >= 8 -> do+ ck <- I.getChunk+ let t = LL.drop 8 ck+ res = case e of+ MSB -> word64 (LL.index ck 0)+ (LL.index ck 1)+ (LL.index ck 2)+ (LL.index ck 3)+ (LL.index ck 4)+ (LL.index ck 5)+ (LL.index ck 6)+ (LL.index ck 7)+ LSB -> word64 (LL.index ck 7)+ (LL.index ck 6)+ (LL.index ck 5)+ (LL.index ck 4)+ (LL.index ck 3)+ (LL.index ck 2)+ (LL.index ck 1)+ (LL.index ck 0)+ res `seq` idone res (I.Chunk t)+ _ -> do+ c1 <- I.head+ c2 <- I.head+ c3 <- I.head+ c4 <- I.head+ c5 <- I.head+ c6 <- I.head+ c7 <- I.head+ c8 <- I.head+ return $ case e of+ MSB -> word64 c1 c2 c3 c4 c5 c6 c7 c8+ LSB -> word64 c8 c7 c6 c5 c4 c3 c2 c1+{-# INLINE [1] endianRead8 #-}++{-# RULES "iteratee: binary bytestring spec." endianRead4 = endianRead4BS #-}+{-# RULES "iteratee: binary bytestring spec." endianRead8 = endianRead8BS #-}++endianRead4BS :: Monad m => Endian -> Iteratee B.ByteString m Word32+endianRead4BS MSB = readWord32be_bs+endianRead4BS LSB = readWord32le_bs+{-# INLINE endianRead4BS #-}++endianRead8BS :: Monad m => Endian -> Iteratee B.ByteString m Word64+endianRead8BS MSB = readWord64be_bs+endianRead8BS LSB = readWord64le_bs+{-# INLINE endianRead8BS #-}++-- the 16-bit variant is only included for completeness; the+-- polymorphic code is as fast as any specialization I've yet found+-- in these cases. (JWL, 2012-01-09)+readWord16be_bs :: Monad m => Iteratee B.ByteString m Word16+readWord16be_bs = endianRead2 MSB+{-# INLINE readWord16be_bs #-}++readWord16le_bs :: Monad m => Iteratee B.ByteString m Word16+readWord16le_bs = endianRead2 LSB+{-# INLINE readWord16le_bs #-}++readWord32be_bs :: Monad m => Iteratee B.ByteString m Word32+readWord32be_bs = do+ ln' <- I.chunkLength+ case ln' of+ Just ln | ln >= 4 -> do+ ck <- I.getChunk+ let t = B.drop 4 ck+ res = word32 (B.unsafeIndex ck 0)+ (B.unsafeIndex ck 1)+ (B.unsafeIndex ck 2)+ (B.unsafeIndex ck 3)+ res `seq` idone res (I.Chunk t)+ _ -> do+ c1 <- I.head+ c2 <- I.head+ c3 <- I.head+ c4 <- I.head+ return $! word32 c1 c2 c3 c4+{-# INLINE readWord32be_bs #-}++readWord32le_bs :: Monad m => Iteratee B.ByteString m Word32+readWord32le_bs = do+ ln' <- I.chunkLength+ case ln' of+ Just ln | ln >= 4 -> do+ ck <- I.getChunk+ let t = B.drop 4 ck+ res = word32 (B.unsafeIndex ck 3)+ (B.unsafeIndex ck 2)+ (B.unsafeIndex ck 1)+ (B.unsafeIndex ck 0)+ res `seq` idone res (I.Chunk t)+ _ -> do+ c1 <- I.head+ c2 <- I.head+ c3 <- I.head+ c4 <- I.head+ return $! word32 c4 c3 c2 c1+{-# INLINE readWord32le_bs #-}++readWord64be_bs :: Monad m => Iteratee B.ByteString m Word64+readWord64be_bs = do+ ln' <- I.chunkLength+ case ln' of+ Just ln | ln >= 8 -> do+ ck <- I.getChunk+ let t = B.drop 8 ck+ res = word64 (B.unsafeIndex ck 0)+ (B.unsafeIndex ck 1)+ (B.unsafeIndex ck 2)+ (B.unsafeIndex ck 3)+ (B.unsafeIndex ck 4)+ (B.unsafeIndex ck 5)+ (B.unsafeIndex ck 6)+ (B.unsafeIndex ck 7)+ res `seq` idone res (I.Chunk t)+ _ -> do+ cs <- I.joinI $ I.take 8 I.stream2stream+ if B.length cs == 8+ then return $ word64 (B.unsafeIndex cs 0)+ (B.unsafeIndex cs 1)+ (B.unsafeIndex cs 2)+ (B.unsafeIndex cs 3)+ (B.unsafeIndex cs 4)+ (B.unsafeIndex cs 5)+ (B.unsafeIndex cs 6)+ (B.unsafeIndex cs 7)+ else I.throwErr (toException EofException)+{-# INLINE readWord64be_bs #-}++readWord64le_bs :: Monad m => Iteratee B.ByteString m Word64+readWord64le_bs = do+ ln' <- I.chunkLength+ case ln' of+ Just ln | ln >= 8 -> do+ ck <- I.getChunk+ let t = B.drop 8 ck+ res = word64 (B.unsafeIndex ck 7)+ (B.unsafeIndex ck 6)+ (B.unsafeIndex ck 5)+ (B.unsafeIndex ck 4)+ (B.unsafeIndex ck 3)+ (B.unsafeIndex ck 2)+ (B.unsafeIndex ck 1)+ (B.unsafeIndex ck 0)+ res `seq` idone res (I.Chunk t)+ _ -> do+ cs <- I.joinI $ I.take 8 I.stream2stream+ if B.length cs == 8+ then return $ word64 (B.unsafeIndex cs 7)+ (B.unsafeIndex cs 6)+ (B.unsafeIndex cs 5)+ (B.unsafeIndex cs 4)+ (B.unsafeIndex cs 3)+ (B.unsafeIndex cs 2)+ (B.unsafeIndex cs 1)+ (B.unsafeIndex cs 0)+ else I.throwErr (toException EofException)+{-# INLINE readWord64le_bs #-}++word16 :: Word8 -> Word8 -> Word16+word16 c1 c2 = (fromIntegral c1 `shiftL` 8) .|. fromIntegral c2+{-# INLINE word16 #-}++word32 :: Word8 -> Word8 -> Word8 -> Word8 -> Word32+word32 c1 c2 c3 c4 =+ (fromIntegral c1 `shiftL` 24) .|.+ (fromIntegral c2 `shiftL` 16) .|.+ (fromIntegral c3 `shiftL` 8) .|.+ fromIntegral c4+{-# INLINE word32 #-}++word64+ :: Word8 -> Word8 -> Word8 -> Word8 + -> Word8 -> Word8 -> Word8 -> Word8 + -> Word64+word64 c1 c2 c3 c4 c5 c6 c7 c8 =+ (fromIntegral c1 `shiftL` 56) .|.+ (fromIntegral c2 `shiftL` 48) .|.+ (fromIntegral c3 `shiftL` 40) .|.+ (fromIntegral c4 `shiftL` 32) .|.+ (fromIntegral c5 `shiftL` 24) .|.+ (fromIntegral c6 `shiftL` 16) .|.+ (fromIntegral c7 `shiftL` 8) .|.+ fromIntegral c8+{-# INLINE word64 #-}
src/Data/Iteratee/Exception.hs view
@@ -40,6 +40,7 @@ module Data.Iteratee.Exception ( -- * Exception types IFException (..)+ ,Exception (..) -- from Control.Exception -- ** Enumerator exceptions ,EnumException (..) ,DivergentException (..)
src/Data/Iteratee/Iteratee.hs view
@@ -245,6 +245,7 @@ onCont k Nothing = runIter (f k Nothing) od oc onCont k (Just e) = runIter (h k e) od oc in runIter inner onDone onCont+{-# INLINABLE eneeCheckIfDoneHandle #-} eneeCheckIfDonePass :: (Monad m, NullPoint elo)@@ -254,7 +255,7 @@ ) -> Enumeratee elo eli m a eneeCheckIfDonePass f = eneeCheckIfDoneHandle (\k e -> f k (Just e)) f-{-# INLINEABLE eneeCheckIfDonePass #-}+{-# INLINABLE eneeCheckIfDonePass #-} eneeCheckIfDoneIgnore :: (Monad m, NullPoint elo)@@ -292,6 +293,7 @@ {-# INLINE mapChunksM #-} -- |Convert one stream into another, not necessarily in lockstep.+-- -- The transformer mapStream maps one element of the outer stream -- to one element of the nested stream. The transformer below is more -- general: it may take several elements of the outer stream to produce@@ -307,6 +309,7 @@ check k (Just e) = throwRecoverableErr e (const identity) >> check k Nothing check k _ = isStreamFinished >>= maybe (step k) (idone (liftI k) . EOF . Just) step k = fi >>= eneeCheckIfDonePass check . k . Chunk+{-# INLINABLE convStream #-} -- |The most general stream converter. Given a function to produce iteratee -- transformers and an initial state, convert the stream using iteratees@@ -345,6 +348,7 @@ let i = f acc >>= \(acc', s') -> (checkDone (check acc') . k $ Chunk s') in joinIM $ enumChunk str' i+{-# INLINABLE unfoldConvStreamCheck #-} -- | Collapse a nested iteratee. The inner iteratee is terminated by @EOF@. -- Errors are propagated through the result.@@ -373,7 +377,8 @@ -- ------------------------------------------------------------------------ -- Enumerators--- |Each enumerator takes an iteratee and returns an iteratee+-- | Each enumerator takes an iteratee and returns an iteratee+-- -- an Enumerator is an iteratee transformer. -- The enumerator normally stops when the stream is terminated -- or when the iteratee moves to the done state, whichever comes first.@@ -414,6 +419,7 @@ -- |The composition of two enumerators: essentially the functional composition+-- -- It is convenient to flip the order of the arguments of the composition -- though: in e1 >>> e2, e1 is executed first
src/Data/Iteratee/ListLike.hs view
@@ -1,4 +1,4 @@-{-# LANGUAGE FlexibleContexts, BangPatterns, TupleSections #-}+{-# LANGUAGE FlexibleContexts, BangPatterns, TupleSections, ScopedTypeVariables #-} -- |Monadic Iteratees: -- incremental input parsers, processors and transformers@@ -58,6 +58,8 @@ ,zip4 ,zip5 ,sequence_+ ,countConsumed+ ,greedy -- ** Monadic functions ,mapM_ ,foldM@@ -80,7 +82,6 @@ import Control.Monad.Trans.Class import Data.Word (Word8) import qualified Data.ByteString as B-import qualified Data.ByteString.Char8 as BC -- Useful combinators for implementing iteratees and enumerators @@ -354,9 +355,7 @@ | otherwise = idone (k (Chunk s1)) (Chunk s2) where (s1, s2) = LL.splitAt n str step _n k stream = idone (k stream) stream-{-# SPECIALIZE take :: Monad m => Int -> Enumeratee [el] [el] m a #-}-{-# SPECIALIZE take :: Monad m => Int -> Enumeratee B.ByteString B.ByteString m a #-}-{-# SPECIALIZE take :: Monad m => Int -> Enumeratee BC.ByteString BC.ByteString m a #-}+{-# INLINE take #-} -- |Read n elements from a stream and apply the given iteratee to the -- stream of the read elements. If the given iteratee accepted fewer@@ -410,9 +409,7 @@ Left (a,s') -> od' (idone a s') (Chunk s2) Right (k',e) -> od' (icont k' e) (Chunk s2) step _ k stream = idone (k stream) stream-{-# SPECIALIZE takeUpTo :: Monad m => Int -> Enumeratee [el] [el] m a #-}-{-# SPECIALIZE takeUpTo :: Monad m => Int -> Enumeratee B.ByteString B.ByteString m a #-}-{-# INLINABLE takeUpTo #-}+{-# INLINE takeUpTo #-} -- | Takes an element predicate and returns the (possibly empty) -- prefix of the stream. All characters@@ -963,6 +960,28 @@ shorter e@(EOF _) _ = e shorter _ e@(EOF _) = e +-- |Transform an iteratee into one that keeps track of how much data it+-- consumes.+countConsumed :: forall a s el m n.+ (Monad m, LL.ListLike s el, Nullable s, Integral n) =>+ Iteratee s m a+ -> Iteratee s m (a, n)+countConsumed i = go 0 (const i) (Chunk empty)+ where+ go :: n -> (Stream s -> Iteratee s m a) -> Stream s+ -> Iteratee s m (a, n)+ go !n f str@(EOF _) = (, n) `liftM` f str+ go !n f str@(Chunk c) = Iteratee rI+ where+ newLen = n + fromIntegral (LL.length c)+ rI od oc = runIter (f str) onDone onCont+ where+ onDone a str'@(Chunk c') =+ od (a, newLen - fromIntegral (LL.length c')) str'+ onDone a str'@(EOF _) = od (a, n) str'+ onCont f' mExc = oc (go newLen f') mExc+{-# INLINE countConsumed #-}+ -- ------------------------------------------------------------------------ -- Enumerators @@ -982,6 +1001,49 @@ in runIter iter' idoneM on_cont {-# INLINE enumPureNChunk #-} +-- | Convert an iteratee to a \"greedy\" version.+--+-- When a chunk is received, repeatedly run the input iteratee+-- until the entire chunk is consumed, then the outputs+-- are combined (via 'mconcat').+--+-- > > let l = [1..5::Int]+-- > > run =<< enumPure1Chunk l (joinI (take 2 stream2list))+-- > [1,2]+-- > > run =<< enumPure1Chunk l (greedy $ joinI (I.take 2 stream2list))+-- > [1,2,3,4,5]+--+-- Note that a greedy iteratee will consume the entire input chunk and force+-- the next chunk before returning a value. A portion of the second chunk may+-- be consumed.+-- +-- 'greedy' may be useful on the first parameter of 'convStream', e.g.+-- +-- > convStream (greedy someIter)+--+-- to create more efficient converters.+greedy ::+ (Monad m, Functor m, LL.ListLike s el', Monoid a) =>+ Iteratee s m a+ -> Iteratee s m a+greedy iter' = liftI (step [] iter')+ where+ step acc iter (Chunk str)+ | LL.null str = liftI (step acc iter)+ | otherwise = joinIM $ do+ i2 <- enumPure1Chunk str iter+ result <- runIter i2 (\a s -> return $ Left (a,s))+ (\k e -> return $ Right (icont k e))+ case result of+ Left (a, Chunk resS)+ | LL.null resS+ || LL.length resS == LL.length str -> return $+ idone (mconcat $ reverse (a:acc)) (Chunk resS)+ Left (a, stream) -> return $ step (a:acc) iter stream+ Right i -> return $ fmap (mconcat . reverse . (:acc)) i+ step acc iter stream = joinIM $+ enumChunk stream (fmap (mconcat . reverse . (:acc)) iter)+{-# INLINE greedy #-} -- ------------------------------------------------------------------------ -- Monadic functions
tests/benchmarks.hs view
@@ -7,6 +7,7 @@ import Data.Iteratee import qualified Data.Iteratee.ListLike as I import qualified Data.Iteratee.Parallel as I+import qualified Data.Iteratee.Binary as I import Data.Iteratee.ListLike (enumPureNChunk, stream2list, stream2stream) import Data.Word import Data.Monoid@@ -35,6 +36,7 @@ id1 name i = BDIter1 name id i idN name i = BDIterN name 5 id i+idNx name sz i = BDIterN name sz id i idNl name i = BDIterN name 1000 id i defTotalSize = 10000@@ -78,6 +80,7 @@ headsbench = makeGroup "heads" headsBenches dropbench = makeGroup "drop" $ drop0 : dropBenches zipbench = makeGroup "zip" $ zipBenches+consbench = makeGroup "consumed" consBenches lengthbench = makeGroup "length" listBenches takebench = makeGroup "take" $ take0 : takeBenches takeUpTobench = makeGroup "takeUpTo" takeUpToBenches@@ -93,6 +96,7 @@ headsbenchbs = makeGroupBS "heads" headsBenches dropbenchbs = makeGroupBS "drop" dropBenches zipbenchbs = makeGroupBS "zip" zipBenches+consbenchbs = makeGroupBS "consumed" consBenches lengthbenchbs = makeGroupBS "length" listBenches takebenchbs = makeGroupBS "take" takeBenches takeUpTobenchbs = makeGroupBS "takeUpTo" takeUpToBenches@@ -102,11 +106,17 @@ convbenchbs = makeGroupBS "convStream" convBenches miscbenchbs = makeGroupBS "other" miscBenches +endian2benchbs = makeGroupBS "2" endian2Benches+endian3benchbs = makeGroupBS "3" endian3Benches+endian4benchbs = makeGroupBS "4" endian4Benches+endian8benchbs = makeGroupBS "8" endian8Benches+endianbenchbs = bgroup "endian" [endian2benchbs, endian3benchbs, endian4benchbs, endian8benchbs] -allListBenches = bgroup "list" [listbench, streambench, breakbench, headsbench, dropbench, zipbench, lengthbench, takebench, takeUpTobench, groupbench, mapbench, foldbench, convbench, miscbench] -allByteStringBenches = bgroup "bytestring" [listbenchbs, streambenchbs, breakbenchbs, headsbenchbs, dropbenchbs, zipbenchbs, lengthbenchbs, takebenchbs, takeUpTobenchbs, groupbenchbs, mapbenchbs, foldbenchbs, convbenchbs, miscbenchbs]+allListBenches = bgroup "list" [listbench, streambench, breakbench, headsbench, dropbench, zipbench, lengthbench, takebench, takeUpTobench, groupbench, mapbench, foldbench, convbench, miscbench, consbench] +allByteStringBenches = bgroup "bytestring" [listbenchbs, streambenchbs, breakbenchbs, headsbenchbs, dropbenchbs, zipbenchbs, lengthbenchbs, takebenchbs, takeUpTobenchbs, groupbenchbs, mapbenchbs, foldbenchbs, convbenchbs, endianbenchbs, miscbenchbs, consbenchbs]+ list0 = makeList "list one go" deepseq list1 = BDIter1 "stream2list one go" (flip deepseq ()) stream2list list2 = BDIterN "stream2list chunk by 4" 4 (flip deepseq ()) stream2list@@ -158,7 +168,11 @@ b_zip4 = idN "zip nonterminating" (I.zip I.length I.stream2stream >> identity) zipBenches = [b_zip0, b_zip1, b_zip2, b_zip3, b_zip4 ] +consumed0 = idN "countConsumed" (I.countConsumed (I.foldl' (+) 0))+consumed1 = idN "countConsumed baseline (`I.enumWith` I.length)" (I.foldl' (+) 0 `I.enumWith` I.length)+consBenches = [consumed0, consumed1] + l1 = makeList "length of list" Prelude.length l2 = id1 "length single iteratee" I.length l3 = idN "length chunked" I.length@@ -209,3 +223,17 @@ instance NFData a => NFData (Sum a) where rnf (Sum a) = rnf a++endianRead2_1 = id1 "endianRead2 single" (I.endianRead2 MSB)+endianRead2_2 = idNx "endianRead2 chunked" 1 (I.endianRead2 MSB)+endianRead3_1 = id1 "endianRead3 single" (I.endianRead3 MSB)+endianRead3_2 = idNx "endianRead3 chunked" 2 (I.endianRead3 MSB)+endianRead4_1 = id1 "endianRead4 single" (I.endianRead4 MSB)+endianRead4_2 = idNx "endianRead4 chunked" 2 (I.endianRead4 MSB)+endianRead8_1 = id1 "endianRead8 single" (I.endianRead8 MSB)+endianRead8_2 = idN "endianRead8 chunked" (I.endianRead8 MSB)+endianRead8_3 = idNx "endianRead8 multiple chunked" 2 (I.endianRead8 MSB)+endian2Benches = [endianRead2_1, endianRead2_2]+endian3Benches = [endianRead3_1, endianRead3_2]+endian4Benches = [endianRead4_1, endianRead4_2]+endian8Benches = [endianRead8_1, endianRead8_2, endianRead8_3]
tests/testIteratee.hs view
@@ -1,5 +1,5 @@ {-# OPTIONS_GHC -O #-}-{-# LANGUAGE NoMonomorphismRestriction #-}+{-# LANGUAGE NoMonomorphismRestriction, ViewPatterns #-} import Prelude as P @@ -242,6 +242,10 @@ == runner1 (enumSpecial xs n (i >> stream2list)) where types = (xs :: [Int], i :: I) +prop_countConsumed (Positive (min (2^10) -> n)) (Positive (min (2^20) -> a)) (Positive k) =+ runner1 (enumPureNChunk [1..] n iter) == (a, a)+ where+ iter = countConsumed . joinI $ (takeUpTo (a + k) ><> Iter.take a) Iter.last -- --------------------------------------------- -- Nested Iteratees@@ -515,6 +519,7 @@ testProperty "enumWith" prop_enumWith ,testProperty "enumWith remaining" prop_enumWith2 ,testProperty "enumWith remaining 2" prop_enumWith3+ ,testProperty "countConsumed" prop_countConsumed ] ,testGroup "Folds" [ testProperty "foldl" prop_foldl