iteratee 0.2.3 → 0.2.4
raw patch · 9 files changed
+64/−61 lines, 9 files
Files
- CONTRIBUTORS +1/−0
- Examples/wave_reader.hs +3/−8
- iteratee.cabal +2/−4
- src/Data/Iteratee/Base.hs +20/−20
- src/Data/Iteratee/Base/StreamChunk.hs +3/−1
- src/Data/Iteratee/IO/Fd.hs +6/−5
- src/Data/Iteratee/IO/Handle.hs +7/−4
- src/Data/Iteratee/WrappedByteString.hs +10/−9
- tests/testIteratee.hs +12/−10
CONTRIBUTORS view
@@ -7,3 +7,4 @@ In addition to the above, many thanks for comments and advice provided by: Johan Tibell+Echo Nolan
Examples/wave_reader.hs view
@@ -3,7 +3,7 @@ {-# LANGUAGE BangPatterns #-} module Main where -import Data.Iteratee+import Data.Iteratee as Iter import Data.Iteratee.Codecs.Wave import qualified Data.IntMap as IM import Data.List (foldl')@@ -38,12 +38,7 @@ -- an iteratee that calculates the maximum value found so far. -- this could be written with head as well, however it is more--- efficient to operate on an entire chunk at once.+-- efficient to use foldl' maxIter :: IterateeG [] Double IO Double-maxIter = m 0- where- m n = IterateeG (step n)- step acc (Chunk []) = return $ Cont (m acc) Nothing- step acc (Chunk xs) = return $ Cont (m $! foldl' (max . abs) acc xs) Nothing- step acc str = return $ Done acc str+maxIter = Iter.foldl' (flip (max . abs)) 0
iteratee.cabal view
@@ -1,5 +1,5 @@ Name: iteratee-Version: 0.2.3+Version: 0.2.4 Cabal-Version: >= 1.2 Description: The IterateeGM monad provides strict, safe, and functional I/O. In addition to pure Iteratee processors, file IO and @@ -26,13 +26,11 @@ Library Hs-Source-Dirs: src- ghc-options: -Wall -fexcess-precision -fno-method-sharing+ ghc-options: -Wall if flag(splitBase) build-depends: base >= 3, base < 5 else build-depends: base < 3- if impl(ghc >= 6.10)- ghc-options: -fsimplifier-phases=4 if os(windows) cpp-options: -DUSE_WINDOWS other-modules: Data.Iteratee.IO.Windows
src/Data/Iteratee/Base.hs view
@@ -194,9 +194,9 @@ joinI :: (SC.StreamChunk s el, SC.StreamChunk s' el', Monad m) => IterateeG s el m (IterateeG s' el' m a) -> IterateeG s el m a-joinI m = IterateeG (\str -> runIter m str >>= docase)+joinI m = IterateeG (docase <=< runIter m) where- docase (Done ma str) = run ma >>= \a -> return (Done a str)+ docase (Done ma str) = liftM (flip Done str) (run ma) docase (Cont k mErr) = return $ Cont (joinI k) mErr -- It turns out, IterateeG form a monad. We can use the familiar do@@ -210,7 +210,7 @@ IterateeG s el m a -> (a -> IterateeG s el m b) -> IterateeG s el m b-iterBind m f = IterateeG $ \str -> (runIter m str >>= docase)+iterBind m f = IterateeG (docase <=< runIter m) where docase (Done a str) = runIter (f a) str docase (Cont k mErr) = return $ Cont (k `iterBind` f) mErr@@ -219,7 +219,7 @@ instance (Monad m, Functor m) => Functor (IterateeG s el m) where- fmap f m = IterateeG $ \str -> runIter m str >>= docase+ fmap f m = IterateeG (docase <=< runIter m) where -- docase :: IterGV s el m a -> m (IterGV s el m a) docase (Done a stream) = return $ Done (f a) stream@@ -227,10 +227,10 @@ instance (Monad m, Functor m) => Applicative (IterateeG s el m) where pure = return- m <*> a = m >>= \f -> fmap f a+ m <*> a = m >>= flip fmap a instance MonadTrans (IterateeG s el) where- lift m = IterateeG $ \str -> m >>= \a -> return $ Done a str+ lift m = IterateeG $ \str -> liftM (flip Done str) m instance (MonadIO m) => MonadIO (IterateeG s el m) where liftIO = lift . liftIO@@ -269,7 +269,7 @@ checkErr :: (Monad m, SC.StreamChunk s el) => IterateeG s el m a -> IterateeG s el m (Either ErrMsg a)-checkErr iter = IterateeG (\str -> runIter iter str >>= check)+checkErr iter = IterateeG (check <=< runIter iter) where check (Done a str) = return $ Done (Right a) str check (Cont _ (Just err)) = return $ Done (Left err) mempty@@ -425,8 +425,7 @@ check n (Done x _) = drop n >> (return $ return x) check n (Cont x Nothing) = take n x check n (Cont _ (Just e)) = drop n >> throwErr e- done s1 s2 = runIter iter s1 >>= checkIfDone return >>= \i' ->- return (Done i' s2)+ done s1 s2 = liftM (flip Done s2) (runIter iter s1 >>= checkIfDone return) -- |Read n elements from a stream and apply the given iteratee to the@@ -450,8 +449,7 @@ step _n str = done str str check _n' (Done a str) = return $ Done (return a) str check n' (Cont k mErr) = return $ Cont (takeR n' k) mErr- done s1 s2 = runIter iter s1 >>= checkIfDone return >>= \i' ->- return (Done i' s2)+ done s1 s2 = liftM (flip Done s2) (runIter iter s1 >>= checkIfDone return) -- |Map the stream: yet another iteratee transformer@@ -463,8 +461,7 @@ mapStream :: (SC.StreamChunk s el, SC.StreamChunk s el', Monad m) => (el -> el') -> EnumeratorN s el s el' m a-mapStream f iter = IterateeG (\str -> runIter iter (strMap (SC.cMap f) str) >>=- check)+mapStream f iter = IterateeG ((check <=< runIter iter) . strMap (SC.cMap f)) where check (Done a _) = return $ Done (return a) (Chunk LL.empty) check (Cont k mErr) = return $ Cont (mapStream f k) mErr@@ -489,8 +486,7 @@ docase (Cont k Nothing) = convStream fi k docase (Cont _ (Just e)) = return $ throwErr e -{-# SPECIALIZE convStream :: IterateeG s el IO (Maybe (s' el')) -> EnumeratorN s el s' el' IO a #-}-+{-# INLINE convStream #-} -- |Creates an enumerator with only elements from the stream that -- satisfy the predicate function.@@ -512,9 +508,10 @@ (a -> el -> a) -> a -> IterateeG s el m a-foldl f i = IterateeG step+foldl f i = iter where- step (Chunk xs) | LL.null xs = return $ Cont (foldl f i) Nothing+ iter = IterateeG step+ step (Chunk xs) | LL.null xs = return $ Cont (iter) Nothing step (Chunk xs) = return $ Cont (foldl f (FLL.foldl f i xs)) Nothing step stream = return $ Done i stream @@ -523,9 +520,10 @@ (a -> el -> a) -> a -> IterateeG s el m a-foldl' f i = IterateeG step+foldl' f i = iter where- step (Chunk xs) | LL.null xs = return $ Cont (foldl' f i) Nothing+ iter = IterateeG step+ step (Chunk xs) | LL.null xs = return $ Cont (iter) Nothing step (Chunk xs) = return $ Cont (foldl' f $! FLL.foldl' f i xs) Nothing step stream = return $ Done i stream @@ -537,6 +535,8 @@ foldl1 f = IterateeG step where step (Chunk xs) | LL.null xs = return $ Cont (foldl1 f) Nothing+ -- After the first chunk, just use regular foldl in order to account for+ -- the accumulator. step (Chunk xs) = return $ Cont (foldl f (FLL.foldl1 f xs)) Nothing step stream = return $ Cont (foldl1 f) (Just (setEOF stream)) @@ -585,7 +585,7 @@ (>.):: (SC.StreamChunk s el, Monad m) => EnumeratorGM s el m a -> EnumeratorGM s el m a -> EnumeratorGM s el m a-(>.) e1 e2 i1 = e1 i1 >>= e2+(>.) e1 e2 = e2 <=< e1 -- |The pure 1-chunk enumerator -- It passes a given list of elements to the iteratee in one chunk
src/Data/Iteratee/Base/StreamChunk.hs view
@@ -77,7 +77,9 @@ -- |Class of streams which can be filled from a 'Ptr'. Typically these -- are streams which can be read from a file.-class StreamChunk s el => ReadableChunk s el where+-- The Int parameter is the length of the data in bytes.+-- N.B. The pointer must not be returned or used after readFromPtr completes.+class (StreamChunk s el, Storable el) => ReadableChunk s el where readFromPtr :: Ptr (el) -> Int -> IO (s el) instance (Storable el) => ReadableChunk [] el where
src/Data/Iteratee/IO/Fd.hs view
@@ -1,4 +1,4 @@-{-# LANGUAGE CPP #-}+{-# LANGUAGE CPP, ScopedTypeVariables #-} -- |Random and Binary IO with generic Iteratees, using File Descriptors for IO. -- when available, these are the preferred functions for performing IO as they@@ -26,6 +26,7 @@ import Foreign.Ptr import Foreign.Marshal.Alloc+import Foreign.Storable import System.IO (SeekMode(..)) @@ -37,10 +38,10 @@ -- |The enumerator of a POSIX File Descriptor. This version enumerates -- over the entire contents of a file, in order, unless stopped by -- the iteratee. In particular, seeking is not supported.-enumFd :: ReadableChunk s el => Fd -> EnumeratorGM s el IO a+enumFd :: forall a s el.(ReadableChunk s el) => Fd -> EnumeratorGM s el IO a enumFd fd iter' = allocaBytes (fromIntegral buffer_size) $ loop iter' where- buffer_size = 4096+ buffer_size = fromIntegral $ 2048 - (mod 2048 $ sizeOf (undefined :: el)) loop iter p = do n <- myfdRead fd (castPtr p) buffer_size case n of@@ -56,13 +57,13 @@ -- |The enumerator of a POSIX File Descriptor: a variation of enumFd that -- supports RandomIO (seek requests)-enumFdRandom :: ReadableChunk s el => Fd -> EnumeratorGM s el IO a+enumFdRandom :: forall a s el.(ReadableChunk s el) => Fd -> EnumeratorGM s el IO a enumFdRandom fd iter = allocaBytes (fromIntegral buffer_size) (loop (0,0) iter) where -- this can be usefully varied. Values between 512 and 4096 seem -- to provide the best performance for most cases.- buffer_size = 4096+ buffer_size = fromIntegral $ 4096 - (mod 4096 $ sizeOf (undefined :: el)) -- the first argument of loop is (off,len), describing which part -- of the file is currently in the buffer 'p' {-
src/Data/Iteratee/IO/Handle.hs view
@@ -1,3 +1,5 @@+{-# LANGUAGE ScopedTypeVariables #-}+ -- |Random and Binary IO with generic Iteratees. These functions use Handles -- for IO operations, and are provided for compatibility. When available, -- the File Descriptor based functions are preferred as these wastefully@@ -23,6 +25,7 @@ import Foreign.Ptr import Foreign.Marshal.Alloc+import Foreign.Storable import System.IO @@ -33,10 +36,10 @@ -- |The enumerator of a file Handle. This version enumerates -- over the entire contents of a file, in order, unless stopped by -- the iteratee. In particular, seeking is not supported.-enumHandle :: ReadableChunk s el => Handle -> EnumeratorGM s el IO a+enumHandle :: forall a s el.(ReadableChunk s el) => Handle -> EnumeratorGM s el IO a enumHandle h i = allocaBytes (fromIntegral buffer_size) $ loop i where- buffer_size = 4096+ buffer_size = 4096 - (mod 4096 $ sizeOf (undefined :: el)) loop iter p = do n <- (try $ hGetBuf h p buffer_size) :: IO (Either SomeException Int) case n of@@ -53,13 +56,13 @@ -- |The enumerator of a Handle: a variation of enumHandle that -- supports RandomIO (seek requests)-enumHandleRandom :: ReadableChunk s el => Handle -> EnumeratorGM s el IO a+enumHandleRandom :: forall a s el.(ReadableChunk s el) => Handle -> EnumeratorGM s el IO a enumHandleRandom h iter = allocaBytes (fromIntegral buffer_size) (loop (0,0) iter) where -- this can be usefully varied. Values between 512 and 4096 seem -- to provide the best performance for most cases.- buffer_size = 4096+ buffer_size = 4096 - (mod 4096 $ sizeOf (undefined :: el)) -- the first argument of loop is (off,len), describing which part -- of the file is currently in the buffer 'p' {-
src/Data/Iteratee/WrappedByteString.hs view
@@ -1,5 +1,4 @@-{-# LANGUAGE MultiParamTypeClasses #-}-{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE MultiParamTypeClasses, FlexibleInstances, BangPatterns #-} module Data.Iteratee.WrappedByteString ( WrappedByteString (..)@@ -14,7 +13,9 @@ import qualified Data.ListLike as LL import Data.Word import Data.Monoid-import Foreign.ForeignPtr+import Foreign.Ptr+import Foreign.Marshal.Array+import Control.Monad -- |Wrap a Data.ByteString ByteString newtype WrappedByteString a = WrapBS { unWrap :: BBase.ByteString }@@ -27,15 +28,15 @@ foldl f z = BW.foldl f z . unWrap foldr f z = BW.foldr f z . unWrap +-- Thanks to Echo Nolan for indicating that the bytestring must copy+-- data to a new ptr to preserve referential transparency. instance SC.ReadableChunk WrappedByteString Word8 where- readFromPtr p l = do- fptr <- newForeignPtr_ p- return . WrapBS $ BBase.fromForeignPtr fptr 0 l+ readFromPtr buf l = liftM WrapBS $! BBase.create l $ \newp ->+ copyArray newp buf l -- must copy from the buffer instance SC.ReadableChunk WrappedByteString Char where- readFromPtr p l = do- fptr <- newForeignPtr_ p- return . WrapBS $ BBase.fromForeignPtr (castForeignPtr fptr) 0 l+ readFromPtr buf l = liftM WrapBS $! BBase.create l $ \newp ->+ copyArray newp (castPtr buf) l --must copy data from buffer instance LL.ListLike (WrappedByteString Word8) Word8 where length = BW.length . unWrap
tests/testIteratee.hs view
@@ -1,6 +1,8 @@ {-# OPTIONS_GHC -O #-} {-# LANGUAGE NoMonomorphismRestriction #-} +import Prelude as P+ import QCUtils import Test.Framework (defaultMain, testGroup)@@ -94,13 +96,13 @@ prop_break2 f xs = runner1 (enumPure1Chunk xs (Iter.break f >> stream2list)) == snd (break f xs) where types = xs :: [Int] -prop_head xs = length xs > 0 ==> runner1 (enumPure1Chunk xs Iter.head) == head xs+prop_head xs = P.length xs > 0 ==> runner1 (enumPure1Chunk xs Iter.head) == head xs where types = xs :: [Int] -prop_head2 xs = length xs > 0 ==> runner1 (enumPure1Chunk xs (Iter.head >> stream2list)) == tail xs+prop_head2 xs = P.length xs > 0 ==> runner1 (enumPure1Chunk xs (Iter.head >> stream2list)) == tail xs where types = xs :: [Int] -prop_heads xs = runner1 (enumPure1Chunk xs $ heads xs) == length xs+prop_heads xs = runner1 (enumPure1Chunk xs $ heads xs) == P.length xs where types = xs :: [Int] prop_heads2 xs = runner1 (enumPure1Chunk xs $ heads [] >>= \c ->@@ -154,7 +156,7 @@ == runner1 (enumPure1Chunk xs i) where types = (xs :: [Int], i :: I) -prop_nullH xs = length xs > 0 ==>+prop_nullH xs = P.length xs > 0 ==> runner1 (enumPure1Chunk xs =<< enumPure1Chunk [] Iter.head) == runner1 (enumPure1Chunk xs Iter.head) where types = (xs :: [Int])@@ -190,29 +192,29 @@ prop_convId xs = runner1 (enumPure1Chunk xs convId) == Just xs where types = xs :: [Int] -prop_convstream xs i = length xs > 0 ==>+prop_convstream xs i = P.length xs > 0 ==> runner2 (enumPure1Chunk xs $ convStream convId i) == runner1 (enumPure1Chunk xs i) where types = (xs :: [Int], i :: I) -prop_convstream2 xs = length xs > 0 ==>+prop_convstream2 xs = P.length xs > 0 ==> runner2 (enumPure1Chunk xs $ convStream convId Iter.head) == runner1 (enumPure1Chunk xs Iter.head) where types = (xs :: [Int]) -prop_convstream3 xs = length xs > 0 ==>+prop_convstream3 xs = P.length xs > 0 ==> runner2 (enumPure1Chunk xs $ convStream convId stream2list) == runner1 (enumPure1Chunk xs stream2list) where types = (xs :: [Int]) prop_take xs n = n >= 0 ==> runner2 (enumPure1Chunk xs $ Iter.take n stream2list)- == runner1 (enumPure1Chunk (Prelude.take n xs) stream2list)+ == runner1 (enumPure1Chunk (P.take n xs) stream2list) where types = (xs :: [Int]) prop_take2 xs n = n > 0 ==> runner2 (enumPure1Chunk xs $ Iter.take n peek)- == runner1 (enumPure1Chunk (Prelude.take n xs) peek)+ == runner1 (enumPure1Chunk (P.take n xs) peek) where types = (xs :: [Int]) prop_takeR xs n = n >= 0 ==>@@ -226,7 +228,7 @@ {- -- this isn't true, since lines "\r" returns ["\r"], and IC.line should -- return Right "". Not sure what a real test would be...-prop_line xs = length xs > 0 ==>+prop_line xs = P.length xs > 0 ==> fromEither (runner1 (enumPure1Chunk xs $ IC.line)) == head (lines xs) where